[coco] Introduce object casting helpers (#2673)
author박종현/동작제어Lab(SR)/Staff Engineer/삼성전자 <jh1302.park@samsung.com>
Fri, 14 Dec 2018 05:41:47 +0000 (14:41 +0900)
committerGitHub Enterprise <noreply-CODE@samsung.com>
Fri, 14 Dec 2018 05:41:47 +0000 (14:41 +0900)
This commit introduces the following object casting helpers:
 - isa<T>
 - cast<T>
 - safe_cast<T>

Signed-off-by: Jonghyun Park <jh1302.park@samsung.com>
contrib/coco/core/include/coco/IR/Object.h
contrib/coco/core/src/IR/FeatureObject.test.cpp
contrib/coco/core/src/IR/KernelObject.test.cpp
contrib/coco/core/src/IR/Object.cpp
contrib/coco/core/src/IR/Object.test.cpp

index 3fa6f12..29a0535 100644 (file)
@@ -101,6 +101,36 @@ private:
   UseSet _uses;
 };
 
+/**
+ * @brief Check whether a given object is of type T
+ *
+ * The example below shows how to use this "isa<T>" helper:
+ *   auto obj = new FeatureObject{};
+ *
+ *   if (isa<FeatureObject>())
+ *   {
+ *     std::cout << "FeatureObject" << std::endl;
+ *   }
+ */
+template <typename T> bool isa(const Object *);
+
+/**
+ * @brief Cast a generic object as a specific one
+ *
+ * "cast<T>(o)" accepts only a valid object pointer "o" that "isa<T>(o)" holds
+ * - Then, "cast<T>(o)" always returns a valid object pointer.
+ */
+template <typename T> T *cast(Object *);
+
+/**
+ * @brief Cast a generic object as a specific one
+ *
+ * Unlike "cast<T>", "safe_cast<T>" accepts any object pointer
+ * - "safe_cast<T>(nullptr)" returns "nullptr"
+ * - "safe_cast<T>(o)" returns "nullptr" if "isa<T>(o)" does not hold
+ */
+template <typename T> T *safe_cast(Object *);
+
 // @brief Return the producer of a given object if it exists
 Object::Producer *producer(const Object *);
 
index 7cd875a..f647626 100644 (file)
@@ -32,6 +32,13 @@ namespace
 class FeatureObjectTest : public ::testing::Test
 {
 protected:
+  coco::FeatureObject *allocate()
+  {
+    auto o = new coco::FeatureObject{};
+    _allocated.emplace_back(o);
+    return o;
+  }
+
   // TODO Deprecate this method
   coco::FeatureObject *allocate(const coco::FeatureShape &shape)
   {
@@ -107,3 +114,12 @@ TEST_F(FeatureObjectTest, asFeature)
   ASSERT_NE(mutable_object->asFeature(), nullptr);
   ASSERT_EQ(mutable_object->asFeature(), immutable_object->asFeature());
 }
+
+TEST_F(FeatureObjectTest, casting_helpers)
+{
+  auto obj = allocate();
+
+  ASSERT_TRUE(coco::isa<coco::FeatureObject>(obj));
+  ASSERT_EQ(coco::cast<coco::FeatureObject>(obj), obj);
+  ASSERT_EQ(coco::safe_cast<coco::FeatureObject>(obj), obj);
+}
index f0dff27..64f4d54 100644 (file)
@@ -31,6 +31,13 @@ namespace
 class KernelObjectTest : public ::testing::Test
 {
 protected:
+  coco::KernelObject *allocate()
+  {
+    auto o = new coco::KernelObject{};
+    _allocated.emplace_back(o);
+    return o;
+  }
+
   coco::KernelObject *allocate(const kernel::Shape &shape)
   {
     auto o = new coco::KernelObject{shape};
@@ -69,6 +76,15 @@ TEST_F(KernelObjectTest, asKernel)
   ASSERT_EQ(mutable_object->asKernel(), immutable_object->asKernel());
 }
 
+TEST_F(KernelObjectTest, casting_helpers)
+{
+  auto obj = allocate();
+
+  ASSERT_TRUE(coco::isa<coco::KernelObject>(obj));
+  ASSERT_EQ(coco::cast<coco::KernelObject>(obj), obj);
+  ASSERT_EQ(coco::safe_cast<coco::KernelObject>(obj), obj);
+}
+
 // TODO Rewrite this test as a test for GenericKernelLayout
 #if 0
 TEST_F(KernelObjectTest, at)
index 08ae90c..6a51a61 100644 (file)
@@ -76,4 +76,41 @@ Object::ConsumerSet consumers(const Object *obj)
 
   return res;
 }
+
+/**
+ * Casting Helpers
+ *
+ * TODO Use Macro to reduce code duplication
+ */
+template <> bool isa<FeatureObject>(const Object *o) { return o->asFeature() != nullptr; }
+template <> bool isa<KernelObject>(const Object *o) { return o->asKernel() != nullptr; }
+
+template <> FeatureObject *cast(Object *o)
+{
+  assert(o != nullptr);
+  auto res = o->asFeature();
+  assert(res != nullptr);
+  return res;
+}
+
+template <> KernelObject *cast(Object *o)
+{
+  assert(o != nullptr);
+  auto res = o->asKernel();
+  assert(res != nullptr);
+  return res;
+}
+
+template <> FeatureObject *safe_cast(Object *o)
+{
+  // NOTE o may be nullptr
+  return (o == nullptr) ? nullptr : o->asFeature();
+}
+
+template <> KernelObject *safe_cast(Object *o)
+{
+  // NOTE o may be nullptr
+  return (o == nullptr) ? nullptr : o->asKernel();
+}
+
 } // namespace coco
index 0341508..dd3466c 100644 (file)
@@ -106,3 +106,9 @@ TEST_F(ObjectTest, destructor)
     ASSERT_EQ(deps.size(), 0);
   }
 }
+
+TEST_F(ObjectTest, safe_cast)
+{
+  ASSERT_EQ(coco::safe_cast<coco::FeatureObject>(nullptr), nullptr);
+  ASSERT_EQ(coco::safe_cast<coco::KernelObject>(nullptr), nullptr);
+}