ArrayDynamic: Partial implementation
[GenericStorageContainerTemplate.git] / GenericStorageContainerTemplateImpl.hpp
1 /*
2  * Implementation of a Generic Data Structure Container Template including STL Iterator
3  * Copyright (c) 2014 TJ <hacker@iam.tj>
4  *
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.
8  *
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.
13  *
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/>.
16  *
17  * see ./COPYRIGHT or http://www.gnu.org/licenses/gpl-3.0.html
18  */
19
20 #ifndef _GENERICSTORAGECONTAINERTEMPLATEIMPL_HPP_
21 #define _GENERICSTORAGECONTAINERTEMPLATEIMPL_HPP_
22
23 #include "DataStructures.hpp"
24 #include <iterator>
25 #include <memory>
26
27 namespace tj
28 {
29  
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.
34    *
35    * Default data structure is a Dynamic Array
36    *
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.
40    *
41    */
42   template <typename T, template<typename> class DATA_STRUCTURE = DataStructure_ArrayDynamic>
43   class GenericStorageContainerTemplateImpl
44   {
45     // attributes
46     
47     // data structure type is templated
48     DATA_STRUCTURE<T> data_structure_;
49
50
51     public:
52
53     /* constant and non-constant custom Standard Template Library (STL) compatible iterators
54      * avoiding writing 2 separate class definitions that only differ on their
55      * constant vs non-constant type specifiers. This makes extensive use of
56      * template metaprogramming
57      *
58      * defaults to a non-const iterator
59      */
60     template <bool is_const_iterator = false>
61     class iterator : public std::iterator< std::bidirectional_iterator_tag, AbstractDataStructure<T> >
62     {
63       typedef iterator self_type;
64       typedef typename std::conditional< is_const_iterator, const AbstractDataStructure<T>, AbstractDataStructure<T> >::type value_type;
65       typedef typename std::conditional< is_const_iterator, const AbstractDataStructure<T>&, AbstractDataStructure<T>& >::type reference;
66       typedef typename std::conditional< is_const_iterator, const AbstractDataStructure<T>*, AbstractDataStructure<T>* >::type pointer;
67       typedef std::bidirectional_iterator_tag iterator_category;
68       typedef int difference_type;
69
70       DATA_STRUCTURE<T>* element_;
71
72       public:
73
74       iterator<is_const_iterator> () {};
75       iterator<is_const_iterator> (DATA_STRUCTURE<T>* element) : element_(element) {};
76       iterator<is_const_iterator> (const iterator<is_const_iterator>& copy) : element_(copy.element_) {}; // copy constructor
77
78       // ForwardIterator methods
79
80       // postfix increment operator
81       self_type operator++()
82       {
83         self_type original(*this); // need to keep a copy of the current value so it can be returned
84
85         DATA_STRUCTURE<T>* temp = element_->get_next();
86         if (temp)
87           element_ = temp; // the increment changes the item being referenced
88
89         return original;
90       };
91
92       // prefix increment operator
93       self_type operator++(int unused)
94       {
95         if (element_) {
96           DATA_STRUCTURE<T>* temp = element_->get_next();
97           if (temp)
98             element_ = temp;
99         }
100         return *this;
101       };
102
103       // BidirectionalIterator methods
104
105       // postfix decrement
106       self_type operator--()
107       {
108         self_type original(*this); // keep copy that is to be returned
109         this->element_->get_previous();
110         return original;
111       };
112
113       // prefix decrement
114       self_type operator--(int unused)
115       {
116         if (element_)
117           element_ = element_->get_previous();
118
119         return *this;
120       };
121
122       // Comparison methods
123       bool operator==(const self_type& right_hand_side)
124       {
125         bool result = false;
126
127         if (element_ && right_hand_side.element_)
128           result = *element_ == *right_hand_side.element_; 
129
130         return result;
131       };
132
133       bool operator!=(const self_type& right_hand_side)
134       {
135         return !this->operator==(right_hand_side);
136       };
137
138       T operator* ()
139       {
140
141         return element_ ? *element_->get_data() : 0;
142       };
143
144       std::conditional<is_const_iterator, const T*, T*>  operator->()
145       { 
146         return &element_->get_data();
147       };
148
149       // allow const and non-const iterator copy-contructors access to private members 
150       friend class iterator<!is_const_iterator>;
151
152     }; // end of Iterator
153
154     // use these handy short-cuts in application code
155     typedef iterator<true> _const_iterator;
156     typedef iterator<false> _iterator;
157
158     /* methods directly supporting use of the iterator uses 'template' to avoid
159      * writing 4 method definitions (2 for constant and 2 for non-constant iterators)
160      *
161      * begin() and end() are used in code that instantiates the iterator:
162      *
163      * GSCTI<int> container;
164      * container.insert(1);
165      * container.insert(2);
166      *
167      * for (_const_iterator i = container.begin(); i != container.end(); ++i) 
168      * {
169      *   cout << *i << endl;
170      * }
171      *
172      * for (auto element : container ) // range-for operator
173      * { 
174      *   cout << element << endl;
175      * }
176      */
177     template<bool is_const_iterator = false>
178     iterator<is_const_iterator> begin()
179     { 
180       return iterator<is_const_iterator>(data_structure_.get_begin());
181     };
182
183     template<bool is_const_iterator = false>
184     iterator<is_const_iterator> end()
185     { 
186       return iterator<is_const_iterator>(data_structure_.get_end());
187     };
188   
189     // object life-cycle
190     GenericStorageContainerTemplateImpl<T, DATA_STRUCTURE> () {};
191     GenericStorageContainerTemplateImpl<T, DATA_STRUCTURE> (const GenericStorageContainerTemplateImpl<T, DATA_STRUCTURE>& copy)
192     {
193        // TODO: implement copy constructor
194     };
195
196     ~GenericStorageContainerTemplateImpl<T, DATA_STRUCTURE>()
197     {
198       delete &data_structure_;
199     };
200
201     // capacity
202     size_t get_capacity()
203     {
204       return data_structure_.get_capacity();
205     };
206
207     size_t get_size()
208     {
209       return data_structure_.get_size();
210     };
211
212     // modifiers
213
214     // append at tail
215     bool append(T& data)
216     {
217       return data_structure_.append(data);
218     };
219
220     // remove from tail
221     bool remove()
222     {
223       return false;
224     };
225
226   }; // end of GenericStorageContainerTemplateImpl
227
228   // handy short-cuts for unweildy names
229   template<typename T, template<class> class DS = DataStructure_ArrayDynamic> using GSCTI = GenericStorageContainerTemplateImpl< T, DS>;
230
231 }; // end of namespace
232
233 #endif