diff --git a/lib/include/srsran/adt/optional.h b/lib/include/srsran/adt/optional.h new file mode 100644 index 000000000..159e1efbe --- /dev/null +++ b/lib/include/srsran/adt/optional.h @@ -0,0 +1,117 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#ifndef SRSRAN_OPTIONAL_H +#define SRSRAN_OPTIONAL_H + +#include "detail/type_storage.h" +#include "srsran/common/srsran_assert.h" + +namespace srsran { + +template +class optional +{ +public: + optional() : has_val_(false) {} + optional(const T& t) : has_val_(true) { storage.emplace(t); } + optional(T&& t) : has_val_(true) { storage.emplace(std::move(t)); } + optional(const optional& other) : has_val_(other.has_value()) + { + if (other.has_value()) { + storage.copy_ctor(other.get()); + } + } + optional(optional&& other) noexcept : has_val_(other.has_value()) + { + if (other.has_value()) { + storage.move_ctor(other.get()); + } + } + optional& operator=(const optional& other) + { + if (this == &other) { + return *this; + } + copy_if_present_helper(storage, other.storage, has_value(), other.has_value()); + has_val_ = other.has_value(); + return *this; + } + optional& operator=(optional&& other) noexcept + { + move_if_present_helper(storage, other.storage, has_value(), other.has_value()); + has_val_ = other.has_value(); + return *this; + } + ~optional() + { + if (has_value()) { + storage.destroy(); + } + } + + bool has_value() const { return has_val_; } + explicit operator bool() const { return has_value(); } + + T* operator->() { return &value(); } + const T* operator->() const { return &value(); } + T& operator*() { return value(); } + const T& operator*() const { return value(); } + T& value() + { + srsran_assert(has_val_, "Invalid optional access"); + return storage.get(); + } + const T& value() const + { + srsran_assert(has_val_, "Invalid optional access"); + return storage.get(); + } + + template + void emplace(Args&&... args) + { + if (has_value()) { + storage.destroy(); + } + storage.emplace(std::forward(args)...); + has_val_ = true; + } + + void reset() + { + if (has_value()) { + storage.destroy(); + has_val_ = false; + } + } + +private: + bool has_val_; + detail::type_storage storage; +}; + +template +bool operator==(const optional& lhs, const optional& rhs) +{ + return lhs.has_value() == rhs.has_value() and (not lhs.has_value() or lhs.value() == rhs.value()); +} + +template +bool operator!=(const optional& lhs, const optional& rhs) +{ + return not(lhs == rhs); +} + +} // namespace srsran + +#endif // SRSRAN_OPTIONAL_H diff --git a/lib/test/adt/CMakeLists.txt b/lib/test/adt/CMakeLists.txt index c95661231..18e4ac1c3 100644 --- a/lib/test/adt/CMakeLists.txt +++ b/lib/test/adt/CMakeLists.txt @@ -53,3 +53,7 @@ add_test(circular_map_test circular_map_test) add_executable(fsm_test fsm_test.cc) target_link_libraries(fsm_test srsran_common) add_test(fsm_test fsm_test) + +add_executable(optional_test optional_test.cc) +target_link_libraries(optional_test srsran_common) +add_test(optional_test optional_test) diff --git a/lib/test/adt/optional_test.cc b/lib/test/adt/optional_test.cc new file mode 100644 index 000000000..bcfe19063 --- /dev/null +++ b/lib/test/adt/optional_test.cc @@ -0,0 +1,35 @@ +/** + * + * \section COPYRIGHT + * + * Copyright 2013-2021 Software Radio Systems Limited + * + * By using this file, you agree to the terms and conditions set + * forth in the LICENSE file which can be found at the top level of + * the distribution. + * + */ + +#include "srsran/adt/optional.h" +#include "srsran/common/test_common.h" + +using namespace srsran; + +void test_optional_int() +{ + optional opt, opt2(5); + TESTASSERT(not opt.has_value() and opt2.has_value()); + TESTASSERT(not static_cast(opt) and static_cast(opt2)); + TESTASSERT(opt2.value() == 5 and *opt2 == 5); + + opt = 4; + TESTASSERT(opt.has_value()); + TESTASSERT(opt != opt2); + opt2 = 4; + TESTASSERT(opt == opt2); +} + +int main() +{ + test_optional_int(); +} \ No newline at end of file