IVGCVSW-2759 Add MakeOptional to enable in-place optional object construction

* Added new argument-forwarding in-place constructor to Optional
* Added MakeOptional utility template to allow for efficient construction
  of optional objects

Change-Id: Iec9067fc5c3e109a26c4cc2fe8468260637b66c5
Signed-off-by: Aron Virginas-Tar <Aron.Virginas-Tar@arm.com>
diff --git a/include/armnn/Optional.hpp b/include/armnn/Optional.hpp
index cfe0d30..116466d 100644
--- a/include/armnn/Optional.hpp
+++ b/include/armnn/Optional.hpp
@@ -30,6 +30,15 @@
 // to have default value for an Optional in a function declaration.
 struct EmptyOptional {};
 
+// Disambiguation tag that can be passed to the constructor to indicate that
+// the contained object should be constructed in-place
+struct ConstructInPlace
+{
+    explicit ConstructInPlace() = default;
+};
+
+#define CONSTRUCT_IN_PLACE armnn::ConstructInPlace{}
+
 // OptionalBase is the common functionality between reference and non-reference
 // optional types.
 class OptionalBase
@@ -79,6 +88,13 @@
         Construct(value);
     }
 
+    template<class... Args>
+    OptionalReferenceSwitch(ConstructInPlace, Args&&... args)
+        : Base{}
+    {
+        Construct(CONSTRUCT_IN_PLACE, std::forward<Args>(args)...);
+    }
+
     OptionalReferenceSwitch(const OptionalReferenceSwitch& other)
         : Base{}
     {
@@ -152,6 +168,13 @@
         m_HasValue = true;
     }
 
+    template<class... Args>
+    void Construct(ConstructInPlace, Args&&... args)
+    {
+        new (m_Storage) T(std::forward<Args>(args)...);
+        m_HasValue = true;
+    }
+
     alignas(alignof(T)) unsigned char m_Storage[sizeof(T)];
 };
 
@@ -181,6 +204,9 @@
     {
     }
 
+    template<class... Args>
+    OptionalReferenceSwitch(ConstructInPlace, Args&&... args) = delete;
+
     OptionalReferenceSwitch& operator=(const T value)
     {
         m_Storage = &value;
@@ -247,6 +273,18 @@
     Optional(EmptyOptional empty) : BaseSwitch{empty} {}
     Optional(const Optional& other) : BaseSwitch{other} {}
     Optional(const BaseSwitch& other) : BaseSwitch{other} {}
+
+    template<class... Args>
+    explicit Optional(ConstructInPlace, Args&&... args) :
+        BaseSwitch(CONSTRUCT_IN_PLACE, std::forward<Args>(args)...) {}
 };
 
+// Utility template that constructs an object of type T in-place and wraps
+// it inside an Optional<T> object
+template<typename T, class... Args>
+Optional<T> MakeOptional(Args&&... args)
+{
+    return Optional<T>(CONSTRUCT_IN_PLACE, std::forward<Args>(args)...);
+}
+
 }
diff --git a/src/armnn/test/OptionalTest.cpp b/src/armnn/test/OptionalTest.cpp
index 3f4c02d..e205439 100644
--- a/src/armnn/test/OptionalTest.cpp
+++ b/src/armnn/test/OptionalTest.cpp
@@ -54,7 +54,6 @@
     BOOST_TEST(optionalString3.value() == "Hello World");
 }
 
-
 BOOST_AUTO_TEST_CASE(StringRefTests)
 {
     armnn::Optional<std::string&> optionalStringRef{armnn::EmptyOptional()};
@@ -111,4 +110,42 @@
     BOOST_TEST(otherOptionalInt.value() == intValue);
 }
 
+BOOST_AUTO_TEST_CASE(ObjectConstructedInPlaceTests)
+{
+    struct SimpleObject
+    {
+        public:
+            SimpleObject(const std::string& name, int value)
+                : m_Name(name)
+                , m_Value(value)
+            {}
+
+            bool operator ==(const SimpleObject& other)
+            {
+                return m_Name  == other.m_Name &&
+                       m_Value == other.m_Value;
+            }
+
+        private:
+            std::string m_Name;
+            int         m_Value;
+    };
+
+    std::string objectName("SimpleObject");
+    int objectValue = 1;
+    SimpleObject referenceObject(objectName, objectValue);
+
+    // Use MakeOptional
+    armnn::Optional<SimpleObject> optionalObject1 = armnn::MakeOptional<SimpleObject>(objectName, objectValue);
+    BOOST_CHECK(optionalObject1 == true);
+    BOOST_CHECK(optionalObject1.has_value() == true);
+    BOOST_CHECK(optionalObject1.value() == referenceObject);
+
+    // Call in-place constructor directly
+    armnn::Optional<SimpleObject> optionalObject2(CONSTRUCT_IN_PLACE, objectName, objectValue);
+    BOOST_CHECK(optionalObject1 == true);
+    BOOST_CHECK(optionalObject1.has_value() == true);
+    BOOST_CHECK(optionalObject1.value() == referenceObject);
+}
+
 BOOST_AUTO_TEST_SUITE_END()