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