fork(1) download
  1. #include <memory>
  2. #include <cstddef>
  3.  
  4. template<typename Value,
  5. typename Alloc = std::allocator<Value>>
  6. struct ListAlloc
  7. {
  8. using value_type = Value;
  9.  
  10. // ///////////////////////////////////////////////////////////////////////////////////////////
  11.  
  12. struct NodeBase
  13. {
  14. NodeBase *prev,
  15. *next;
  16.  
  17. NodeBase( NodeBase* prev, NodeBase* next ) noexcept :
  18. prev{prev},
  19. next{next} {}
  20.  
  21. NodeBase() noexcept :
  22. NodeBase{nullptr, nullptr} {}
  23. } mutable mStart, mEnd;
  24.  
  25. struct Node : NodeBase
  26. {
  27. value_type data;
  28.  
  29. template<typename... Args>
  30. Node( NodeBase* prev, NodeBase* next, Args&&... args ) noexcept :
  31. NodeBase{prev, next},
  32. data{std::forward<Args>(args)...} {}
  33.  
  34. Node() noexcept = default;
  35. };
  36.  
  37. using allocator_type = typename Alloc::template rebind<Node>::other;
  38. using allocator_traits = std::allocator_traits<allocator_type>;
  39.  
  40. /// ////////////////////////////
  41.  
  42. #define takeover( N ) using N = typename allocator_traits::N;
  43.  
  44. typedef value_type& reference;
  45. typedef value_type const& const_reference;
  46.  
  47. takeover(pointer)
  48. takeover(const_pointer)
  49.  
  50. takeover(difference_type)
  51. takeover(size_type)
  52.  
  53. #undef takeover
  54.  
  55. /// /////////////////////////////
  56.  
  57. allocator_type mAllocator;
  58.  
  59. ListAlloc( NodeBase const& start, NodeBase const& end, allocator_type const& alloc = allocator_type{} ):
  60. mStart{start}, mEnd{end},
  61. mAllocator{alloc} {}
  62.  
  63. template<typename... Args>
  64. Node* _alloc_make_node( NodeBase* prev, NodeBase* next, Args&&... args )
  65. {
  66. Node* node = allocator_traits::allocate( mAllocator, 1 );
  67.  
  68. try
  69. {
  70. allocator_traits::construct( mAllocator, node, prev, next, std::forward<Args>(args)... );
  71. }
  72. catch(...)
  73. {
  74. allocator_traits::deallocate( mAllocator, node, 1 );
  75. throw;
  76. }
  77.  
  78. return node;
  79. }
  80.  
  81. template<typename... Args>
  82. Node* _alloc_make_node_notify( NodeBase* prev, NodeBase* next, Args&&... args )
  83. {
  84. Node* node = _alloc_make_node( prev, next, std::forward<Args>(args)... );
  85.  
  86. if( prev )
  87. prev->next = node;
  88. if( next )
  89. next->prev = node;
  90.  
  91. return node;
  92. }
  93.  
  94. void _alloc_destroy_node( Node* ptr )
  95. {
  96. allocator_traits::destroy( mAllocator, ptr );
  97. allocator_traits::deallocate( mAllocator, ptr, 1 );
  98. }
  99.  
  100. void _alloc_destroy_all_prev( NodeBase* end, NodeBase* ptr )
  101. {
  102. NodeBase* old_ptr;
  103. while( ptr != end )
  104. {
  105. old_ptr = ptr;
  106. ptr = ptr->prev;
  107. _alloc_destroy_node( static_cast<Node*>(old_ptr) );
  108. }
  109. }
  110.  
  111. private:
  112.  
  113. template<typename... Func>
  114. std::pair<Node*, Node*> _alloc_create_impl( size_type n, Func... func )
  115. {
  116. if( n == 0 )
  117. return { nullptr, nullptr };
  118.  
  119. Node* ptr = _alloc_make_node_notify( ptr, nullptr, func()... );
  120. Node* const rval = ptr;
  121.  
  122. while( --n ) try
  123. {
  124. ptr = _alloc_make_node_notify( ptr, nullptr, func()... );
  125. }
  126. catch(...)
  127. {
  128. ptr = ptr->prev;
  129. _alloc_destroy_all_prev( ptr );
  130. throw;
  131. }
  132.  
  133.  
  134. return {rval, ptr};
  135. }
  136.  
  137. public:
  138. std::pair<Node*, Node*> _alloc_fill_n( size_type n )
  139. {
  140. return _alloc_create_impl( n );
  141. }
  142.  
  143. std::pair<Node*, Node*> _alloc_fill_n( size_type n, const_reference value )
  144. {
  145. return _alloc_create_impl( n, [&]() -> const_reference { return value; } );
  146. }
  147.  
  148. template<typename InputIterator>
  149. std::pair<Node*, Node*> _alloc_copy( size_type n, InputIterator first )
  150. {
  151. return _alloc_create_impl( n, [&]() -> const_reference { return *first++; } );
  152. }
  153.  
  154. // ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  155.  
  156. void _alloc_swap( allocator_type& lhs, allocator_type& rhs, std::true_type )
  157. { std::swap(lhs, rhs); }
  158. void _alloc_swap( allocator_type&, allocator_type&, std::false_type )
  159. {}
  160.  
  161. allocator_type get_allocator() const { return mAllocator; }
  162.  
  163. size_type max_size() const { return allocator_traits::max_size(mAllocator); }
  164. };
  165.  
  166. #include <type_traits>
  167.  
  168. /// Geborgt von camper - verzeih'
  169. #define TAG_CHECK(It, ItTag) \
  170.   ,typename std::enable_if<std::is_convertible< \
  171.   typename std::conditional<std::is_class<It>::value || std::is_pointer<It>::value, std::iterator_traits<It>, std::false_type>::type::iterator_category, \
  172.   ItTag>::value, int>::type = 0
  173.  
  174. #include <iterator>
  175.  
  176. template<typename Value,
  177. typename Alloc = std::allocator<Value>>
  178. class List : ListAlloc<Value, Alloc>
  179. {
  180. #define takeover(N) using ListAlloc<Value,Alloc>::N;
  181.  
  182. takeover(_alloc_copy)
  183. takeover(_alloc_make_node_notify)
  184. takeover(_alloc_make_node)
  185. takeover(_alloc_fill_n)
  186. takeover(_alloc_swap)
  187. takeover(_alloc_destroy_all_prev)
  188. takeover(_alloc_destroy_node)
  189.  
  190. takeover(mAllocator)
  191. takeover(mStart)
  192. takeover(mEnd)
  193.  
  194. typedef typename List::allocator_traits allocator_traits;
  195.  
  196. public:
  197.  
  198. takeover( get_allocator )
  199. takeover( max_size )
  200.  
  201. #undef takeover
  202. #define takeover(N) using typename ListAlloc<Value,Alloc>::N;
  203. takeover(NodeBase)
  204.  
  205. private:
  206. takeover(Node)
  207.  
  208. public:
  209. takeover(value_type)
  210. takeover(reference)
  211. takeover(const_reference)
  212. takeover(pointer)
  213. takeover(const_pointer)
  214. takeover(difference_type)
  215. takeover(size_type)
  216. takeover(allocator_type)
  217.  
  218.  
  219. #define DEFINE_OP( class, mem, ch ) \
  220.   class& operator ch() noexcept \
  221.   { \
  222.   p = p->mem; \
  223.   return *this; \
  224.   }
  225.  
  226. #define DEFINE_POST_OP( class, ch ) \
  227.   class operator ch(int) noexcept \
  228.   { \
  229.   auto rval = *this; \
  230.   ch*this; \
  231.   return rval; \
  232.   }
  233.  
  234. struct iterator : std::iterator<std::bidirectional_iterator_tag,
  235. value_type,
  236. difference_type,
  237. pointer,
  238. reference>
  239. {
  240. private:
  241.  
  242. friend class List;
  243. friend class const_iterator;
  244.  
  245. NodeBase* p;
  246.  
  247. iterator( NodeBase* p ) noexcept :
  248. p{p} {}
  249.  
  250. public:
  251.  
  252. iterator() noexcept :
  253. iterator{nullptr} {}
  254.  
  255. reference operator*() noexcept { return static_cast<Node*>(p)->data; }
  256. pointer operator->() noexcept { return &static_cast<Node*>(p)->data; }
  257.  
  258. DEFINE_OP( iterator, next, ++ )
  259. DEFINE_OP( iterator, prev, -- )
  260. DEFINE_POST_OP( iterator, ++ )
  261. DEFINE_POST_OP( iterator, -- )
  262.  
  263. friend bool operator==( iterator lhs, iterator rhs ) noexcept { return lhs.p == rhs.p; }
  264. friend bool operator!=( iterator lhs, iterator rhs ) noexcept { return !(lhs == rhs); }
  265. };
  266.  
  267. struct const_iterator : std::iterator<std::bidirectional_iterator_tag,
  268. value_type const,
  269. difference_type,
  270. const_pointer,
  271. const_reference>
  272. {
  273. private:
  274.  
  275. friend class List;
  276.  
  277. mutable NodeBase* p;
  278.  
  279. const_iterator( NodeBase* p ) noexcept :
  280. p{p} {}
  281.  
  282. public:
  283.  
  284. const_iterator() noexcept :
  285. const_iterator{nullptr} {}
  286.  
  287. const_iterator( iterator it ) noexcept :
  288. p{it.p} {}
  289.  
  290. const_reference operator*() noexcept { return static_cast<Node*>(p)->data; }
  291. const_pointer operator->() noexcept { return &static_cast<Node*>(p)->data; }
  292.  
  293. DEFINE_OP( const_iterator, next, ++ )
  294. DEFINE_OP( const_iterator, prev, -- )
  295. DEFINE_POST_OP( const_iterator, ++ )
  296. DEFINE_POST_OP( const_iterator, -- )
  297.  
  298. friend bool operator==( const_iterator lhs, const_iterator rhs ) noexcept { return lhs.p == rhs.p; }
  299. friend bool operator!=( const_iterator lhs, const_iterator rhs ) noexcept { return !(lhs == rhs); }
  300. };
  301.  
  302. #undef DEFINE_POST_OP
  303. #undef DEFINE_OP
  304.  
  305. typedef std::reverse_iterator<iterator> reverse_iterator;
  306. typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
  307.  
  308. private:
  309.  
  310. size_type mSize;
  311.  
  312. /// ///////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  313.  
  314. void _assign_to( std::pair<Node*, Node*> pair )
  315. {
  316. mStart.next = pair.first;
  317. mEnd.prev = pair.second;
  318. }
  319.  
  320. template<typename scenario_bool>
  321. void _swap( List& other )
  322. {
  323. std::swap( mStart, other.mStart );
  324. std::swap( mEnd, other.mEnd );
  325. std::swap( mSize, other.mSize );
  326. _alloc_swap( mAllocator, other.mAllocator, scenario_bool{} );
  327. }
  328.  
  329. public:
  330.  
  331. void swap( List& other )
  332. {
  333. _swap<typename allocator_traits::propagate_on_container_swap>(other);
  334. }
  335.  
  336. explicit List( allocator_type const& alloc = allocator_type{} ):
  337. ListAlloc<Value, Alloc>{NodeBase{ nullptr, &mEnd }, // Start-NodeBase
  338. NodeBase{ &mStart, nullptr }, // End-NodeBase
  339. alloc},
  340. mSize{0} {}
  341.  
  342. explicit List( size_type count,
  343. const_reference value,
  344. allocator_type const& alloc = allocator_type{} ):
  345. ListAlloc<Value, Alloc>{alloc},
  346. mSize{count}
  347. {
  348. _assign_to( _alloc_fill_n(count, mAllocator.address(value)) );
  349. }
  350.  
  351. explicit List( size_type count,
  352. allocator_type const& alloc = allocator_type{} ):
  353. ListAlloc<Value, Alloc>{alloc},
  354. mSize{count}
  355. {
  356. _assign_to( _alloc_fill_n(count) );
  357. }
  358.  
  359. template<typename InputIterator
  360. TAG_CHECK(InputIterator, std::input_iterator_tag)>
  361. explicit List( InputIterator first,
  362. InputIterator last,
  363. allocator_type const& alloc = allocator_type{} ):
  364. List{alloc}
  365. {
  366. assign(first, last);
  367. }
  368.  
  369. List( std::initializer_list<value_type> ilist,
  370. allocator_type const& alloc = allocator_type{} ):
  371. List(std::begin(ilist), std::end(ilist), alloc) {}
  372.  
  373. List( List const& l ):
  374. ListAlloc<Value, Alloc>{ allocator_traits::select_on_container_copy_construction(l.mAllocator) },
  375. mSize{l.mSize}
  376. { _assign_to( _alloc_copy( mSize, l.cbegin() ) ); }
  377.  
  378. List( List const& l, allocator_type const& alloc ):
  379. ListAlloc<Value, Alloc>{alloc},
  380. mSize{l.mSize}
  381. { _assign_to( _alloc_copy( mSize, l.cbegin() ) ); }
  382.  
  383. List& operator=( List const& l )
  384. {
  385. clear();
  386.  
  387. if( allocator_traits::propagate_on_container_copy_assignment::value )
  388. mAllocator = l.mAllocator;
  389.  
  390. _assign_to( _alloc_copy( l.mSize, l.cbegin() ) );
  391. mSize = l.mSize;
  392.  
  393. return *this;
  394. }
  395.  
  396. List( List&& l ):
  397. List{}
  398. { _swap<std::false_type>(l); }
  399.  
  400. List( List&& l, allocator_type const& alloc ):
  401. List{alloc}
  402. { _swap<std::false_type>(l); }
  403.  
  404. List& operator=( List&& l )
  405. {
  406. clear();
  407. _swap<allocator_traits::propagate_on_container_move_assignment>(l);
  408. }
  409.  
  410. ~List() // noexcept (ist schon default)
  411. {
  412. clear();
  413. }
  414.  
  415. void assign( size_type count, const_reference value )
  416. {
  417. clear();
  418. mSize = count;
  419. _assign_to( _alloc_fill_n(count, mAllocator.address(value)) );
  420. }
  421.  
  422. template<typename InputIterator>
  423. void assign( InputIterator first, InputIterator last )
  424. {
  425. clear();
  426. insert( cbegin(), first, last );
  427. }
  428.  
  429. void assign( std::initializer_list<value_type> ilist )
  430. {
  431. assign(std::begin(ilist), std::end(ilist));
  432. }
  433.  
  434. size_type size() const { return mSize; }
  435.  
  436. bool empty() const { return size() == 0; }
  437.  
  438. void clear()
  439. {
  440. _alloc_destroy_all_prev( &mStart, mEnd.prev );
  441. mSize = 0;
  442. }
  443.  
  444. iterator begin() noexcept { return mStart.next ; }
  445. iterator end() noexcept { return &mEnd ; }
  446. const_iterator begin() const noexcept { return mStart.next ; }
  447. const_iterator end() const noexcept { return &mEnd ; }
  448. const_iterator cbegin() const noexcept { return begin(); }
  449. const_iterator cend() const noexcept { return end() ; }
  450.  
  451. reverse_iterator rbegin() { return reverse_iterator{begin()}; }
  452. reverse_iterator rend() { return reverse_iterator{end() }; }
  453. const_reverse_iterator rbegin() const { return const_reverse_iterator{cbegin()}; }
  454. const_reverse_iterator rend() const { return const_reverse_iterator{cend() }; }
  455. const_reverse_iterator crbegin() const { return rbegin(); }
  456. const_reverse_iterator crend() const { return rend() ; }
  457.  
  458. reference front() noexcept { return *begin(); }
  459. reference back() noexcept { return *--iterator{end()}; }
  460. const_reference front() const noexcept { return *cbegin(); }
  461. const_reference back() const noexcept { return *--const_iterator{cend()}; }
  462.  
  463. template<typename... ValueT>
  464. iterator emplace( const_iterator it, ValueT&&... v )
  465. {
  466. auto node = _alloc_make_node_notify( it.p->prev, it.p, std::forward<ValueT>(v)... );
  467.  
  468. ++mSize;
  469.  
  470. return node;
  471. }
  472.  
  473. iterator insert( const_iterator it, const_reference value )
  474. { return emplace(it, value); }
  475. iterator insert( const_iterator it, value_type&& value )
  476. { return emplace(it, value); }
  477.  
  478. iterator insert( const_iterator it, size_type count, const_reference value )
  479. {
  480. if( count == 0 )
  481. return it;
  482.  
  483. auto rval = insert( it, value );
  484.  
  485. while( --count )
  486. insert( it, value );
  487.  
  488. return rval;
  489. }
  490.  
  491. template<typename InputIterator
  492. TAG_CHECK(InputIterator, std::input_iterator_tag)>
  493. iterator insert( const_iterator it, InputIterator first, InputIterator last )
  494. {
  495. if( first == last )
  496. return it;
  497.  
  498. auto rval = insert( it, *first );
  499.  
  500. while( ++first != last )
  501. insert( it, *first );
  502.  
  503. return rval;
  504. }
  505.  
  506. iterator insert( const_iterator it, std::initializer_list<value_type> ilist )
  507. {
  508. insert( it, std::begin(ilist), std::end(ilist) );
  509. }
  510.  
  511. template<typename... Args>
  512. iterator emplace_back( Args&&... args )
  513. {
  514. return emplace( cend(), std::forward<Args>(args)... );
  515. }
  516.  
  517. template<typename... Args>
  518. iterator emplace_front( Args&&... args )
  519. {
  520. return emplace( cbegin(), std::forward<Args>(args)... );
  521. }
  522.  
  523. void push_back( const_reference v )
  524. { insert( cend(), v ); }
  525. void push_back( value_type&& v )
  526. { insert( cend(), v ); }
  527.  
  528. void push_front( const_reference v )
  529. { insert( cbegin(), v ); }
  530. void push_front( value_type&& v )
  531. { insert( cbegin(), v ); }
  532.  
  533. iterator erase( const_iterator it )
  534. {
  535. auto rval = it.p->next;
  536.  
  537. it.p->prev->next = it.p->next;
  538. it.p->next->prev = it.p->prev;
  539.  
  540. _alloc_destroy_node( static_cast<Node*>(it.p) );
  541.  
  542. --mSize;
  543.  
  544. return rval;
  545. }
  546.  
  547. iterator erase( const_iterator first, const_iterator last )
  548. {
  549. while( first != last )
  550. erase( first++ );
  551.  
  552. return last;
  553. }
  554.  
  555. void pop_back()
  556. { erase( --end() ); }
  557. void pop_front()
  558. { erase( begin() ); }
  559.  
  560. private:
  561.  
  562. template<typename ... Args>
  563. void _resize_impl( size_type new_size, Args&&... args )
  564. {
  565. if( new_size > size() )
  566. for( size_type n = size(); n != new_size; ++n )
  567. emplace_back( std::forward<Args>(args)... );
  568.  
  569. else if( new_size < size() )
  570. erase( std::next(cbegin(), new_size), cend() );
  571. }
  572.  
  573. public:
  574. void resize( size_type new_size, const_reference value )
  575. { _resize_impl( new_size, value ); }
  576. void resize( size_type new_size )
  577. { _resize_impl( new_size ); }
  578. };
  579.  
  580. #include <iostream>
  581. #include <iterator>
  582. #include <cassert>
  583. #include <string>
  584.  
  585. int main()
  586. {
  587. #define check(s) assert(std::string(l.begin(), l.end()) == s)
  588.  
  589. List<char> l;
  590. l.push_back('m'); check("m");
  591. l.push_back('z'); check("mz");
  592. l.push_front('a'); check("amz");
  593. l.erase(l.begin());check("mz");
  594. l.insert(l.begin(), 'a');check("amz");
  595. l.insert(l.end(), '!'); check("amz!");
  596. l.pop_front(); check("mz!");
  597. l.pop_back(); check("mz");
  598. List<char>::iterator i=l.begin(); i++;
  599. i = l.insert(i, '-'); check("m-z");
  600. i = l.erase(i); check("mz");
  601. l.erase(i); check("m");
  602. l.push_front('a'); check("am");
  603. l.push_back('z'); check("amz");
  604. i=l.end(); i--; i--;
  605. i=l.erase(i); check("az");
  606. }
  607.  
Success #stdin #stdout 0s 3028KB
stdin
Standard input is empty
stdout
Standard output is empty