2 * Implementation of Data Structures for GenericStorageContainerTemplateImpl
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 _DATASTRUCTURE_HPP_
21 #define _DATASTRUCTURE_HPP_
24 #include <new> // for std::nothrow
29 /* Abstract base class for the different data structures
31 * Defines the API they must implement. The API allows the Container and its
32 * Iterator to call common methods to perform store, retrieve, and search operations
36 class AbstractDataStructure
38 typedef AbstractDataStructure<D> self_type;
42 // shared pointer wraps actual data so that iterator instances can safely reference the same data
43 std::shared_ptr<D> data_;
44 size_t capacity_; // storage allocated (in units of data type)
45 size_t size_; // storage used (in units of data type)
46 size_t current_; // index of active element (may not make sense for some data structures but is needed for API)
50 /* use descriptive symbols rather than booleans for method parameters */
52 // alternatives to numeric 'index' values
60 // element erasure choices that evaluate to boolean states
66 AbstractDataStructure(size_t capacity = 0) :
67 // use a lambda as the shared_ptr array deleter since the default deleter does not handle array deletion
68 data_(new D[capacity_], []( D* p) {delete[] p; } ),
74 data_.reset(new(std::nothrow) D[capacity_]);
77 virtual ~AbstractDataStructure() {};
80 /* API available to caller
82 * Some methods are pure virtual making this an Abstract (base) class
83 * Sub-classes must implement these methods and over-ride others to
84 * provide the specific storage class functionality
87 virtual size_t get_capacity() // storage allocated (in units of data type)
92 virtual size_t get_size() // storage used (in units of data type)
97 /* the concepts of first, last, next and previous may not have a useful meaning in
98 * some data structures e.g: 'previous' in a 1-way linked list (only has 'next').
100 virtual D* get_data()
102 return (data_.get() && size_ > 0) ? &data_.get()[current_] : nullptr;
105 virtual self_type* get_begin() = 0;
106 virtual self_type* get_end() = 0;
107 virtual self_type* get_next() = 0;
108 virtual self_type* get_previous() = 0;
111 * @param data the item (of type S) to be stored
112 * @param index position to insert; 0 is 'beginning', -1 is 'end'
114 * Depending on the data structure, values of index other than 0 or -1 may have no meaning and be ignored
116 virtual bool insert_at(D& data, long index = HEAD) = 0;
118 virtual bool insert(D& data)
120 return this->insert_at(data, TAIL);
122 virtual bool append(D& data)
124 return this->insert_at(data);
127 /* the remove operation can perform an optional erasure (delete) of the stored data.
129 * returns true if the operation succeeded
132 // 'data' element at 'index' must satisfy equality
133 virtual bool remove_at(D& data, long index = HEAD, bool erase = NO_ERASE) = 0; // element matching 'data' at 'index'
134 virtual bool remove_at(long index = HEAD, bool erase = NO_ERASE) = 0; // any element at 'index'
135 virtual bool remove_all(D& data, bool erase = NO_ERASE) = 0; // all elements matching 'data'
137 /* the replace operation can perform an optional erasure (delete) of the current data element
139 virtual bool replace_at(D& data_in, D& data_out, long index = HEAD, bool erase = NO_ERASE) = 0; // element matching 'data_out' at 'index'
140 virtual bool replace_at(D& data_in, long index = HEAD, bool erase = NO_ERASE) = 0; // any element at 'index'
141 virtual bool replace_all(D& data_in, D& data_out, bool erase = NO_ERASE) = 0; // all elements matching 'data_out'
144 /* Search for an element matching 'needle'. The stored type must have defined
145 * operator<() and operator==() to allow the container to compare 'needle' with each stored element.
147 * If find() is called with last_found == nullptr it searches from the start of the container. If
148 * last_found points to an element in the container the search continues from that element. The
149 * implementation must guard against last_found not pointing to a valid object, or that object not
150 * belonging to the container.
152 * returns a nullptr if there are no (more) matches
154 virtual D* find(D& needle, D* last_found = nullptr) = 0;
156 // comparison methods
157 virtual bool operator==(const self_type& right_hand_side)
160 if (this->data_.get() && right_hand_side.data_.get())
161 result = this->current_ == right_hand_side.current_;
165 virtual bool operator!=(const self_type& right_hand_side)
167 return !this->operator==(right_hand_side);
169 virtual bool operator< (const self_type& right_hand_side)
172 if (this->data_.get() && right_hand_side.data_.get())
173 result = this->current_ < right_hand_side.current_;
177 virtual bool operator<=(const self_type& right_hand_side)
179 return this->operator==(right_hand_side) | this->operator<(right_hand_side);
185 /* Specialised data structure implementing a Dynamic Array
187 template <typename AD>
188 class DataStructure_ArrayDynamic : public AbstractDataStructure<AD>
190 typedef DataStructure_ArrayDynamic<AD> self_type;
191 typedef AbstractDataStructure<AD> BASE_CLASS; // alias for easier reading of enums
196 DataStructure_ArrayDynamic<AD>(size_t capacity = 512) : AbstractDataStructure<AD>(capacity), growth_(512) {};
198 /* Copy constructor that can do deep and shallow copies.
199 * Shallow copies are efficient for use by iterators where the only unique variable is
200 * the 'current_' index - the object can share a pointer to the data.
202 DataStructure_ArrayDynamic<AD>(const self_type& copy, bool shallow = false)
204 this->data_ = copy.data_;
205 this->capacity_ = copy.capacity_;
206 this->size_ = copy.size_;
207 this->current_ = copy.current_;
208 this->growth_ = copy.growth_;
211 this->data_.reset(new AD [this->capacity_]);
212 for (size_t i = 0; i < this->capacity_; ++i)
213 this->data_.get()[i] = copy.data_.get()[i];
217 virtual self_type* get_begin()
219 self_type* result = nullptr;
221 if (this->size_ > 0) {
222 // TODO: make a shallow copy (share the array to avoid an expensive copy)
223 result = new self_type(*this, true);
224 result->current_ = 0;
229 virtual self_type* get_end()
231 self_type* result = nullptr;
235 result = new self_type(*this, true);
236 // 1 beyond last element; used by iterator loops to detect when to break
237 result->current_ = result->size_;
242 virtual self_type* get_next()
244 self_type* result = nullptr;
248 /* if (this->current_ + 1 < this->size_)
250 result = new self_type(*this, true);
258 virtual self_type* get_previous()
260 self_type* result = nullptr;
264 if (this->current_ - 1 >= 0)
266 result = new self_type(*this, true);
274 virtual bool insert_at(AD& data, long index = BASE_CLASS::HEAD)
278 if (this->data_ != nullptr)
280 if (index == BASE_CLASS::TAIL)
282 else if (index == BASE_CLASS::HEAD)
285 if (this->capacity_ <= index)
288 if (this->capacity_ > index)
290 this->data_.get()[index] = data;
292 if (index >= this->size_)
293 this->size_ = index + 1;
302 virtual bool remove_at(AD& data, long index = BASE_CLASS::TAIL, bool erase = BASE_CLASS::NO_ERASE)
309 virtual bool remove_at(long index = BASE_CLASS::TAIL, bool erase = BASE_CLASS::NO_ERASE)
316 virtual bool remove_all(AD& data, bool eraser = BASE_CLASS::NO_ERASE)
323 virtual bool replace_at(AD& data_in, AD& data_out, long index = BASE_CLASS::TAIL, bool erase = BASE_CLASS::NO_ERASE)
330 virtual bool replace_at(AD& data_in, long index = BASE_CLASS::TAIL, bool erase = BASE_CLASS::NO_ERASE)
337 virtual bool replace_all(AD& data_in, AD& data_out, bool erase = BASE_CLASS::NO_ERASE)
344 virtual AD* find(AD& needle, AD* last_found = nullptr)
346 AD* result = nullptr;
351 // comparisons require both sides to have the same array pointer
352 virtual bool operator==(const self_type& right_hand_side)
356 if (this->data_.get() == right_hand_side.data_.get())
357 result = this->current_ == right_hand_side.current_;
362 virtual bool operator<(const self_type& right_hand_side)
366 if (this->data_.get() == right_hand_side.data_.get())
367 result = this->current_ < right_hand_side.current_;
375 AD* temp = new (std::nothrow) AD[this->capacity_ + this->growth_];
378 for (size_t index = 0; index < this->size_; ++index)
379 temp[index] = this->data_.get()[index];
381 this->data_.reset(temp);
383 this->capacity_ += this->growth_;
393 /* Specialised data structure implementing a 1-way Linked List
395 template <typename LLS>
396 class DataStructure_LinkedListSingle : protected AbstractDataStructure<LLS>
401 /* Specialised data structure implementing a 2-way Linked List
403 template <typename LLD>
404 class DataStructure_LinkedListDouble : public DataStructure_LinkedListSingle<LLD>
409 /* Specialised data structure implementing a Binary Search Tree
411 template <typename BST>
412 class DataStructure_BinarySearchTree : protected AbstractDataStructure<BST>
417 }; // end of namespace