[Common] add optional class like boost::optional
authorpius.lee <pius.lee@samsung.com>
Tue, 10 Feb 2015 15:45:13 +0000 (00:45 +0900)
committerpius lee <pius.lee@samsung.com>
Fri, 13 Feb 2015 06:50:17 +0000 (15:50 +0900)
[Verified] tested with self made c++ test cases on gcc4.6 and gcc4.8

Change-Id: I640675a034b24539a18b55370e38bfa0fab0182e
Signed-off-by: pius.lee <pius.lee@samsung.com>
src/common/common.gypi
src/common/optional.h [new file with mode: 0644]

index e9943ba..260a0fb 100644 (file)
@@ -97,6 +97,7 @@
       'task-queue.h',
       'callback_user_data.cc',
       'callback_user_data.h',
+      'optional.h',
       #'multi_callback_user_data.cc',
       #'multi_callback_user_data.h',
       'platform_result.cc',
diff --git a/src/common/optional.h b/src/common/optional.h
new file mode 100644 (file)
index 0000000..f382149
--- /dev/null
@@ -0,0 +1,113 @@
+// Copyright 2014 Samsung Electronics Co, Ltd. All rights reserved.
+// Use of this source code is governed by a BSD-style license that can be
+// found in the LICENSE file.
+
+#ifndef COMMON_OPTIONAL_H_
+#define COMMON_OPTIONAL_H_
+
+#if __GNUC__ >= 4 && __GNUC_MINOR__ >= 8
+  #define ALIGNAS_TYPE(x) alignas(x)
+  #define ALIGNAS(x) alignas(x)
+#else
+  #define ALIGNAS_TYPE(x) __attribute__((__aligned__(__alignof(x))))
+  #define ALIGNAS(x) __attribute__((aligned(x)))
+#endif
+
+
+#include <cassert>
+#include <new>
+#include <utility>
+#include <type_traits>
+
+namespace common {
+
+template<typename T>
+class optional {
+  static_assert(!std::is_reference<T>::value, "reference is not supported");
+
+ public:
+  optional() : exist_(false) {}
+  explicit optional(std::nullptr_t) : exist_(false) {}
+  optional(const optional& rhs): exist_(rhs.exist_) { create(rhs); }
+  optional(optional&& rhs): exist_(rhs.exist_) { create(std::move(rhs)); }
+  optional(const T& v): exist_(true) { create(v); }
+  ~optional() { if (exist_) destroy(); }
+
+  bool operator !() const { return !exist_; }
+  explicit operator bool() const { return exist_; }
+
+  optional& operator = (const optional& rhs) { return assign(rhs); }
+  optional& operator = (optional&& rhs) { return assign(std::move(rhs)); }
+  optional& operator = (std::nullptr_t) {if (exist_) cleanup(); return *this; }
+  optional& operator = (const T& v) { return assign(v); }
+
+  const T& operator * () const { return *get(); }
+  T& operator * () { return *get(); }
+  const T* operator -> () const { return get(); }
+  T* operator -> () { return get(); }
+
+ private:
+  void create(const T& v) {
+    new(value_) T(v);
+  }
+  void create(T&& v) {
+    new(value_) T(std::move(v));
+  }
+  void create(const optional& rhs) {
+    if (exist_) create(*rhs.get());
+  }
+  void create(optional&& rhs) {
+    if (exist_) create(std::move(*rhs.get()));
+  }
+  void destroy() {
+    get()->~T();
+  }
+  const T* get() const {
+    assert(exist_);
+    return reinterpret_cast<const T*>(value_);
+  }
+
+  T* get() {
+    assert(exist_);
+    return reinterpret_cast<T*>(value_);
+  }
+
+  void cleanup() {
+    destroy();
+    exist_ = false;
+  }
+
+  optional& assign(const T& v) {
+    if (exist_) {
+      *get() = v;
+    } else {
+      create(v);
+      exist_ = true;
+    }
+    return *this;
+  }
+
+  optional& assign(const optional& rhs) {
+    if (rhs.exist_) return assign(*rhs.get());
+    if (!exist_) return *this;
+    cleanup();
+    return *this;
+  }
+
+  optional& assign(optional&& rhs) {
+    if (rhs.exist_) return assign(std::move(*rhs.get()));
+    if (!exist_) return *this;
+    cleanup();
+    return *this;
+  }
+
+  bool exist_;
+  ALIGNAS_TYPE(T) char value_[sizeof(T)];
+};
+
+}  // namespace common
+
+#undef ALIGNAS_TYPE
+#undef ALIGNAS
+
+#endif  // COMMON_OPTIONAL_H_