Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
forward_list.h
00001 ///\file 00002 00003 /****************************************************************************** 00004 The MIT License(MIT) 00005 00006 Embedded Template Library. 00007 https://github.com/ETLCPP/etl 00008 http://www.etlcpp.com 00009 00010 Copyright(c) 2014 jwellbelove 00011 00012 Permission is hereby granted, free of charge, to any person obtaining a copy 00013 of this software and associated documentation files(the "Software"), to deal 00014 in the Software without restriction, including without limitation the rights 00015 to use, copy, modify, merge, publish, distribute, sublicense, and / or sell 00016 copies of the Software, and to permit persons to whom the Software is 00017 furnished to do so, subject to the following conditions : 00018 00019 The above copyright notice and this permission notice shall be included in all 00020 copies or substantial portions of the Software. 00021 00022 THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 00023 IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 00024 FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE 00025 AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 00026 LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 00027 OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 00028 SOFTWARE. 00029 ******************************************************************************/ 00030 00031 #ifndef __ETL_FORWARD_LIST__ 00032 #define __ETL_FORWARD_LIST__ 00033 00034 #include <iterator> 00035 #include <algorithm> 00036 #include <functional> 00037 #include <stddef.h> 00038 00039 #include "platform.h " 00040 #include "pool.h " 00041 #include "container.h " 00042 #include "exception.h " 00043 #include "error_handler.h " 00044 #include "debug_count.h " 00045 #include "nullptr.h " 00046 #include "type_traits.h " 00047 #include "parameter_type.h " 00048 00049 #ifdef ETL_COMPILER_MICROSOFT 00050 #undef min 00051 #endif 00052 00053 #undef ETL_FILE 00054 #define ETL_FILE "6" 00055 00056 //***************************************************************************** 00057 ///\defgroup forward_list forward_list 00058 /// A linked forward_list with the capacity defined at compile time. 00059 ///\ingroup containers 00060 //***************************************************************************** 00061 00062 namespace etl 00063 { 00064 //*************************************************************************** 00065 /// Exception for the forward_list. 00066 ///\ingroup forward_list 00067 //*************************************************************************** 00068 class forward_list_exception : public etl::exception 00069 { 00070 public: 00071 00072 forward_list_exception(string_type reason_, string_type file_name_, numeric_type line_number_) 00073 : exception(reason_, file_name_, line_number_) 00074 { 00075 } 00076 }; 00077 00078 //*************************************************************************** 00079 /// Full exception for the forward_list. 00080 ///\ingroup forward_list 00081 //*************************************************************************** 00082 class forward_list_full : public etl::forward_list_exception 00083 { 00084 public: 00085 00086 forward_list_full(string_type file_name_, numeric_type line_number_) 00087 : etl::forward_list_exception(ETL_ERROR_TEXT("forward_list:full", ETL_FILE"A"), file_name_, line_number_) 00088 { 00089 } 00090 }; 00091 00092 //*************************************************************************** 00093 /// Empty exception for the forward_list. 00094 ///\ingroup forward_list 00095 //*************************************************************************** 00096 class forward_list_empty : public etl::forward_list_exception 00097 { 00098 public: 00099 00100 forward_list_empty(string_type file_name_, numeric_type line_number_) 00101 : etl::forward_list_exception(ETL_ERROR_TEXT("forward_list:empty", ETL_FILE"B"), file_name_, line_number_) 00102 { 00103 } 00104 }; 00105 00106 //*************************************************************************** 00107 /// Iterator exception for the forward_list. 00108 ///\ingroup forward_list 00109 //*************************************************************************** 00110 class forward_list_iterator : public etl::forward_list_exception 00111 { 00112 public: 00113 00114 forward_list_iterator(string_type file_name_, numeric_type line_number_) 00115 : etl::forward_list_exception(ETL_ERROR_TEXT("forward_list:iterator", ETL_FILE"C"), file_name_, line_number_) 00116 { 00117 } 00118 }; 00119 00120 //*************************************************************************** 00121 /// The base class for all forward_lists. 00122 ///\ingroup forward_list 00123 //*************************************************************************** 00124 class forward_list_base 00125 { 00126 protected: 00127 00128 //************************************************************************* 00129 /// The node element in the forward_list. 00130 //************************************************************************* 00131 struct node_t 00132 { 00133 node_t() 00134 : next(std::nullptr) 00135 { 00136 } 00137 00138 node_t* next; 00139 }; 00140 00141 public: 00142 00143 typedef size_t size_type; ///< The type used for determining the size of forward_list. 00144 00145 //************************************************************************* 00146 /// Gets the size of the forward_list. 00147 //************************************************************************* 00148 size_type size() const 00149 { 00150 return p_node_pool->size(); 00151 } 00152 00153 //************************************************************************* 00154 /// Gets the maximum possible size of the forward_list. 00155 //************************************************************************* 00156 size_type max_size() const 00157 { 00158 return MAX_SIZE; 00159 } 00160 00161 //************************************************************************* 00162 /// Checks to see if the forward_list is empty. 00163 //************************************************************************* 00164 bool empty() const 00165 { 00166 return p_node_pool->empty(); 00167 } 00168 00169 //************************************************************************* 00170 /// Checks to see if the forward_list is full. 00171 //************************************************************************* 00172 bool full() const 00173 { 00174 return p_node_pool->full(); 00175 } 00176 00177 //************************************************************************* 00178 /// Returns the remaining capacity. 00179 ///\return The remaining capacity. 00180 //************************************************************************* 00181 size_t available() const 00182 { 00183 return p_node_pool->available(); 00184 } 00185 00186 //************************************************************************* 00187 /// Reverses the forward_list. 00188 //************************************************************************* 00189 void reverse() 00190 { 00191 if (is_trivial_list()) 00192 { 00193 return; 00194 } 00195 00196 node_t* p_last = &start_node; 00197 node_t* p_current = p_last->next; 00198 node_t* p_next = p_current->next; 00199 00200 p_current->next = std::nullptr; 00201 00202 while (p_next != std::nullptr) 00203 { 00204 p_last = p_current; 00205 p_current = p_next; 00206 p_next = p_current->next; 00207 00208 p_current->next = p_last; 00209 } 00210 00211 join(&start_node, p_current); 00212 } 00213 00214 protected: 00215 00216 //************************************************************************* 00217 /// The constructor that is called from derived classes. 00218 //************************************************************************* 00219 forward_list_base(etl::ipool& node_pool_, size_type max_size_) 00220 : p_node_pool(&node_pool_), 00221 MAX_SIZE(max_size_) 00222 { 00223 } 00224 00225 //************************************************************************* 00226 /// Get the head node. 00227 //************************************************************************* 00228 node_t& get_head() 00229 { 00230 return *start_node.next; 00231 } 00232 00233 //************************************************************************* 00234 /// Get the head node. 00235 //************************************************************************* 00236 const node_t& get_head() const 00237 { 00238 return *start_node.next; 00239 } 00240 00241 //************************************************************************* 00242 /// Insert a node. 00243 //************************************************************************* 00244 inline void insert_node_after(node_t& position, node_t& node) 00245 { 00246 // Connect to the forward_list. 00247 join(&node, position.next); 00248 join(&position, &node); 00249 } 00250 00251 //************************************************************************* 00252 /// Is the forward_list a trivial length? 00253 //************************************************************************* 00254 bool is_trivial_list() const 00255 { 00256 return (size() < 2); 00257 } 00258 00259 //************************************************************************* 00260 /// Join two nodes. 00261 //************************************************************************* 00262 void join(node_t* left, node_t* right) 00263 { 00264 left->next = right; 00265 } 00266 00267 node_t start_node; ///< The node that acts as the forward_list start. 00268 etl::ipool* p_node_pool; ///< The pool of data nodes used in the list. 00269 const size_type MAX_SIZE; ///< The maximum size of the forward_list. 00270 etl::debug_count construct_count; ///< Internal debugging. 00271 }; 00272 00273 //*************************************************************************** 00274 /// A templated base for all etl::forward_list types. 00275 ///\ingroup forward_list 00276 //*************************************************************************** 00277 template <typename T> 00278 class iforward_list : public etl::forward_list_base 00279 { 00280 public: 00281 00282 typedef T value_type; 00283 typedef T* pointer; 00284 typedef const T* const_pointer; 00285 typedef T& reference; 00286 typedef const T& const_reference; 00287 typedef size_t size_type; 00288 00289 protected: 00290 00291 typedef typename etl::parameter_type<T>::type parameter_t; 00292 00293 //************************************************************************* 00294 /// The data node element in the forward_list. 00295 //************************************************************************* 00296 struct data_node_t : public node_t 00297 { 00298 explicit data_node_t(parameter_t value_) 00299 : value(value_) 00300 {} 00301 00302 T value; 00303 }; 00304 00305 public: 00306 00307 //************************************************************************* 00308 /// iterator. 00309 //************************************************************************* 00310 class iterator : public std::iterator<std::forward_iterator_tag, T> 00311 { 00312 public: 00313 00314 friend class iforward_list; 00315 00316 iterator() 00317 : p_node(std::nullptr) 00318 { 00319 } 00320 00321 iterator(node_t& node) 00322 : p_node(&node) 00323 { 00324 } 00325 00326 iterator(const iterator& other) 00327 : p_node(other.p_node) 00328 { 00329 } 00330 00331 iterator& operator ++() 00332 { 00333 p_node = p_node->next; 00334 return *this; 00335 } 00336 00337 iterator operator ++(int) 00338 { 00339 iterator temp(*this); 00340 p_node = p_node->next; 00341 return temp; 00342 } 00343 00344 iterator operator =(const iterator& other) 00345 { 00346 p_node = other.p_node; 00347 return *this; 00348 } 00349 00350 reference operator *() 00351 { 00352 return iforward_list::data_cast(p_node)->value; 00353 } 00354 00355 const_reference operator *() const 00356 { 00357 return iforward_list::data_cast(p_node)->value; 00358 } 00359 00360 pointer operator &() 00361 { 00362 return &(iforward_list::data_cast(p_node)->value); 00363 } 00364 00365 const_pointer operator &() const 00366 { 00367 return &(iforward_list::data_cast(p_node)->value); 00368 } 00369 00370 pointer operator ->() 00371 { 00372 return &(iforward_list::data_cast(p_node)->value); 00373 } 00374 00375 const_pointer operator ->() const 00376 { 00377 return &(iforward_list::data_cast(p_node)->value); 00378 } 00379 00380 friend bool operator == (const iterator& lhs, const iterator& rhs) 00381 { 00382 return lhs.p_node == rhs.p_node; 00383 } 00384 00385 friend bool operator != (const iterator& lhs, const iterator& rhs) 00386 { 00387 return !(lhs == rhs); 00388 } 00389 00390 private: 00391 00392 node_t* p_node; 00393 }; 00394 00395 //************************************************************************* 00396 /// const_iterator 00397 //************************************************************************* 00398 class const_iterator : public std::iterator<std::forward_iterator_tag, const T> 00399 { 00400 public: 00401 00402 friend class iforward_list; 00403 00404 const_iterator() 00405 : p_node(std::nullptr) 00406 { 00407 } 00408 00409 const_iterator(node_t& node) 00410 : p_node(&node) 00411 { 00412 } 00413 00414 const_iterator(const node_t& node) 00415 : p_node(&node) 00416 { 00417 } 00418 00419 const_iterator(const typename iforward_list::iterator& other) 00420 : p_node(other.p_node) 00421 { 00422 } 00423 00424 const_iterator(const const_iterator& other) 00425 : p_node(other.p_node) 00426 { 00427 } 00428 00429 const_iterator& operator ++() 00430 { 00431 p_node = p_node->next; 00432 return *this; 00433 } 00434 00435 const_iterator operator ++(int) 00436 { 00437 const_iterator temp(*this); 00438 p_node = p_node->next; 00439 return temp; 00440 } 00441 00442 const_iterator operator =(const const_iterator& other) 00443 { 00444 p_node = other.p_node; 00445 return *this; 00446 } 00447 00448 const_reference operator *() const 00449 { 00450 return iforward_list::data_cast(p_node)->value; 00451 } 00452 00453 const_pointer operator &() const 00454 { 00455 return &(iforward_list::data_cast(p_node)->value); 00456 } 00457 00458 const_pointer operator ->() const 00459 { 00460 return &(iforward_list::data_cast(p_node)->value); 00461 } 00462 00463 friend bool operator == (const const_iterator& lhs, const const_iterator& rhs) 00464 { 00465 return lhs.p_node == rhs.p_node; 00466 } 00467 00468 friend bool operator != (const const_iterator& lhs, const const_iterator& rhs) 00469 { 00470 return !(lhs == rhs); 00471 } 00472 00473 private: 00474 00475 const node_t* p_node; 00476 }; 00477 00478 typedef typename std::iterator_traits<iterator>::difference_type difference_type; 00479 00480 //************************************************************************* 00481 /// Gets the beginning of the forward_list. 00482 //************************************************************************* 00483 iterator begin() 00484 { 00485 return iterator(data_cast(get_head())); 00486 } 00487 00488 //************************************************************************* 00489 /// Gets the beginning of the forward_list. 00490 //************************************************************************* 00491 const_iterator begin() const 00492 { 00493 return const_iterator(data_cast(get_head())); 00494 } 00495 00496 //************************************************************************* 00497 /// Gets before the beginning of the forward_list. 00498 //************************************************************************* 00499 iterator before_begin() 00500 { 00501 return iterator(static_cast<data_node_t&>(start_node)); 00502 } 00503 00504 //************************************************************************* 00505 /// Gets before the beginning of the forward_list. 00506 //************************************************************************* 00507 const_iterator before_begin() const 00508 { 00509 return const_iterator(static_cast<const data_node_t&>(start_node)); 00510 } 00511 00512 //************************************************************************* 00513 /// Gets the beginning of the forward_list. 00514 //************************************************************************* 00515 const_iterator cbegin() const 00516 { 00517 return const_iterator(get_head()); 00518 } 00519 00520 //************************************************************************* 00521 /// Gets the end of the forward_list. 00522 //************************************************************************* 00523 iterator end() 00524 { 00525 return iterator(); 00526 } 00527 00528 //************************************************************************* 00529 /// Gets the end of the forward_list. 00530 //************************************************************************* 00531 const_iterator end() const 00532 { 00533 return const_iterator(); 00534 } 00535 00536 //************************************************************************* 00537 /// Gets the end of the forward_list. 00538 //************************************************************************* 00539 const_iterator cend() const 00540 { 00541 return const_iterator(); 00542 } 00543 00544 //************************************************************************* 00545 /// Clears the forward_list. 00546 //************************************************************************* 00547 void clear() 00548 { 00549 initialise(); 00550 } 00551 00552 //************************************************************************* 00553 /// Gets a reference to the first element. 00554 //************************************************************************* 00555 reference front() 00556 { 00557 return data_cast(get_head()).value; 00558 } 00559 00560 //************************************************************************* 00561 /// Gets a const reference to the first element. 00562 //************************************************************************* 00563 const_reference front() const 00564 { 00565 return data_cast(get_head()).value; 00566 } 00567 00568 //************************************************************************* 00569 /// Assigns a range of values to the forward_list. 00570 /// If asserts or exceptions are enabled throws etl::forward_list_full if the forward_list does not have enough free space. 00571 /// If ETL_THROW_EXCEPTIONS & ETL_DEBUG are defined throws forward_list_iterator if the iterators are reversed. 00572 //************************************************************************* 00573 template <typename TIterator> 00574 void assign(TIterator first, TIterator last) 00575 { 00576 #if defined(ETL_DEBUG) 00577 difference_type d = std::distance(first, last); 00578 ETL_ASSERT(d >= 0, ETL_ERROR(forward_list_iterator)); 00579 #endif 00580 00581 initialise(); 00582 00583 node_t* p_last_node = &start_node; 00584 00585 // Add all of the elements. 00586 while (first != last) 00587 { 00588 ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); 00589 00590 data_node_t& data_node = allocate_data_node(*first++); 00591 join(p_last_node, &data_node); 00592 data_node.next = std::nullptr; 00593 p_last_node = &data_node; 00594 } 00595 } 00596 00597 //************************************************************************* 00598 /// Assigns 'n' copies of a value to the forward_list. 00599 //************************************************************************* 00600 void assign(size_t n, parameter_t value) 00601 { 00602 ETL_ASSERT(n <= MAX_SIZE, ETL_ERROR(forward_list_full)); 00603 00604 initialise(); 00605 00606 node_t* p_last_node = &start_node; 00607 00608 // Add all of the elements. 00609 while (size() < n) 00610 { 00611 data_node_t& data_node = allocate_data_node(value); 00612 join(p_last_node, &data_node); 00613 data_node.next = std::nullptr; 00614 p_last_node = &data_node; 00615 } 00616 } 00617 00618 //************************************************************************* 00619 /// Adds a node to the front of the forward_list so a new value can be assigned to front(). 00620 //************************************************************************* 00621 void push_front() 00622 { 00623 push_front(T()); 00624 } 00625 00626 //************************************************************************* 00627 /// Pushes a value to the front of the forward_list. 00628 //************************************************************************* 00629 void push_front(parameter_t value) 00630 { 00631 #if defined(ETL_CHECK_PUSH_POP) 00632 ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); 00633 #endif 00634 00635 data_node_t& data_node = allocate_data_node(value); 00636 insert_node_after(start_node, data_node); 00637 } 00638 00639 //************************************************************************* 00640 /// Emplaces a value to the front of the list.. 00641 //************************************************************************* 00642 template <typename T1> 00643 void emplace_front(const T1& value1) 00644 { 00645 #if defined(ETL_CHECK_PUSH_POP) 00646 ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); 00647 #endif 00648 data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); 00649 ::new (&(p_data_node->value)) T(value1); 00650 ++construct_count; 00651 insert_node_after(start_node, *p_data_node); 00652 } 00653 00654 //************************************************************************* 00655 /// Emplaces a value to the front of the list.. 00656 //************************************************************************* 00657 template <typename T1, typename T2> 00658 void emplace_front(const T1& value1, const T2& value2) 00659 { 00660 #if defined(ETL_CHECK_PUSH_POP) 00661 ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); 00662 #endif 00663 data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); 00664 ::new (&(p_data_node->value)) T(value1, value2); 00665 ++construct_count; 00666 insert_node_after(start_node, *p_data_node); 00667 } 00668 00669 //************************************************************************* 00670 /// Emplaces a value to the front of the list.. 00671 //************************************************************************* 00672 template <typename T1, typename T2, typename T3> 00673 void emplace_front(const T1& value1, const T2& value2, const T3& value3) 00674 { 00675 #if defined(ETL_CHECK_PUSH_POP) 00676 ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); 00677 #endif 00678 data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); 00679 ::new (&(p_data_node->value)) T(value1, value2, value3); 00680 ++construct_count; 00681 insert_node_after(start_node, *p_data_node); 00682 } 00683 00684 //************************************************************************* 00685 /// Emplaces a value to the front of the list.. 00686 //************************************************************************* 00687 template <typename T1, typename T2, typename T3, typename T4> 00688 void emplace_front(const T1& value1, const T2& value2, const T3& value3, const T4& value4) 00689 { 00690 #if defined(ETL_CHECK_PUSH_POP) 00691 ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); 00692 #endif 00693 data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); 00694 ::new (&(p_data_node->value)) T(value1, value2, value3, value4); 00695 ++construct_count; 00696 insert_node_after(start_node, *p_data_node); 00697 } 00698 00699 //************************************************************************* 00700 /// Removes a value from the front of the forward_list. 00701 //************************************************************************* 00702 void pop_front() 00703 { 00704 #if defined(ETL_CHECK_PUSH_POP) 00705 ETL_ASSERT(!empty(), ETL_ERROR(forward_list_empty)); 00706 #endif 00707 remove_node_after(start_node); 00708 } 00709 00710 //************************************************************************* 00711 /// Resizes the forward_list. 00712 //************************************************************************* 00713 void resize(size_t n) 00714 { 00715 resize(n, T()); 00716 } 00717 00718 //************************************************************************* 00719 /// Resizes the forward_list. 00720 /// If asserts or exceptions are enabled, will throw an etl::forward_list_full 00721 /// if <b>n</b> is larger than the maximum size. 00722 //************************************************************************* 00723 void resize(size_t n, T value) 00724 { 00725 ETL_ASSERT(n <= MAX_SIZE, ETL_ERROR(forward_list_full)); 00726 00727 size_t i = 0; 00728 iterator i_node = begin(); 00729 iterator i_last_node; 00730 00731 // Find where we're currently at. 00732 while ((i < n) && (i_node != end())) 00733 { 00734 ++i; 00735 i_last_node = i_node; 00736 ++i_node; 00737 } 00738 00739 if (i_node != end()) 00740 { 00741 // Reduce. 00742 erase_after(i_last_node, end()); 00743 } 00744 else if (i_node == end()) 00745 { 00746 // Increase. 00747 while (i < n) 00748 { 00749 i_last_node = insert_after(i_last_node, value); 00750 ++i; 00751 } 00752 } 00753 } 00754 00755 //************************************************************************* 00756 /// Inserts a value to the forward_list after the specified position. 00757 //************************************************************************* 00758 iterator insert_after(iterator position, parameter_t value) 00759 { 00760 ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); 00761 00762 data_node_t& data_node = allocate_data_node(value); 00763 insert_node_after(*position.p_node, data_node); 00764 00765 return iterator(data_node); 00766 } 00767 00768 //************************************************************************* 00769 /// Emplaces a value to the forward_list after the specified position. 00770 //************************************************************************* 00771 template <typename T1> 00772 iterator emplace_after(iterator position, const T1& value1) 00773 { 00774 ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); 00775 00776 data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); 00777 ::new (&(p_data_node->value)) T(value1); 00778 ++construct_count; 00779 insert_node_after(*position.p_node, *p_data_node); 00780 00781 return iterator(*p_data_node); 00782 } 00783 00784 //************************************************************************* 00785 /// Emplaces a value to the forward_list after the specified position. 00786 //************************************************************************* 00787 template <typename T1, typename T2> 00788 iterator emplace_after(iterator position, const T1& value1, const T2& value2) 00789 { 00790 ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); 00791 00792 data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); 00793 ::new (&(p_data_node->value)) T(value1, value2); 00794 ++construct_count; 00795 insert_node_after(*position.p_node, *p_data_node); 00796 00797 return iterator(*p_data_node); 00798 } 00799 00800 //************************************************************************* 00801 /// Emplaces a value to the forward_list after the specified position. 00802 //************************************************************************* 00803 template <typename T1, typename T2, typename T3> 00804 iterator emplace_after(iterator position, const T1& value1, const T2& value2, const T3& value3) 00805 { 00806 ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); 00807 00808 data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); 00809 ::new (&(p_data_node->value)) T(value1, value2, value3); 00810 ++construct_count; 00811 insert_node_after(*position.p_node, *p_data_node); 00812 00813 return iterator(*p_data_node); 00814 } 00815 00816 //************************************************************************* 00817 /// Emplaces a value to the forward_list after the specified position. 00818 //************************************************************************* 00819 template <typename T1, typename T2, typename T3, typename T4> 00820 iterator emplace_after(iterator position, const T1& value1, const T2& value2, const T3& value3, const T4& value4) 00821 { 00822 ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); 00823 00824 data_node_t* p_data_node = p_node_pool->allocate<data_node_t>(); 00825 ::new (&(p_data_node->value)) T(value1, value2, value3, value4); 00826 ++construct_count; 00827 insert_node_after(*position.p_node, *p_data_node); 00828 00829 return iterator(*p_data_node); 00830 } 00831 00832 //************************************************************************* 00833 /// Inserts 'n' copies of a value to the forward_list after the specified position. 00834 //************************************************************************* 00835 void insert_after(iterator position, size_t n, parameter_t value) 00836 { 00837 ETL_ASSERT(!full(), ETL_ERROR(forward_list_full)); 00838 00839 for (size_t i = 0; !full() && (i < n); ++i) 00840 { 00841 // Set up the next free node. 00842 data_node_t& data_node = allocate_data_node(value); 00843 insert_node_after(*position.p_node, data_node); 00844 } 00845 } 00846 00847 //************************************************************************* 00848 /// Inserts a range of values to the forward_list after the specified position. 00849 //************************************************************************* 00850 template <typename TIterator> 00851 void insert_after(iterator position, TIterator first, TIterator last) 00852 { 00853 #if defined(ETL_DEBUG) 00854 difference_type d = std::distance(first, last); 00855 ETL_ASSERT((d + size()) <= MAX_SIZE, ETL_ERROR(forward_list_full)); 00856 #endif 00857 00858 while (first != last) 00859 { 00860 // Set up the next free node. 00861 data_node_t& data_node = allocate_data_node(*first++); 00862 insert_node_after(*position.p_node, data_node); 00863 ++position; 00864 } 00865 } 00866 00867 //************************************************************************* 00868 /// Erases the value at the specified position. 00869 //************************************************************************* 00870 iterator erase_after(iterator position) 00871 { 00872 iterator next(position); 00873 if (next != end()) 00874 { 00875 ++next; 00876 if (next != end()) 00877 { 00878 ++next; 00879 remove_node_after(*position.p_node); 00880 } 00881 } 00882 00883 return next; 00884 } 00885 00886 //************************************************************************* 00887 /// Erases a range of elements. 00888 //************************************************************************* 00889 iterator erase_after(iterator first, iterator last) 00890 { 00891 if (first != end() && (first != last)) 00892 { 00893 node_t* p_first = first.p_node; 00894 node_t* p_last = last.p_node; 00895 node_t* p_next = p_first->next; 00896 00897 // Join the ends. 00898 join(p_first, p_last); 00899 00900 p_first = p_next; 00901 00902 // Erase the ones in between. 00903 while (p_first != p_last) 00904 { 00905 p_next = p_first->next; // Remember the next node. 00906 destroy_data_node(static_cast<data_node_t&>(*p_first)); // Destroy the pool object. 00907 p_first = p_next; // Move to the next node. 00908 } 00909 00910 if (p_next == std::nullptr) 00911 { 00912 return end(); 00913 } 00914 else 00915 { 00916 return iterator(*p_last); 00917 } 00918 } 00919 else 00920 { 00921 return end(); 00922 } 00923 } 00924 00925 //************************************************************************* 00926 /// Erases the value at the specified position. 00927 //************************************************************************* 00928 void move_after(const_iterator from_before, const_iterator to_before) 00929 { 00930 if (from_before == to_before) // Can't move to after yourself! 00931 { 00932 return; 00933 } 00934 00935 node_t* p_from_before = const_cast<node_t*>(from_before.p_node); // We're not changing the value, just it's position. 00936 node_t* p_to_before = const_cast<node_t*>(to_before.p_node); // We're not changing the value, just it's position. 00937 00938 node_t* p_from = p_from_before->next; 00939 00940 // Disconnect from the list. 00941 join(p_from_before, p_from->next); 00942 00943 // Attach it to the new position. 00944 join(p_from, p_to_before->next); 00945 join(p_to_before, p_from); 00946 } 00947 00948 //************************************************************************* 00949 /// Moves a range from one position to another within the list. 00950 /// Moves a range at position 'first_before'/'last' to the position before 'to_before'. 00951 //************************************************************************* 00952 void move_after(const_iterator first_before, const_iterator last, const_iterator to_before) 00953 { 00954 if ((first_before == to_before) || (last == to_before)) 00955 { 00956 return; // Can't more to before yourself! 00957 } 00958 00959 #if defined(ETL_DEBUG) 00960 // Check that we are not doing an illegal move! 00961 for (const_iterator item = first_before; item != last; ++item) 00962 { 00963 ETL_ASSERT(item != to_before, ETL_ERROR(forward_list_iterator)); 00964 } 00965 #endif 00966 00967 node_t* p_first_before = const_cast<node_t*>(first_before.p_node); // We're not changing the value, just it's position. 00968 node_t* p_last = const_cast<node_t*>(last.p_node); // We're not changing the value, just it's position. 00969 node_t* p_to_before = const_cast<node_t*>(to_before.p_node); // We're not changing the value, just it's position. 00970 node_t* p_first = p_first_before->next; 00971 node_t* p_final = p_first_before; 00972 00973 // Find the last node that will be moved. 00974 while (p_final->next != p_last) 00975 { 00976 p_final = p_final->next; 00977 } 00978 00979 // Disconnect from the list. 00980 join(p_first_before, p_final->next); 00981 00982 // Attach it to the new position. 00983 join(p_final, p_to_before->next); 00984 join(p_to_before, p_first); 00985 } 00986 00987 //************************************************************************* 00988 /// Removes all but the first element from every consecutive group of equal 00989 /// elements in the container. 00990 //************************************************************************* 00991 void unique() 00992 { 00993 unique(std::equal_to<T>()); 00994 } 00995 00996 //************************************************************************* 00997 /// Removes all but the one element from every consecutive group of equal 00998 /// elements in the container. 00999 //************************************************************************* 01000 template <typename TIsEqual> 01001 void unique(TIsEqual isEqual) 01002 { 01003 if (empty()) 01004 { 01005 return; 01006 } 01007 01008 node_t* last = &get_head(); 01009 node_t* current = last->next; 01010 01011 while (current != std::nullptr) 01012 { 01013 // Is this value the same as the last? 01014 if (isEqual(data_cast(current)->value, data_cast(last)->value)) 01015 { 01016 remove_node_after(*last); 01017 } 01018 else 01019 { 01020 // Move on one. 01021 last = current; 01022 } 01023 01024 current = last->next; 01025 } 01026 } 01027 01028 //************************************************************************* 01029 /// Sort using in-place merge sort algorithm. 01030 /// Uses 'less-than operator as the predicate. 01031 //************************************************************************* 01032 void sort() 01033 { 01034 sort(std::less<T>()); 01035 } 01036 01037 //************************************************************************* 01038 /// Sort using in-place merge sort algorithm. 01039 /// Uses a supplied predicate function or functor. 01040 /// This is not my algorithm. I got it off the web somewhere. 01041 //************************************************************************* 01042 template <typename TCompare> 01043 void sort(TCompare compare) 01044 { 01045 iterator p_left; 01046 iterator p_right; 01047 iterator p_node; 01048 iterator p_head; 01049 iterator p_tail; 01050 int list_size = 1; 01051 int number_of_merges; 01052 int left_size; 01053 int right_size; 01054 01055 if (is_trivial_list()) 01056 { 01057 return; 01058 } 01059 01060 while (true) 01061 { 01062 p_left = begin(); 01063 p_head = before_begin(); 01064 p_tail = before_begin(); 01065 01066 number_of_merges = 0; // Count the number of merges we do in this pass. 01067 01068 while (p_left != end()) 01069 { 01070 ++number_of_merges; // There exists a merge to be done. 01071 p_right = p_left; 01072 left_size = 0; 01073 01074 // Step 'list_size' places along from left 01075 for (int i = 0; i < list_size; ++i) 01076 { 01077 ++left_size; 01078 01079 ++p_right; 01080 01081 if (p_right == end()) 01082 { 01083 break; 01084 } 01085 } 01086 01087 // If right hasn't fallen off end, we have two lists to merge. 01088 right_size = list_size; 01089 01090 // Now we have two lists. Merge them. 01091 while (left_size > 0 || (right_size > 0 && p_right != end())) 01092 { 01093 // Decide whether the next node of merge comes from left or right. 01094 if (left_size == 0) 01095 { 01096 // Left is empty. The node must come from right. 01097 p_node = p_right; 01098 ++p_right; 01099 --right_size; 01100 } 01101 else if (right_size == 0 || p_right == end()) 01102 { 01103 // Right is empty. The node must come from left. 01104 p_node = p_left; 01105 ++p_left; 01106 --left_size; 01107 } 01108 else if (!compare(*p_right, *p_left)) 01109 { 01110 // First node of left is lower or same. The node must come from left. 01111 p_node = p_left; 01112 ++p_left; 01113 --left_size; 01114 } 01115 else 01116 { 01117 // First node of right is lower. The node must come from right. 01118 p_node = p_right; 01119 ++p_right; 01120 --right_size; 01121 } 01122 01123 // Add the next node to the merged head. 01124 if (p_head == before_begin()) 01125 { 01126 join(p_head.p_node, p_node.p_node); 01127 p_head = p_node; 01128 p_tail = p_node; 01129 } 01130 else 01131 { 01132 join(p_tail.p_node, p_node.p_node); 01133 p_tail = p_node; 01134 } 01135 01136 p_tail.p_node->next = std::nullptr; 01137 } 01138 01139 // Now left has stepped `list_size' places along, and right has too. 01140 p_left = p_right; 01141 } 01142 01143 // If we have done only one merge, we're finished. 01144 if (number_of_merges <= 1) // Allow for number_of_merges == 0, the empty head case 01145 { 01146 return; 01147 } 01148 01149 // Otherwise repeat, merging lists twice the size 01150 list_size *= 2; 01151 } 01152 } 01153 01154 //************************************************************************* 01155 // Removes the values specified. 01156 //************************************************************************* 01157 void remove(parameter_t value) 01158 { 01159 iterator i_item = begin(); 01160 iterator i_last_item = before_begin(); 01161 01162 while (i_item != end()) 01163 { 01164 if (*i_item == value) 01165 { 01166 i_item = erase_after(i_last_item); 01167 } 01168 else 01169 { 01170 ++i_item; 01171 ++i_last_item; 01172 } 01173 } 01174 } 01175 01176 //************************************************************************* 01177 /// Removes according to a predicate. 01178 //************************************************************************* 01179 template <typename TPredicate> 01180 void remove_if(TPredicate predicate) 01181 { 01182 iterator i_item = begin(); 01183 iterator i_last_item = before_begin(); 01184 01185 while (i_item != end()) 01186 { 01187 if (predicate(*i_item)) 01188 { 01189 i_item = erase_after(i_last_item); 01190 } 01191 else 01192 { 01193 ++i_item; 01194 ++i_last_item; 01195 } 01196 } 01197 } 01198 01199 //************************************************************************* 01200 /// Assignment operator. 01201 //************************************************************************* 01202 iforward_list& operator = (const iforward_list& rhs) 01203 { 01204 if (&rhs != this) 01205 { 01206 assign(rhs.cbegin(), rhs.cend()); 01207 } 01208 01209 return *this; 01210 } 01211 01212 protected: 01213 01214 //************************************************************************* 01215 /// Constructor. 01216 //************************************************************************* 01217 iforward_list(etl::ipool& node_pool, size_t max_size_) 01218 : forward_list_base(node_pool, max_size_) 01219 { 01220 } 01221 01222 //************************************************************************* 01223 /// Initialise the forward_list. 01224 //************************************************************************* 01225 void initialise() 01226 { 01227 if (!empty()) 01228 { 01229 node_t* p_first = start_node.next; 01230 node_t* p_next; 01231 01232 // Erase the ones in between. 01233 while (p_first != std::nullptr) 01234 { 01235 p_next = p_first->next; // Remember the next node. 01236 destroy_data_node(static_cast<data_node_t&>(*p_first)); // Destroy the pool object. 01237 p_first = p_next; // Move to the next node. 01238 } 01239 } 01240 01241 start_node.next = std::nullptr; 01242 } 01243 01244 private: 01245 01246 //************************************************************************* 01247 /// Downcast a node_t* to a data_node_t* 01248 //************************************************************************* 01249 static data_node_t* data_cast(node_t* p_node) 01250 { 01251 return static_cast<data_node_t*>(p_node); 01252 } 01253 01254 //************************************************************************* 01255 /// Downcast a node_t& to a data_node_t& 01256 //************************************************************************* 01257 static data_node_t& data_cast(node_t& node) 01258 { 01259 return static_cast<data_node_t&>(node); 01260 } 01261 01262 //************************************************************************* 01263 /// Downcast a const node_t* to a const data_node_t* 01264 //************************************************************************* 01265 static const data_node_t* data_cast(const node_t* p_node) 01266 { 01267 return static_cast<const data_node_t*>(p_node); 01268 } 01269 01270 //************************************************************************* 01271 /// Downcast a const node_t& to a const data_node_t& 01272 //************************************************************************* 01273 static const data_node_t& data_cast(const node_t& node) 01274 { 01275 return static_cast<const data_node_t&>(node); 01276 } 01277 01278 //************************************************************************* 01279 /// Remove a node. 01280 //************************************************************************* 01281 void remove_node_after(node_t& node) 01282 { 01283 // The node to erase. 01284 node_t* p_node = node.next; 01285 01286 if (p_node != std::nullptr) 01287 { 01288 // Disconnect the node from the forward_list. 01289 join(&node, p_node->next); 01290 01291 // Destroy the pool object. 01292 destroy_data_node(static_cast<data_node_t&>(*p_node)); 01293 } 01294 } 01295 01296 //************************************************************************* 01297 /// Allocate a data_node_t. 01298 //************************************************************************* 01299 data_node_t& allocate_data_node(parameter_t value) 01300 { 01301 data_node_t* p_node = p_node_pool->allocate<data_node_t>(); 01302 ::new (&(p_node->value)) T(value); 01303 ++construct_count; 01304 01305 return *p_node; 01306 } 01307 01308 //************************************************************************* 01309 /// Destroy a data_node_t. 01310 //************************************************************************* 01311 void destroy_data_node(data_node_t& node) 01312 { 01313 node.value.~T(); 01314 p_node_pool->release(&node); 01315 --construct_count; 01316 } 01317 01318 // Disable copy construction. 01319 iforward_list(const iforward_list&); 01320 }; 01321 01322 //************************************************************************* 01323 /// A templated forward_list implementation that uses a fixed size pool. 01324 ///\note 'merge' and 'splice_after' and are not supported. 01325 //************************************************************************* 01326 template <typename T, const size_t MAX_SIZE_> 01327 class forward_list : public etl::iforward_list<T> 01328 { 01329 public: 01330 01331 static const size_t MAX_SIZE = MAX_SIZE_; 01332 01333 public: 01334 01335 typedef T value_type; 01336 typedef T* pointer; 01337 typedef const T* const_pointer; 01338 typedef T& reference; 01339 typedef const T& const_reference; 01340 typedef size_t size_type; 01341 01342 //************************************************************************* 01343 /// Default constructor. 01344 //************************************************************************* 01345 forward_list() 01346 : etl::iforward_list<T>(node_pool, MAX_SIZE) 01347 { 01348 etl::iforward_list<T>::initialise(); 01349 } 01350 01351 //************************************************************************* 01352 /// Construct from size and value. 01353 //************************************************************************* 01354 explicit forward_list(size_t initial_size, typename etl::iforward_list<T>::parameter_t value = T()) 01355 : etl::iforward_list<T>(node_pool, MAX_SIZE) 01356 { 01357 etl::iforward_list<T>::assign(initial_size, value); 01358 } 01359 01360 //************************************************************************* 01361 /// Copy constructor. 01362 //************************************************************************* 01363 forward_list(const forward_list& other) 01364 : etl::iforward_list<T>(node_pool, MAX_SIZE) 01365 { 01366 etl::iforward_list<T>::assign(other.cbegin(), other.cend()); 01367 } 01368 01369 //************************************************************************* 01370 /// Construct from range. 01371 //************************************************************************* 01372 template <typename TIterator> 01373 forward_list(TIterator first, TIterator last) 01374 : etl::iforward_list<T>(node_pool, MAX_SIZE) 01375 { 01376 etl::iforward_list<T>::assign(first, last); 01377 } 01378 01379 //************************************************************************* 01380 /// Destructor. 01381 //************************************************************************* 01382 ~forward_list() 01383 { 01384 etl::iforward_list<T>::initialise(); 01385 } 01386 01387 //************************************************************************* 01388 /// Assignment operator. 01389 //************************************************************************* 01390 forward_list& operator = (const forward_list& rhs) 01391 { 01392 if (&rhs != this) 01393 { 01394 etl::iforward_list<T>::assign(rhs.cbegin(), rhs.cend()); 01395 } 01396 01397 return *this; 01398 } 01399 01400 private: 01401 01402 /// The pool of nodes used in the list. 01403 etl::pool<typename etl::iforward_list<T>::data_node_t, MAX_SIZE> node_pool; 01404 }; 01405 } 01406 01407 //************************************************************************* 01408 /// Equal operator. 01409 ///\param lhs Reference to the first forward_list. 01410 ///\param rhs Reference to the second forward_list. 01411 ///\return <b>true</b> if the arrays are equal, otherwise <b>false</b>. 01412 //************************************************************************* 01413 template <typename T> 01414 bool operator ==(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs) 01415 { 01416 return (lhs.size() == rhs.size()) && 01417 std::equal(lhs.begin(), lhs.end(), rhs.begin()); 01418 } 01419 01420 //************************************************************************* 01421 /// Not equal operator. 01422 ///\param lhs Reference to the first forward_list. 01423 ///\param rhs Reference to the second forward_list. 01424 ///\return <b>true</b> if the arrays are not equal, otherwise <b>false</b>. 01425 //************************************************************************* 01426 template <typename T> 01427 bool operator !=(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs) 01428 { 01429 return !(lhs == rhs); 01430 } 01431 01432 //************************************************************************* 01433 /// Less than operator. 01434 ///\param lhs Reference to the first forward_list. 01435 ///\param rhs Reference to the second forward_list. 01436 ///\return <b>true</b> if the first forward_list is lexicographically less than the 01437 /// second, otherwise <b>false</b>. 01438 //************************************************************************* 01439 template <typename T> 01440 bool operator <(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs) 01441 { 01442 return std::lexicographical_compare(lhs.begin(), 01443 lhs.end(), 01444 rhs.begin(), 01445 rhs.end()); 01446 } 01447 01448 //************************************************************************* 01449 /// Greater than operator. 01450 ///\param lhs Reference to the first forward_list. 01451 ///\param rhs Reference to the second forward_list. 01452 ///\return <b>true</b> if the first forward_list is lexicographically greater than the 01453 /// second, otherwise <b>false</b>. 01454 //************************************************************************* 01455 template <typename T> 01456 bool operator >(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs) 01457 { 01458 return (rhs < lhs); 01459 } 01460 01461 //************************************************************************* 01462 /// Less than or equal operator. 01463 ///\param lhs Reference to the first forward_list. 01464 ///\param rhs Reference to the second forward_list. 01465 ///\return <b>true</b> if the first forward_list is lexicographically less than or equal 01466 /// to the second, otherwise <b>false</b>. 01467 //************************************************************************* 01468 template <typename T> 01469 bool operator <=(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs) 01470 { 01471 return !(lhs > rhs); 01472 } 01473 01474 //************************************************************************* 01475 /// Greater than or equal operator. 01476 ///\param lhs Reference to the first forward_list. 01477 ///\param rhs Reference to the second forward_list. 01478 ///\return <b>true</b> if the first forward_list is lexicographically greater than or 01479 /// equal to the second, otherwise <b>false</b>. 01480 //************************************************************************* 01481 template <typename T> 01482 bool operator >=(const etl::iforward_list<T>& lhs, const etl::iforward_list<T>& rhs) 01483 { 01484 return !(lhs < rhs); 01485 } 01486 01487 #ifdef ETL_COMPILER_MICROSOFT 01488 #define min(a,b) (((a) < (b)) ? (a) : (b)) 01489 #endif 01490 01491 #undef ETL_FILE 01492 01493 #endif 01494
Generated on Tue Jul 12 2022 14:05:41 by
