[beast: 15/20] BSE: add and use DataListContainer from Rapicorn



commit 91f03191160873b4a5d9e2f75f05be921fd20881
Author: Tim Janik <timj gnu org>
Date:   Sun Sep 17 14:39:04 2017 +0200

    BSE: add and use DataListContainer from Rapicorn
    
    Import is based on Rapicorn commit id:
        bf228016cba3f6d252ee2cc38e1ed32607f37bf0
    
    Signed-off-by: Tim Janik <timj gnu org>

 bse/bseobject.hh |    3 +-
 sfi/Makefile.am  |    2 +
 sfi/bcore.hh     |    2 -
 sfi/datalist.cc  |   67 +++++++++++++++++++++++++
 sfi/datalist.hh  |  145 ++++++++++++++++++++++++++++++++++++++++++++++++++++++
 5 files changed, 216 insertions(+), 3 deletions(-)
---
diff --git a/bse/bseobject.hh b/bse/bseobject.hh
index 3bf1035..c6b2e27 100644
--- a/bse/bseobject.hh
+++ b/bse/bseobject.hh
@@ -2,7 +2,8 @@
 #ifndef __BSE_OBJECT_H__
 #define __BSE_OBJECT_H__
 
-#include       <bse/bseparam.hh>
+#include <bse/bseparam.hh>
+#include <sfi/datalist.hh>
 
 namespace Bse {
 
diff --git a/sfi/Makefile.am b/sfi/Makefile.am
index 1b86be0..28a172c 100644
--- a/sfi/Makefile.am
+++ b/sfi/Makefile.am
@@ -17,6 +17,7 @@ sfi_public_headers = $(strip \
        sficxx.hh       sfiring.hh      sfimemory.hh    sficomport.hh   \
                        sfi.hh                                          \
        gbsearcharray.hh \
+       datalist.hh             \
        entropy.hh              \
        randomhash.hh           \
        testing.hh      \
@@ -30,6 +31,7 @@ sfi_all_sources = $(strip \
        sfitime.cc      sfitypes.cc     sfivalues.cc    \
        sfivisitors.cc  sfiustore.cc    \
                        sfiring.cc      sfimemory.cc    sficomport.cc   \
+       datalist.cc             \
        entropy.cc              \
        randomhash.cc           \
        testing.cc      \
diff --git a/sfi/bcore.hh b/sfi/bcore.hh
index f15c5ed..63e2113 100644
--- a/sfi/bcore.hh
+++ b/sfi/bcore.hh
@@ -28,8 +28,6 @@ typedef vector<String> StringVector;    ///< Convenience alias for a std::vector
 using   Aida::Any;
 using   Aida::EventFd;
 using   Rapicorn::url_show;
-using   Rapicorn::DataKey;
-using   Rapicorn::DataListContainer;
 using   Rapicorn::void_t;
 using   Rapicorn::Blob;
 using   Rapicorn::Res;
diff --git a/sfi/datalist.cc b/sfi/datalist.cc
new file mode 100644
index 0000000..9e03959
--- /dev/null
+++ b/sfi/datalist.cc
@@ -0,0 +1,67 @@
+// This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
+#include "datalist.hh"
+
+namespace Bse {
+
+// == DataList ==
+DataList::NodeBase::~NodeBase ()
+{}
+
+void
+DataList::set_data (NodeBase *node)
+{
+  /* delete old node */
+  NodeBase *it = rip_data (node->key);
+  if (it)
+    delete it;
+  /* prepend node */
+  node->next = nodes;
+  nodes = node;
+}
+
+DataList::NodeBase*
+DataList::get_data (DataKey<void> *key) const
+{
+  NodeBase *it;
+  for (it = nodes; it; it = it->next)
+    if (it->key == key)
+      return it;
+  return NULL;
+}
+
+DataList::NodeBase*
+DataList::rip_data (DataKey<void> *key)
+{
+  NodeBase *last = NULL, *it;
+  for (it = nodes; it; last = it, it = last->next)
+    if (it->key == key)
+      {
+        /* unlink existing node */
+        if (last)
+          last->next = it->next;
+        else
+          nodes = it->next;
+        it->next = NULL;
+        return it;
+      }
+  return NULL;
+}
+
+void
+DataList::clear_like_destructor()
+{
+  while (nodes)
+    {
+      NodeBase *it = nodes;
+      nodes = it->next;
+      it->next = NULL;
+      delete it;
+    }
+}
+
+DataList::~DataList()
+{
+  clear_like_destructor();
+}
+
+} // Bse
diff --git a/sfi/datalist.hh b/sfi/datalist.hh
new file mode 100644
index 0000000..0c13f52
--- /dev/null
+++ b/sfi/datalist.hh
@@ -0,0 +1,145 @@
+// This Source Code Form is licensed MPL-2.0: http://mozilla.org/MPL/2.0
+#ifndef __BSE_DATALIST_HH__
+#define __BSE_DATALIST_HH__
+
+#include <sfi/bcore.hh>
+
+namespace Bse {
+
+// == DataList ==
+/// DataKey objects are used to identify and manage custom data members of DataListContainer objects.
+template<typename Type> class DataKey {
+private:
+  /*Copy*/        DataKey    (const DataKey&);
+  DataKey&        operator=  (const DataKey&);
+public:
+  /* explicit */  DataKey    ()                 { }
+  virtual Type    fallback   ()                 { Type d = Type(); return d; }  ///< Return the default 
value for Type.
+  virtual void    destroy    (Type data)        { /* destruction hook */ }      ///< Hook invoked when @a 
data is deleted.
+  virtual        ~DataKey    ()                 {}
+};
+
+/// Underlying storage implementation for a DataListContainer.
+class DataList {
+  class NodeBase {
+  protected:
+    NodeBase      *next;
+    DataKey<void> *key;
+    explicit       NodeBase (DataKey<void> *k) : next (NULL), key (k) {}
+    virtual       ~NodeBase ();
+    friend         class DataList;
+  };
+  template<typename T>
+  class Node : public NodeBase {
+    T data;
+  public:
+    T        get_data ()     { return data; }
+    T        swap     (T d)  { T result = data; data = d; return result; }
+    virtual ~Node()
+    {
+      if (key)
+        {
+          DataKey<T> *dkey = reinterpret_cast<DataKey<T>*> (key);
+          dkey->destroy (data);
+        }
+    }
+    explicit Node (DataKey<T> *k,
+                   T           d) :
+      NodeBase (reinterpret_cast<DataKey<void>*> (k)),
+      data (d)
+    {}
+  };
+  NodeBase *nodes;
+  BSE_CLASS_NON_COPYABLE (DataList);
+public:
+  DataList() :
+    nodes (NULL)
+  {}
+  template<typename T> void
+  set (DataKey<T> *key,
+       T           data)
+  {
+    Node<T> *node = new Node<T> (key, data);
+    set_data (node);
+  }
+  template<typename T> T
+  get (DataKey<T> *key) const
+  {
+    NodeBase *nb = get_data (reinterpret_cast<DataKey<void>*> (key));
+    if (nb)
+      {
+        Node<T> *node = reinterpret_cast<Node<T>*> (nb);
+        return node->get_data();
+      }
+    else
+      return key->fallback();
+  }
+  template<typename T> T
+  swap (DataKey<T> *key,
+        T           data)
+  {
+    NodeBase *nb = get_data (reinterpret_cast<DataKey<void>*> (key));
+    if (nb)
+      {
+        Node<T> *node = reinterpret_cast<Node<T>*> (nb);
+        return node->swap (data);
+      }
+    else
+      {
+        set (key, data);
+        return key->fallback();
+      }
+  }
+  template<typename T> T
+  swap (DataKey<T> *key)
+  {
+    NodeBase *nb = rip_data (reinterpret_cast<DataKey<void>*> (key));
+    if (nb)
+      {
+        Node<T> *node = reinterpret_cast<Node<T>*> (nb);
+        T d = node->get_data();
+        nb->key = NULL; // rip key to prevent data destruction
+        delete nb;
+        return d;
+      }
+    else
+      return key->fallback();
+  }
+  template<typename T> void
+  del (DataKey<T> *key)
+  {
+    NodeBase *nb = rip_data (reinterpret_cast<DataKey<void>*> (key));
+    if (nb)
+      delete nb;
+  }
+  void clear_like_destructor();
+  ~DataList();
+private:
+  void      set_data (NodeBase      *node);
+  NodeBase* get_data (DataKey<void> *key) const;
+  NodeBase* rip_data (DataKey<void> *key);
+};
+
+/** DataListContainer - typesafe storage and retrieval of arbitrary members.
+ * By using a DataKey, DataListContainer objects allow storage and retrieval of custom data members in a 
typesafe fashion.
+ * The custom data members will initially default to DataKey::fallback and are deleted by the 
DataListContainer destructor.
+ * Example: @snippet tests/t201/rcore-basics-datalist.cc DataListContainer-EXAMPLE
+ */
+class DataListContainer {
+  DataList data_list;
+public: /// @name Accessing custom data members
+  /// Assign @a data to the custom keyed data member, deletes any previously set data.
+  template<typename Type> inline void set_data    (DataKey<Type> *key, Type data) { data_list.set (key, 
data); }
+  /// Retrieve contents of the custom keyed data member, returns DataKey::fallback if nothing was set.
+  template<typename Type> inline Type get_data    (DataKey<Type> *key) const      { return data_list.get 
(key); }
+  /// Swap @a data with the current contents of the custom keyed data member, returns the current contents.
+  template<typename Type> inline Type swap_data   (DataKey<Type> *key, Type data) { return data_list.swap 
(key, data); }
+  /// Removes and returns the current contents of the custom keyed data member without deleting it.
+  template<typename Type> inline Type swap_data   (DataKey<Type> *key)            { return data_list.swap 
(key); }
+  /// Delete the current contents of the custom keyed data member, invokes DataKey::destroy.
+  template<typename Type> inline void delete_data (DataKey<Type> *key)            { data_list.del (key); }
+};
+
+} // Bse
+
+#endif // __BSE_DATALIST_HH__


[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]