2 * Implementation of a Generic Data Structure Container Template including STL Iterator
3 * Copyright (c) 2014 TJ <hacker@iam.tj>
5 * This program is free software: you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation, either version 3 of the License.
9 * This program is distributed in the hope that it will be useful,
10 * but WITHOUT ANY WARRANTY; without even the implied warranty of
11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 * GNU General Public License for more details.
14 * You should have received a copy of the GNU General Public License
15 * along with this program. If not, see <http://www.gnu.org/licenses/>.
17 * see ./COPYRIGHT or http://www.gnu.org/licenses/gpl-3.0.html
20 #ifndef _GENERICSTORAGECONTAINERTEMPLATEIMPL_HPP_
21 #define _GENERICSTORAGECONTAINERTEMPLATEIMPL_HPP_
23 #include "DataStructures.hpp"
30 /* A generic Container that can use different internal data structures
31 * (Array, Linked-List, Binary Search Tree) determined by
32 * application code at compile time using the power of Templating
33 * and Metaprogramming of C++11 and later.
35 * Default data structure is a Dynamic Array
37 * Uses Metaprogramming conditionals to create constant and non-constant iterators
38 * from a single iterator definition. Provides typedefs to make instantiating the
39 * correct type of iterator easier to read and write in application code.
41 * template parameters:
42 * T = type being stored
43 * DATA_STRUCTURE = class providing underlying storage of T elements, defaults to dynamic array
45 * For template template parameters see http://en.cppreference.com/w/cpp/language/template_parameters
47 template <typename T, template<typename> class DATA_STRUCTURE = DataStructure_ArrayDynamic>
48 class GenericStorageContainerTemplateImpl
50 // easy to read aliases
51 typedef AbstractDataStructure<T> DS_BASE_CLASS; // for access to enums
53 // data structure type is templated and decided by application code at compilation time
54 DATA_STRUCTURE<T> data_structure_;
59 /* constant and non-constant custom Standard Template Library (STL) compatible iterators
60 * avoiding writing 2 separate class definitions that only differ on their
61 * constant vs non-constant type specifiers. This makes extensive use of
62 * template metaprogramming
64 * defaults to a non-const iterator
66 template <bool is_const_iterator = false>
67 class iterator : public std::iterator< std::bidirectional_iterator_tag, AbstractDataStructure<T> >
69 typedef iterator self_type;
70 typedef typename std::conditional< is_const_iterator, const AbstractDataStructure<T>, AbstractDataStructure<T> >::type value_type;
71 typedef typename std::conditional< is_const_iterator, const AbstractDataStructure<T>&, AbstractDataStructure<T>& >::type reference;
72 typedef typename std::conditional< is_const_iterator, const AbstractDataStructure<T>*, AbstractDataStructure<T>* >::type pointer;
73 typedef std::bidirectional_iterator_tag iterator_category;
74 typedef int difference_type;
76 DATA_STRUCTURE<T>* element_;
80 iterator<is_const_iterator> () {};
81 iterator<is_const_iterator> (DATA_STRUCTURE<T>* element) : element_(element) {};
82 iterator<is_const_iterator> (const iterator<is_const_iterator>& copy) : element_(copy.element_) {}; // copy constructor
84 /* ForwardIterator methods */
86 // postfix increment operator
87 self_type operator++()
89 self_type original(*this); // need to keep a copy of the current value so it can be returned
91 DATA_STRUCTURE<T>* temp = element_->get_next();
93 element_ = temp; // the increment changes the item being referenced
98 // prefix increment operator
99 self_type operator++(int unused)
101 DATA_STRUCTURE<T>* result = nullptr;
104 result = element_->get_next();
110 /* BidirectionalIterator methods */
113 self_type operator--()
115 self_type original(*this); // keep copy that is to be returned
116 this->element_->get_previous();
121 self_type operator--(int unused)
124 element_ = element_->get_previous();
132 bool operator==(const self_type& right_hand_side)
136 if (element_ && right_hand_side.element_)
137 result = *this->element_ == *right_hand_side.element_;
142 // implemented using operator==()
143 bool operator!=(const self_type& right_hand_side)
145 return !this->operator==(right_hand_side);
148 bool operator<(const self_type& right_hand_side)
152 if (element_ && right_hand_side.element_)
153 result = *this->element_ < *right_hand_side.element_;
158 // implemented using operator==() and operator<()
159 bool operator<=(const self_type& right_hand_side)
161 return this->operator==(right_hand_side) | this->operator<(right_hand_side);
170 return element_ ? *element_->get_data() : 0;
174 std::conditional<is_const_iterator, const T*, T*> operator->()
176 return &element_->get_data();
179 // allow const and non-const iterator copy-contructors access to private members of each other
180 friend class iterator<!is_const_iterator>;
182 }; // end of Iterator
184 // use these handy aliases in application code
185 typedef iterator<true> _const_iterator;
186 typedef iterator<false> _iterator;
188 /* methods directly supporting use of the iterator uses 'template' to avoid
189 * writing 4 method definitions (2 for constant and 2 for non-constant iterators)
191 * begin() and end() are used in code that instantiates the iterator:
193 * GSCTI<int> container;
194 * container.append(1);
195 * container.append(2);
197 * for (_const_iterator i = container.begin(); i != container.end(); ++i)
199 * cout << *i << endl;
202 * for (auto element : container ) // range-for operator
204 * cout << element << endl;
207 template<bool is_const_iterator = false>
208 iterator<is_const_iterator> begin()
210 return iterator<is_const_iterator>(data_structure_.get_begin());
213 template<bool is_const_iterator = false>
214 iterator<is_const_iterator> end()
216 return iterator<is_const_iterator>(data_structure_.get_end());
220 /* Object life-cycle */
222 GenericStorageContainerTemplateImpl<T, DATA_STRUCTURE> () {};
223 GenericStorageContainerTemplateImpl<T, DATA_STRUCTURE> (const GenericStorageContainerTemplateImpl<T, DATA_STRUCTURE>& copy)
225 // TODO: implement copy constructor
228 ~GenericStorageContainerTemplateImpl<T, DATA_STRUCTURE>()
235 // storage allocated (in units of stored type)
236 size_t get_capacity()
238 return data_structure_.get_capacity();
241 // storage used (in units of stored type)
244 return data_structure_.get_size();
252 return data_structure_.append(data);
258 return data_structure_.remove_at(DS_BASE_CLASS::HEAD, DS_BASE_CLASS::NO_ERASE);
261 }; // end of GenericStorageContainerTemplateImpl
263 // GSCTI: handy alias for unweildy type name
264 template<typename T, template<class> class DS = DataStructure_ArrayDynamic> using GSCTI = GenericStorageContainerTemplateImpl< T, DS>;
266 }; // end of namespace