From d811474d8f973aaadf2979d7a75a699832ba5732 Mon Sep 17 00:00:00 2001 From: Matthias Koefferlein Date: Sat, 9 Mar 2024 15:48:45 +0100 Subject: [PATCH] tl::optional now based on internal implementation, added tests and tl::to_string binding --- src/tl/tl/tlOptional.cc | 4 +- src/tl/tl/tlOptional.h | 160 +++++++++++++-------------- src/tl/unit_tests/tlOptionalTests.cc | 97 ++++++++++++++++ src/tl/unit_tests/unit_tests.pro | 1 + 4 files changed, 177 insertions(+), 85 deletions(-) create mode 100644 src/tl/unit_tests/tlOptionalTests.cc diff --git a/src/tl/tl/tlOptional.cc b/src/tl/tl/tlOptional.cc index 02269651a..ba2774439 100644 --- a/src/tl/tl/tlOptional.cc +++ b/src/tl/tl/tlOptional.cc @@ -25,8 +25,6 @@ namespace tl { -#if __cplusplus < 201703L -extern const nullopt_t nullopt = nullopt_t(); -#endif +extern const nullopt_t nullopt = nullopt_t (); } // namespace tl diff --git a/src/tl/tl/tlOptional.h b/src/tl/tl/tlOptional.h index 7dcc59565..c30fa6679 100644 --- a/src/tl/tl/tlOptional.h +++ b/src/tl/tl/tlOptional.h @@ -24,136 +24,132 @@ #define HDR_tlOptional #include "tlAssert.h" +#include "tlString.h" +#include "tlCommon.h" #include -#include namespace tl { -#if __cplusplus >= 201703L - -template -class optional : public std::optional {}; - -#else - struct nullopt_t {}; extern const nullopt_t nullopt; -/* - * Poor man's partly implementation of C++17's std::optional +/** + * @brief Poor man's partial implementation of C++17's std::optional */ template -class optional +class TL_PUBLIC_TEMPLATE optional { public: - optional() : - a_value(), - a_isValid(false) - {} + optional () : + m_value (), + m_is_valid (false) + {} - optional(const nullopt_t&) : - a_value(), - a_isValid(false) - {} + optional (const nullopt_t &) : + m_value (), + m_is_valid (false) + {} - optional(const T &value) : - a_value(value), - a_isValid(true) - {} + optional (const T &value) : + m_value (value), + m_is_valid (true) + {} - void reset() - { - a_isValid = false; - } + void reset () + { + m_is_valid = false; + } - bool has_value() const { return a_isValid; } + bool has_value() const { return m_is_valid; } - T &value() - { - tl_assert(a_isValid); + T &value () + { + tl_assert (m_is_valid); - return a_value; - } + return m_value; + } - const T &value() const - { - tl_assert(a_isValid); + const T &value () const + { + tl_assert (m_is_valid); - return a_value; - } + return m_value; + } - T& operator* () - { - return value(); - } + T& operator* () + { + return value (); + } - const T& operator* () const - { - return value(); - } + const T& operator* () const + { + return value (); + } - T* operator-> () - { - return &value(); - } + T* operator-> () + { + return m_is_valid ? &m_value : 0; + } - const T* operator-> () const - { - return &value(); - } + const T* operator-> () const + { + return m_is_valid ? &m_value : 0; + } private: - T a_value; - bool a_isValid; + T m_value; + bool m_is_valid; }; template -optional make_optional(const T& value) +optional make_optional (const T &value) { - return optional(value); + return optional (value); } template -bool operator==(const optional &lhs, const optional &rhs) +bool operator== (const optional &lhs, const optional &rhs) { - if (lhs.has_value() != rhs.has_value()) - { - return false; - } + if (lhs.has_value () != rhs.has_value ()) { + return false; + } + if (!lhs.has_value ()) { + return true; + } - if (!lhs.has_value()) - { - return true; - } - - return lhs.value() == rhs.value(); + return lhs.value() == rhs.value(); } template -bool operator!=(const optional &lhs, const optional &rhs) +bool operator!= (const optional &lhs, const optional &rhs) { - return !(lhs == rhs); + return !(lhs == rhs); } template -std::ostream &operator<<(std::ostream &ostr, const optional &rhs) +std::ostream &operator<< (std::ostream &ostr, const optional &rhs) { - if (rhs.has_value()) - { - ostr << rhs.value(); - } - else - { - ostr << ""; - } + if (rhs.has_value()) { + ostr << rhs.value(); + } else { + ostr << ""; + } - return ostr; + return ostr; } -#endif /* __cplusplus >= 201703L */ +template +std::string to_string (const optional &opt) +{ + if (opt.has_value ()) { + return tl::to_string (*opt); + } else { + return std::string (); + } +} } // namespace tl diff --git a/src/tl/unit_tests/tlOptionalTests.cc b/src/tl/unit_tests/tlOptionalTests.cc new file mode 100644 index 000000000..182d0048d --- /dev/null +++ b/src/tl/unit_tests/tlOptionalTests.cc @@ -0,0 +1,97 @@ + +/* + + KLayout Layout Viewer + Copyright (C) 2006-2024 Matthias Koefferlein + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 2 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program; if not, write to the Free Software + Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA + +*/ + +#include "tlOptional.h" +#include "tlUnitTest.h" + +namespace +{ + +TEST(1_Basic) +{ + tl::optional opt; + + // value not set + + EXPECT_EQ (opt.has_value (), false); + EXPECT_EQ (opt.operator-> (), (int *) 0); + EXPECT_EQ (((const tl::optional &) opt).operator-> (), (const int *) 0); + EXPECT_EQ (tl::to_string (opt), ""); + + try { + opt.value (); // asserts + EXPECT_EQ (true, false); + } catch (...) { + } + + // make_optional, assignment + + opt = tl::make_optional (17); + + // value set + + EXPECT_EQ (opt.has_value (), true); + EXPECT_EQ (opt.value (), 17); + EXPECT_EQ (tl::to_string (opt), "17"); + EXPECT_EQ (((const tl::optional &) opt).value (), 17); + EXPECT_EQ (*opt, 17); + EXPECT_EQ (*((const tl::optional &) opt), 17); + EXPECT_EQ (*(opt.operator-> ()), 17); + EXPECT_EQ (*(((const tl::optional &) opt).operator-> ()), 17); + + // compare operators + + EXPECT_EQ (opt == tl::make_optional (-1), false); + EXPECT_EQ (opt == tl::make_optional (17), true); + EXPECT_EQ (opt == tl::optional (), false); + + EXPECT_EQ (opt != tl::make_optional (-1), true); + EXPECT_EQ (opt != tl::make_optional (17), false); + EXPECT_EQ (opt != tl::optional (), true); + + // copy ctor + + tl::optional opt2 (opt); + + EXPECT_EQ (opt2.has_value (), true); + EXPECT_EQ (opt2.value (), 17); + + // reset method + + opt = tl::make_optional (17); + opt.reset (); + + EXPECT_EQ (opt.has_value (), false); + EXPECT_EQ (opt == tl::optional (), true); + EXPECT_EQ (opt != tl::optional (), false); + + // tl::nullopt tag + + opt = tl::make_optional (17); + opt = tl::optional (tl::nullopt); + + EXPECT_EQ (opt.has_value (), false); + EXPECT_EQ (opt == tl::optional (), true); + EXPECT_EQ (opt != tl::optional (), false); +} + +} diff --git a/src/tl/unit_tests/unit_tests.pro b/src/tl/unit_tests/unit_tests.pro index 0e4bcc449..3d8b06676 100644 --- a/src/tl/unit_tests/unit_tests.pro +++ b/src/tl/unit_tests/unit_tests.pro @@ -31,6 +31,7 @@ SOURCES = \ tlLongIntTests.cc \ tlMathTests.cc \ tlObjectTests.cc \ + tlOptionalTests.cc \ tlPixelBufferTests.cc \ tlResourcesTests.cc \ tlReuseVectorTests.cc \