fork download
  1. # include <type_traits>
  2. # include <cmath>
  3. # include <cassert>
  4. # include <iterator>
  5. # include <sstream>
  6. # include <algorithm>
  7. #include <iostream>
  8.  
  9. namespace digits
  10. {
  11. // Default base type traits, infer base size from the number of character
  12. template <char... Chars>
  13. struct base_char_traits
  14. {
  15. // Mandatory for the digits container, maybe someone want to make
  16. // another traits with wchar ?
  17. typedef char value_type;
  18.  
  19. // Size of the base, computed from the number of characters passed
  20. static constexpr size_t size = sizeof...(Chars);
  21.  
  22. // Array of characters use to print the output
  23. static constexpr value_type characters[sizeof...(Chars)] = { Chars... };
  24. };
  25.  
  26. // **sigh**
  27. // Instantiation of the array of character; otherwise there will be a link
  28. // error
  29. template <char... Chars>
  30. constexpr typename base_char_traits<Chars...>::value_type base_char_traits<Chars...>::characters[sizeof...(Chars)];
  31.  
  32. // All your bases are belong to us !
  33. struct base2_traits : public base_char_traits<'0', '1'> { };
  34. struct base8_traits : public base_char_traits<'0', '1', '2', '3', '4', '5', '6', '7'> { };
  35. struct base10_traits : public base_char_traits<'0', '1', '2', '3', '4', '5', '6', '7', '8', '9'> { };
  36. struct base12_traits : public base_char_traits<'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b'> { };
  37. struct base16_traits : public base_char_traits<'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'> { };
  38.  
  39.  
  40. // The digit container with the base traits and the type as template
  41. // parameter.
  42. //
  43. // It is a read only container that allows you to iterate on the digit in
  44. // the base given as template parameter.
  45. template <typename BaseTraits, typename T = unsigned long>
  46. class digits
  47. {
  48. public:
  49.  
  50. // Assert that T fullfil our criteria
  51. static_assert(std::is_integral<T>(), "T must be integral");
  52. static_assert(std::is_unsigned<T>(), "T must be unsigned");
  53.  
  54. // Value type is defined by the base traits to allow the use of more
  55. // complicated digit type (here we only handle char)
  56. typedef typename BaseTraits::value_type value_type;
  57.  
  58. // Reference type is defined to be the same as value type because this is an immutable container
  59. typedef typename BaseTraits::value_type reference;
  60.  
  61. // The size type of the container, i.e. the type that will be used to
  62. // express a digit position
  63. typedef size_t size_type;
  64.  
  65. // Iterator class allowing one to walk through the number's digit from
  66. // the lowest to the highest
  67. class iterator
  68. {
  69. public:
  70.  
  71. // Type used to return iterator substraction result
  72. typedef size_t difference_type;
  73.  
  74. // type used by algorithms (e.g. find)
  75. typedef typename digits::reference reference;
  76.  
  77. // type used by algorithms (e.g. find)
  78. typedef typename digits::reference pointer;
  79.  
  80. // type returned by operator*
  81. typedef typename digits::value_type value_type;
  82.  
  83. // Iterator category, here we can randomly walk in the digit
  84. typedef std::random_access_iterator_tag iterator_category;
  85.  
  86. // Mandatory default constructor, initialize to an invalid iterator
  87. iterator()
  88. {
  89. _current_digit = 0;
  90. _digits = nullptr;
  91. }
  92.  
  93. // Build an iterator other a digits container starting at digit
  94. iterator(const digits* digits, size_type digit)
  95. {
  96. _current_digit = digit;
  97. _digits = digits;
  98. }
  99.  
  100. iterator(const iterator& it) :
  101. iterator(it._digits, it._current_digit)
  102. {
  103.  
  104. }
  105.  
  106. // Move using swap idiom
  107. iterator(iterator&& it) :
  108. iterator()
  109. {
  110. swap(*this, it);
  111. }
  112.  
  113. ~iterator()
  114. {
  115. _digits = nullptr;
  116. }
  117.  
  118. // assignment iterator using swap idiom
  119. iterator& operator=(iterator it)
  120. {
  121. swap(*this, it);
  122. return *this;
  123. }
  124.  
  125. // Comparison operators
  126. bool operator==(const iterator& it) const
  127. {
  128. assert(_digits == it._digits);
  129. return (_current_digit == it._current_digit);
  130. }
  131.  
  132. bool operator!=(const iterator& it) const
  133. {
  134. return !(operator==(it));
  135. }
  136.  
  137. bool operator<(const iterator& it) const
  138. {
  139. assert(_digits == it._digits);
  140. return (_current_digit < it._current_digit);
  141. }
  142.  
  143. bool operator>(const iterator& it) const
  144. {
  145. assert(_digits == it._digits);
  146. return (_current_digit > it._current_digit);
  147. }
  148.  
  149. bool operator<=(const iterator& it) const
  150. {
  151. assert(_digits == it._digits);
  152. return (_current_digit <= it._current_digit);
  153. }
  154.  
  155. bool operator>=(const iterator& it) const
  156. {
  157. assert(_digits == it._digits);
  158. return (_current_digit >= it._current_digit);
  159. }
  160.  
  161. // Moving the iterator
  162. iterator& operator++()
  163. {
  164. ++_current_digit;
  165. return *this;
  166. }
  167.  
  168. iterator operator++(int)
  169. {
  170. iterator it(*this);
  171. operator++();
  172. return it;
  173. }
  174.  
  175. iterator& operator--()
  176. {
  177. --_current_digit;
  178. return *this;
  179. }
  180.  
  181. iterator operator--(int)
  182. {
  183. iterator it(*this);
  184. operator--();
  185. return it;
  186. }
  187.  
  188. iterator& operator+=(size_type increment)
  189. {
  190. _current_digit += increment;
  191. return *this;
  192. }
  193.  
  194. iterator operator+(size_type increment) const
  195. {
  196. iterator it(*this);
  197. return (it += increment);
  198. }
  199.  
  200. friend iterator operator+(size_type increment, const iterator& it)
  201. {
  202. return (it + increment);
  203. }
  204.  
  205. iterator& operator-=(size_type decrement)
  206. {
  207. _current_digit -= decrement;
  208. return *this;
  209. }
  210.  
  211. iterator operator-(size_type decrement) const
  212. {
  213. iterator it(*this);
  214. return (it - decrement);
  215. }
  216.  
  217. difference_type operator-(const iterator& it) const
  218. {
  219. assert(_digits == it._digits);
  220. return (_current_digit - it._current_digit);
  221. }
  222.  
  223. value_type operator*() const
  224. {
  225. assert(nullptr != _digits);
  226.  
  227. return _digits->digit(_current_digit);
  228. }
  229.  
  230. friend void swap(iterator& first, iterator& second)
  231. {
  232. std::swap(first._digits, second._digits);
  233. std::swap(first._current_digit, second._current_digit);
  234. }
  235.  
  236. private:
  237.  
  238. // The current digit we will be printing when calling operator*().
  239. // From 0 to (digits.size() - 1)
  240. size_t _current_digit;
  241.  
  242. // The digit container we're working on.
  243. const digits* _digits;
  244. };
  245.  
  246. // Define the reverse iterator, that will allow to iterator from the
  247. // highest digit to the lowest (more printing friendly)
  248. typedef std::reverse_iterator<iterator> reverse_iterator;
  249.  
  250. // Default constructor use 0 as a number
  251. digits()
  252. {
  253. _number = 0;
  254. }
  255.  
  256. // Build a container over a number given as parameter
  257. digits(T number)
  258. {
  259. _number = number;
  260. }
  261.  
  262. digits(const digits& copy) :
  263. digits(copy._number)
  264. {
  265. }
  266.  
  267. // Move constructor using swap idiom
  268. digits(digits&& move) :
  269. digits()
  270. {
  271. swap(*this, move);
  272. }
  273.  
  274. ~digits()
  275. {
  276. }
  277.  
  278. // Retrieve the digit character
  279. value_type digit(size_t digit) const
  280. {
  281. assert(digit < size());
  282. constexpr size_t base = BaseTraits::size;
  283.  
  284. // @warning
  285. // llround is mandatory because of a double to unsigned long problem
  286. T modul = static_cast<T>(llround(std::pow(base, digit + 1)));
  287. T div = static_cast<T>(llround(std::pow(base, digit)));
  288. T digit_index = (_number % modul) / div;
  289.  
  290. return BaseTraits::characters[digit_index];
  291. }
  292.  
  293. // Assignment using swap idiom
  294. digits& operator=(digits assign)
  295. {
  296. swap(_number, assign._number);
  297. }
  298.  
  299. // Comparison operator
  300. bool operator==(const digits& comp) const
  301. {
  302. return (_number == comp._number);
  303. }
  304.  
  305. bool operator!=(const digits& comp) const
  306. {
  307. return !(operator==(comp));
  308. }
  309.  
  310. // Iterators creation
  311. iterator begin() const
  312. {
  313. return iterator(this, static_cast<size_type>(0));
  314. }
  315.  
  316. iterator cbegin() const
  317. {
  318. return begin();
  319. }
  320.  
  321. iterator end() const
  322. {
  323. return iterator(this, size());
  324. }
  325.  
  326. iterator cend() const
  327. {
  328. return end();
  329. }
  330.  
  331. reverse_iterator rbegin() const
  332. {
  333. return reverse_iterator(end());
  334. }
  335.  
  336. reverse_iterator crbegin() const
  337. {
  338. return reverse_iterator(cend());
  339. }
  340.  
  341. reverse_iterator rend() const
  342. {
  343. return reverse_iterator(begin());
  344. }
  345.  
  346. reverse_iterator crend() const
  347. {
  348. return reverse_iterator(cbegin());
  349. }
  350.  
  351. // swap function
  352. friend void swap(digits& first, digits& second)
  353. {
  354. std::swap(first._number, second._number);
  355. }
  356.  
  357. // cast to string
  358. operator std::string () const
  359. {
  360. std::ostringstream stream;
  361.  
  362. // print from high to low
  363. std::copy(rbegin(), rend(),
  364. std::ostream_iterator<value_type>(stream, ""));
  365. return stream.str();
  366. }
  367.  
  368. // The number of digits of this _number
  369. size_type size() const
  370. {
  371. const double log_number = std::log(_number);
  372. constexpr double log_base = std::log(BaseTraits::size);
  373. return std::ceil(log_number / log_base);
  374. }
  375.  
  376. // The maximum nulber of digits this type can have
  377. size_type max_size() const
  378. {
  379. constexpr double max_number = std::pow(2, sizeof(T) * 8);
  380. constexpr double log_max_number = std::log(max_number);
  381. constexpr double log_base = std::log(BaseTraits::size);
  382. return log_max_number / log_base;
  383. }
  384.  
  385. private:
  386.  
  387. // The number we will iterate over the digits
  388. T _number;
  389. };
  390. }
  391.  
  392. template <typename Iterator>
  393. void find_and_print(Iterator begin, Iterator end, char value)
  394. {
  395. auto it = std::find(begin, end, value);
  396. if (end == it)
  397. {
  398. std::cout << "Digit " << value << " not found" << std::endl;
  399. }
  400. else
  401. {
  402. std::cout << *it << " digit found at place "
  403. << std::distance(begin, it)
  404. << std::endl;
  405. auto it2 = it;
  406.  
  407. if (it2 == it)
  408. {
  409. std::cout << *it2 << " == " << *it << std::endl;
  410. }
  411.  
  412. }
  413. }
  414.  
  415. int main(int argc, char const *argv[])
  416. {
  417. digits::digits<digits::base16_traits> dig(123456);
  418. digits::digits<digits::base2_traits> dig3(123456);
  419. digits::digits<digits::base10_traits> dig4(123456);
  420. auto dig2 = dig;
  421.  
  422. for (auto digit: dig)
  423. {
  424. std::cout << "Digit: " << digit << std::endl;
  425. }
  426.  
  427. std::copy(dig2.rbegin(), dig2.rend(), std::ostream_iterator<char>(std::cout, " "));
  428. std::cout << std::endl;
  429. std::copy(dig3.begin(), dig3.end(), std::ostream_iterator<char>(std::cout, " "));
  430. std::cout << std::endl;
  431.  
  432. find_and_print(dig.begin(), dig.end(), 'e');
  433. find_and_print(dig2.begin(), dig2.end(), '0');
  434. find_and_print(dig3.rbegin(), dig3.rend(), '0');
  435.  
  436. std::cout << "Dig: " << static_cast<std::string>(dig) << std::endl;
  437. std::cout << "Dig3: " << static_cast<std::string>(dig3) << std::endl;
  438. std::cout << "Dig4: " << static_cast<std::string>(dig4) << std::endl;
  439. return 0;
  440. }
Success #stdin #stdout 0s 3492KB
stdin
Standard input is empty
stdout
Digit: 0
Digit: 4
Digit: 2
Digit: e
Digit: 1
1 e 2 4 0 
0 0 0 0 0 0 1 0 0 1 0 0 0 1 1 1 1 
e digit found at place 3
e ==  e
0 digit found at place 0
0 ==  0
0 digit found at place 4
0 ==  0
Dig: 1e240
Dig3: 11110001001000000
Dig4: 123456