refactor: move StorageClass to separate translation unit
[GenericStorageContainerTemplate.git] / GenericStorageContainerTemplateImpl.hpp
1 /*
2  * Implementation of a Generic Storage Type 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 _GENERIC_STORAGE_CONTAINER_TEMPLATE_IMPL_HPP_
21 #define _GENERIC_STORAGE_CONTAINER_TEMPLATE_IMPL_HPP_
22
23 #include <iterator>
24 #include <memory>
25
26 namespace tj
27 {
28  
29  /* A generic Container that can use different internal storage
30    * representations (Array, Linked-List, Binary Search Tree) based on an
31    * enum passed by application code at compile time using the power of Templating
32    * and Metaprogramming of C++11 and later.
33    *
34    * Uses Metaprogramming conditionals to create constant and non-constant iterators
35    * from a single iterator definition. Provides typedefs to make instantiating the
36    * correct type of iterator easier to read and write in application code.
37    *
38    */
39   template <typename T, template<typename> class STORAGE_CLASS = StorageClass_DynamicArray>
40   class GenericStorageContainerTemplateImpl
41   {
42     /* XXX: Have to use different template typename value (T, S, etc.) although the types are
43      * the same else the compiler cannot determine the correct value to use.
44      * Metaprogramming does not have the concept of scope or namespace:
45      *
46      *
47      *   GenericStorageContainerTemplateImpl.hpp:40:15: error: declaration of ‘class T’
48      *   template <typename T>
49      *             ^
50      *   GenericStorageContainerTemplateImpl.hpp:31:13: error:  shadows template parm ‘class T’
51      *   template <typename T, int storage_class>
52      *             ^
53      */
54
55     // attributes
56     
57     // storage class type is templated
58     STORAGE_CLASS<T> storage_;
59
60
61     public:
62
63     GenericStorageContainerTemplateImpl() {};
64     GenericStorageContainerTemplateImpl(const GenericStorageContainerTemplateImpl<T, STORAGE_CLASS>& copy)
65     {
66
67     };
68     ~GenericStorageContainerTemplateImpl()
69     {
70       delete storage_;
71     };
72
73     /* constant and non-constant custom Standard Template Library (STL) iterators
74      * avoiding writing 2 separate class definitions that only differ on their
75      * constant vs non-constant type specifiers. This makes extensive use of
76      * template metaprogramming
77      *
78      * defaults to a non-const iterator
79      */
80     template <bool is_const_iterator = false>
81     class iterator : public std::iterator< std::bidirectional_iterator_tag, StorageClass<T> >
82     {
83       /* XXX: Ensure the <iterator> header is included to avoid cryptic errors:
84        *
85        *     GenericStorageContainerTemplateImpl.hpp:168:42: error: expected template-name before ‘<’ token
86        *        class iterator : public std::iterator< std::bidirectional_iterator_tag, StorageClass<T> >
87        *                                             ^
88        *     GenericStorageContainerTemplateImpl.hpp:168:42: error: expected ‘{’ before ‘<’ token
89        *     GenericStorageContainerTemplateImpl.hpp:168:42: error: expected unqualified-id before ‘<’ token
90        */
91
92       /*
93        * 1. typedef the container's type to the naming convention used by the STL iterators (makes readable code)
94        * 2. Use Metaprogramming's std::conditional to decide whether to declare const or non-const iterator
95        *    which avoids writing 2 iterator classes, keeping the code cleaner and easier to use
96        * 3. declare and implement methods to support forward and reverse iteration (bidirectional)
97        */
98       typedef iterator self_type;
99       typedef typename std::conditional< is_const_iterator, const StorageClass<T>, StorageClass<T> >::type value_type;
100       typedef typename std::conditional< is_const_iterator, const StorageClass<T>&, StorageClass<T>& >::type reference;
101       typedef typename std::conditional< is_const_iterator, const StorageClass<T>*, StorageClass<T>* >::type pointer;
102       typedef std::bidirectional_iterator_tag iterator_category;
103       typedef int difference_type;
104
105       StorageClass<T>& __node;
106
107       public:
108
109       iterator<is_const_iterator> () {}; // default constructor
110       iterator<is_const_iterator> ( StorageClass<T>& node) : __node(node) {};
111       iterator<is_const_iterator> (const iterator<is_const_iterator>& copy) : __node(copy.__node) {}; // copy constructor
112
113       // ForwardIterator methods
114
115       // postfix increment operator
116       self_type operator++()
117       {
118         self_type original = *this; // need to keep a reference to the current value so it can be returned
119         this->__node = this->__node->get_next(); // after the increment changes the item being referenced
120         return original;
121       }
122
123       // prefix increment operator
124       self_type operator++(int unused)
125       {
126         __node = __node.get_next();
127         return *this;
128       }
129
130       // BidirectionalIterator methods
131
132       // postfix decrement
133       self_type operator--()
134       {
135         self_type original = *this; // keep reference to value that is to be returned
136         this->__node.get_previous();
137         return original;
138       };
139
140       // prefix decrement
141       self_type operator--(int unused)
142       {
143         __node = __node->get_previous();
144         return *this;
145       };
146
147       // Comparison methods
148       bool operator==(const self_type& right_hand_side)
149       {
150         return __node == right_hand_side.__node; 
151       }
152
153       bool operator!=(const self_type& right_hand_side)
154       {
155         return __node != right_hand_side.__node;
156       }
157
158       T operator* ()
159       {
160         return __node->get_data();
161       }
162
163       std::conditional<is_const_iterator, const T*, T*>  operator->()
164       { 
165         return &__node->get_data();
166       }
167
168       // allow const and non-const iterator copy-contructors access to private members 
169       friend class iterator<!is_const_iterator>;
170
171     }; // end of Iterator
172
173   // use these handy short-cuts in application code
174   typedef iterator<true> _const_iterator;
175   typedef iterator<false> _iterator;
176
177   }; // end of GenericStorageContainerTemplateImpl
178
179   // handy short-cuts for unweildy names
180   template<typename T, template<class> class SC = StorageClass_DynamicArray> using GSCTI = GenericStorageContainerTemplateImpl< T, SC>;
181
182 }; // end of namespace
183
184 #endif