STL style generic storage type container example
authorTJ <hacker@iam.tj>
Sun, 12 Apr 2015 11:48:06 +0000 (12:48 +0100)
committerTJ <hacker@iam.tj>
Sun, 12 Apr 2015 11:48:06 +0000 (12:48 +0100)
GenericStorageContainerDemo.cpp [new file with mode: 0644]
GenericStorageContainerTemplateImpl.hpp [new file with mode: 0644]
Makefile [new file with mode: 0644]

diff --git a/GenericStorageContainerDemo.cpp b/GenericStorageContainerDemo.cpp
new file mode 100644 (file)
index 0000000..847b238
--- /dev/null
@@ -0,0 +1,12 @@
+#include "GenericStorageContainerTemplateImpl.hpp"
+
+using namespace tj;
+
+int
+main (int argc, char **argv, char **env)
+{
+  GenericStorageContainerTemplateImpl<int, Storage::dynamic_array> my_collection();
+
+  return 0;
+}
+
diff --git a/GenericStorageContainerTemplateImpl.hpp b/GenericStorageContainerTemplateImpl.hpp
new file mode 100644 (file)
index 0000000..2aade09
--- /dev/null
@@ -0,0 +1,250 @@
+/*
+ * Implementation of a Generic Storage Type Container Template including STL Iterator
+ * Copyright (c) 2014 TJ <hacker@iam.tj>
+ *
+ *    This program is free software: you can redistribute it and/or modify
+ *    it under the terms of the GNU General Public License as published by
+ *    the Free Software Foundation, either version 3 of the License.
+ *
+ *    This program is distributed in the hope that it will be useful,
+ *    but WITHOUT ANY WARRANTY; without even the implied warranty of
+ *    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+ *    GNU General Public License for more details.
+ *
+ *   You should have received a copy of the GNU General Public License
+ *   along with this program.  If not, see <http://www.gnu.org/licenses/>.
+ *
+ * see ./COPYRIGHT or http://www.gnu.org/licenses/gpl-3.0.html
+ */
+
+#ifndef _GENERIC_STORAGE_CONTAINER_TEMPLATE_IMPL_HPP_
+#define _GENERIC_STORAGE_CONTAINER_TEMPLATE_IMPL_HPP_
+
+#include <iterator>
+
+namespace tj
+{
+  /* possible options for the storage class the application may request
+   */
+  enum Storage
+  {
+    unknown,
+    static_array,
+    dynamic_array,
+    linked_list_single,
+    linked_list_double,
+    bst,
+    bst_reversible,
+    LENGTH                // allows application to determine how many storage classes are available
+  };
+  
+  /* A generic Container that can use different internal storage
+   * representations (Array, Linked-List, Binary Search Tree) based on an
+   * enum passed by application code at compile time using the power of Templating
+   * and Metaprogramming of C++11 and later.
+   *
+   * Uses Metaprogramming conditionals to create constant and non-constant iterators
+   * from a single iterator definition. Provides typedefs to make instantiating the
+   * correct type of iterator easier to read and write in application code.
+   *
+   */
+  template <typename T, int storage_class>
+  class GenericStorageContainerTemplateImpl
+  {
+
+
+    /* XXX: Have to use different template typename value (T, S, etc.) although the types are
+     * the same else the compiler cannot determine the correct value to use.
+     * Metaprogramming does not have the concept of scope or namespace:
+     *
+     *
+     *   GenericStorageContainerTemplateImpl.hpp:40:15: error: declaration of ‘class T’
+     *   template <typename T>
+     *             ^
+     *   GenericStorageContainerTemplateImpl.hpp:31:13: error:  shadows template parm ‘class T’
+     *   template <typename T, int storage_class>
+     *             ^
+     */
+
+    /* Abstract base class for the different storage classes
+     *
+     * Defines the API they must implement. The API allows the Container and its
+     * Iterator to call common methods to perform store, retrieve, and search operations
+     */
+
+    template <typename S>
+    class StorageClass
+    {
+      S& __data;
+
+      public:
+      StorageClass() {};
+      StorageClass(S& data) : __data(data) {};
+
+      /* API available to application
+       *
+       * Some methods are pure virtual making this an Abstract (base) class
+       * Sub-classes must implement these methods and over-ride others to
+       * provide the specific storage class functionality
+       */
+      S& get_data()
+      {
+        return __data;
+      };
+
+      S& get_first() = 0;
+      S& get_previous() = 0;
+      S& get_next() = 0;
+      S& get_last() = 0;
+
+      /*
+       * @param data the item (of type S) to be stored
+       * @param index position to insert; 0 is 'beginning', -1 is 'end'
+       *
+       * Depending on the concrete implemenation of this method, values of index other
+       * than 0 or -1 may have no meaning and be ignored
+       */
+      virtual bool insert_at(S& data, long index = -1) = 0;
+      virtual bool insert(S& data)
+      {
+        return insert_at(data, 0);
+      };
+      virtual bool append(S& data)
+      {
+        return insert_at(data, -1);
+      };
+
+      virtual bool remove_at(S& data, long index = -1) = 0;
+      virtual bool remove() = 0;
+      virtual bool remove(S& data) = 0;
+      virtual bool erase(S& data) = 0;
+    };
+
+
+    /* Specialised storage class implementing a Dynamic Array
+     */
+    template <typename SAD>
+    class StorageClass_DynamicArray : StorageClass<SAD> 
+    {
+      // TODO: implement
+    };
+
+    /* Specialised storage class implementing a 2-way Linked List
+     */
+    template <typename SLLD>
+    class StorageClass_DoubleLinkedList : StorageClass<SLLD> 
+    {
+      // TODO: implement
+    };
+
+    /* Specialised storage class implementing a Binary Search Tree
+     */
+    template <typename SBST>
+    class StorageClass_BinarySearchTree : StorageClass<SBST> 
+    {
+      // TODO: implement
+    };
+
+
+    // attributes
+    
+    /* storage class type is decided when collection is compiled
+     * so use the (abstract) base class to keep the Collection's private
+     * reference to the internal storage class
+     */
+    StorageClass<T> storage;
+  
+
+    public:
+
+    /* constant and non-constant custom Standard Template Library (STL) iterators
+     * avoiding writing 2 separate class definitions that only differ on their
+     * constant vs non-constant type specifiers. This makes extensive use of
+     * template metaprogramming
+     *
+     * defaults to a non-const iterator
+     */
+    template <bool is_const_iterator = false>
+    class iterator : public std::iterator< std::bidirectional_iterator_tag, StorageClass<T> >
+    /* XXX: Ensure the <iterator> header is included to avoid cryptic errors:
+     *
+     *     GenericStorageContainerTemplateImpl.hpp:168:42: error: expected template-name before ‘<’ token
+     *        class iterator : public std::iterator< std::bidirectional_iterator_tag, StorageClass<T> >
+     *                                             ^
+     *     GenericStorageContainerTemplateImpl.hpp:168:42: error: expected ‘{’ before ‘<’ token
+     *     GenericStorageContainerTemplateImpl.hpp:168:42: error: expected unqualified-id before ‘<’ token
+     */
+
+    {
+      /*
+       * 1. typedef the container's type to the naming convention used by the STL iterators (makes readable code)
+       * 2. Use Metaprogramming's std::conditional to decide whether to declare const or non-const iterator
+       *    which avoids writing 2 iterator classes, keeping the code cleaner and easier to use
+       * 3. declare and implement methods to support forward and reverse iteration (bidirectional)
+       */
+      typedef iterator self_type;
+      typedef typename std::conditional< is_const_iterator, const StorageClass<T>, StorageClass<T> >::type value_type;
+      typedef typename std::conditional< is_const_iterator, const StorageClass<T>&, StorageClass<T>& >::type reference;
+      typedef typename std::conditional< is_const_iterator, const StorageClass<T>*, StorageClass<T>* >::type pointer;
+      typedef std::bidirectional_iterator_tag iterator_category;
+      typedef int difference_type;
+
+      StorageClass<T>& __node;
+
+      public:
+
+      iterator<is_const_iterator> () {}; // default constructor
+      iterator<is_const_iterator> ( StorageClass<T>& node) : __node(node) {};
+      iterator<is_const_iterator> (const iterator<is_const_iterator>& copy) : __node(copy.__node) {}; // copy constructor
+
+      // postfix increment operator
+      self_type operator++()
+      {
+        self_type original = *this; // need to keep a reference to the current value so it can be returned
+        this->__node = this->__node->get_next(); // after the increment changes the item being referenced
+        return original;
+      }
+
+      // prefix increment operator
+      self_type operator++(int unused)
+      {
+        __node = __node->get_next();
+        return *this;
+      }
+
+      bool operator==(const self_type& right_hand_side)
+      {
+        return __node == right_hand_side.__node; 
+      }
+
+      bool operator!=(const self_type& right_hand_side)
+      {
+        return __node != right_hand_side.__node;
+      }
+
+      T operator* ()
+      {
+        return __node->get_data();
+      }
+
+      std::conditional<is_const_iterator, const T*, T*>  operator->()
+      { 
+        return &__node->get_data();
+      }
+
+      // allow const and non-const iterator copy-contructors access to private members 
+      friend class iterator<!is_const_iterator>;
+
+    }; // end of Iterator
+
+    /* use these handy short-cuts in application code
+     */
+    typedef iterator<true> _const_iterator;
+    typedef iterator<false> _iterator;
+
+  }; // end of GenericStorageContainerTemplateImpl
+
+}; // end of namespace
+
+#endif
diff --git a/Makefile b/Makefile
new file mode 100644 (file)
index 0000000..f690e6e
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,10 @@
+BIN=GenericStorageContainerDemo
+# must use C++ 2011 standard
+CXX_FLAGS += -Wall --std=c++11 -g
+
+all:
+       $(CXX) $(CXX_FLAGS) -o $(BIN) $(BIN).cpp
+
+clean:
+       rm $(BIN)
+