[coco] Introduce PtrSlot (#969)
author박종현/동작제어Lab(SR)/Staff Engineer/삼성전자 <jh1302.park@samsung.com>
Tue, 14 Aug 2018 07:43:01 +0000 (16:43 +0900)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Tue, 14 Aug 2018 07:43:01 +0000 (16:43 +0900)
This commit introduces PtrSlot which allows us to insert a hook on
pointer updates.

Signed-off-by: Jonghyun Park <jh1302.park@samsung.com>
contrib/coco/core/include/coco/ADT/PtrSlot.h [new file with mode: 0644]
contrib/coco/core/src/ADT/PtrSlot.test.cpp [new file with mode: 0644]

diff --git a/contrib/coco/core/include/coco/ADT/PtrSlot.h b/contrib/coco/core/include/coco/ADT/PtrSlot.h
new file mode 100644 (file)
index 0000000..8797196
--- /dev/null
@@ -0,0 +1,86 @@
+#ifndef __COCO_ADT_PTR_SLOT_H__
+#define __COCO_ADT_PTR_SLOT_H__
+
+#include <vector>
+#include <memory>
+
+#include <functional>
+#include <cassert>
+
+namespace coco
+{
+
+template <typename T> class PtrSlot
+{
+public:
+  struct Hook
+  {
+    virtual ~Hook() = default;
+
+    virtual void onTake(T *value) = 0;
+    virtual void onRelease(T *value) = 0;
+  };
+
+public:
+  PtrSlot() : _value{nullptr}
+  {
+    // DO NOTHING
+  }
+
+public:
+  virtual ~PtrSlot() { value(nullptr); }
+
+public:
+  T *value(void) const { return _value; }
+
+public:
+  void value(T *value)
+  {
+    if (_value)
+    {
+      notifyRelease(_value);
+      _value = nullptr;
+    }
+
+    assert(_value == nullptr);
+
+    if (value)
+    {
+      _value = value;
+      notifyTake(_value);
+    }
+
+    assert(_value == value);
+  }
+
+protected:
+  void insert(std::unique_ptr<Hook> &&hook) { _hooks.emplace_back(std::move(hook)); }
+
+private:
+  void notifyTake(T *value) const
+  {
+    for (const auto &hook : _hooks)
+    {
+      hook->onTake(value);
+    }
+  }
+
+private:
+  void notifyRelease(T *value) const
+  {
+    for (const auto &hook : _hooks)
+    {
+      hook->onRelease(value);
+    }
+  }
+
+private:
+  T *_value;
+
+private:
+  std::vector<std::unique_ptr<Hook>> _hooks;
+};
+
+} // namespace coco
+
+#endif // __COCO_ADT_PTR_SLOT_H__
diff --git a/contrib/coco/core/src/ADT/PtrSlot.test.cpp b/contrib/coco/core/src/ADT/PtrSlot.test.cpp
new file mode 100644 (file)
index 0000000..42f02ef
--- /dev/null
@@ -0,0 +1,65 @@
+#include "coco/ADT/PtrSlot.h"
+
+#include <nncc/foundation/Memory.h>
+
+#include <gtest/gtest.h>
+
+namespace
+{
+struct Entity
+{
+  Entity() = default;
+};
+
+struct EntitySlot final : public coco::PtrSlot<Entity>
+{
+private:
+  class Hook final : public coco::PtrSlot<Entity>::Hook
+  {
+  public:
+    Hook(std::set<Entity *> *bounded) : _bounded{bounded}
+    {
+      // DO NOTING
+    }
+
+  public:
+    void onTake(Entity *node) { _bounded->insert(node); }
+    void onRelease(Entity *node) { _bounded->erase(node); }
+
+  private:
+    std::set<Entity *> *_bounded;
+  };
+
+public:
+  EntitySlot(std::set<Entity *> *bounded) { insert(nncc::foundation::make_unique<Hook>(bounded)); }
+};
+} // namespace
+
+TEST(ADT_PTR_SLOT, usecase)
+{
+  std::set<Entity *> bounded;
+
+  EntitySlot slot{&bounded};
+
+  ASSERT_EQ(slot.value(), nullptr);
+
+  Entity e_0;
+  Entity e_1;
+
+  slot.value(&e_0);
+
+  ASSERT_EQ(slot.value(), &e_0);
+  ASSERT_EQ(bounded.size(), 1);
+  ASSERT_EQ(bounded.count(&e_0), 1);
+
+  slot.value(&e_1);
+
+  ASSERT_EQ(slot.value(), &e_1);
+  ASSERT_EQ(bounded.size(), 1);
+  ASSERT_EQ(bounded.count(&e_1), 1);
+
+  slot.value(nullptr);
+
+  ASSERT_EQ(slot.value(), nullptr);
+  ASSERT_EQ(bounded.size(), 0);
+}