diff --git a/include/boost/core/empty_value.hpp b/include/boost/core/empty_value.hpp new file mode 100644 index 0000000..8853588 --- /dev/null +++ b/include/boost/core/empty_value.hpp @@ -0,0 +1,113 @@ +/* +Copyright 2018 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#ifndef BOOST_CORE_EMPTY_VALUE_HPP +#define BOOST_CORE_EMPTY_VALUE_HPP + +#include +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#include +#endif + +#if defined(BOOST_GCC_VERSION) && (BOOST_GCC_VERSION >= 40700) +#define BOOST_DETAIL_EMPTY_VALUE_BASE +#elif defined(BOOST_INTEL) && defined(_MSC_VER) && (_MSC_VER >= 1800) +#define BOOST_DETAIL_EMPTY_VALUE_BASE +#elif defined(BOOST_MSVC) && (BOOST_MSVC >= 1800) +#define BOOST_DETAIL_EMPTY_VALUE_BASE +#elif defined(BOOST_CLANG) && !defined(__CUDACC__) +#if __has_feature(is_empty) && __has_feature(is_final) +#define BOOST_DETAIL_EMPTY_VALUE_BASE +#endif +#endif + +namespace boost { + +template +struct use_empty_value_base { + enum { +#if defined(BOOST_DETAIL_EMPTY_VALUE_BASE) + value = __is_empty(T) && !__is_final(T) +#else + value = false +#endif + }; +}; + +struct empty_init_t { }; + +template::value> +class empty_value { +public: + empty_value() + : value_() { } + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + empty_value(empty_init_t, Args&&... args) + : value_(std::forward(args)...) { } +#else + template + empty_value(empty_init_t, U&& value) + : value_(std::forward(value)) { } +#endif +#else + template + empty_value(empty_init_t, const U& value) + : value_(value) { } +#endif + + const T& get() const BOOST_NOEXCEPT { + return value_; + } + + T& get() BOOST_NOEXCEPT { + return value_; + } + +private: + T value_; +}; + +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) +template +class empty_value + : T { +public: + empty_value() + : T() { } + +#if !defined(BOOST_NO_CXX11_RVALUE_REFERENCES) +#if !defined(BOOST_NO_CXX11_VARIADIC_TEMPLATES) + template + empty_value(empty_init_t, Args&&... args) + : T(std::forward(args)...) { } +#else + template + empty_value(empty_init_t, U&& value) + : T(std::forward(value)) { } +#endif +#else + template + empty_value(empty_init_t, const U& value) + : T(value) { } +#endif + + const T& get() const BOOST_NOEXCEPT { + return *this; + } + + T& get() BOOST_NOEXCEPT { + return *this; + } +}; +#endif + +} /* boost */ + +#endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index 320fca9..284b4c1 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -123,5 +123,8 @@ run to_address_test.cpp ; run exchange_test.cpp ; run exchange_move_test.cpp ; +run empty_value_test.cpp ; +run empty_value_size_test.cpp ; + use-project /boost/core/swap : ./swap ; build-project ./swap ; diff --git a/test/empty_value_size_test.cpp b/test/empty_value_size_test.cpp new file mode 100644 index 0000000..f0ed675 --- /dev/null +++ b/test/empty_value_size_test.cpp @@ -0,0 +1,60 @@ +/* +Copyright 2018 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#include +#if !defined(BOOST_NO_TEMPLATE_PARTIAL_SPECIALIZATION) +#include +#include + +struct T1 { }; + +struct S1 + : boost::empty_value { }; + +struct T2 { + int value; +}; + +struct S2 + : boost::empty_value + , boost::empty_value { }; + +struct S3 + : boost::empty_value + , boost::empty_value { }; + +struct T3 { }; + +struct S4 + : boost::empty_value + , boost::empty_value { }; + +struct S5 + : boost::empty_value + , boost::empty_value { }; + +struct S6 + : boost::empty_value + , boost::empty_value + , boost::empty_value { }; + +int main() +{ + BOOST_TEST(sizeof(S1) == sizeof(T1)); + BOOST_TEST(sizeof(S2) == sizeof(T2)); + BOOST_TEST(sizeof(S3) > sizeof(T2)); + BOOST_TEST(sizeof(S4) == sizeof(T1)); + BOOST_TEST(sizeof(S5) > sizeof(T1)); + BOOST_TEST(sizeof(S6) == sizeof(T2)); + return boost::report_errors(); +} +#else +int main() +{ + return 0; +} +#endif diff --git a/test/empty_value_test.cpp b/test/empty_value_test.cpp new file mode 100644 index 0000000..d7261b6 --- /dev/null +++ b/test/empty_value_test.cpp @@ -0,0 +1,76 @@ +/* +Copyright 2018 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +*/ +#include +#include + +struct empty { + operator bool() const { + return false; + } + operator bool() { + return true; + } +}; + +class type { +public: + type() + : value_(false) { } + explicit type(bool value) + : value_(value) { } + operator bool() const { + return value_; + } +private: + bool value_; +}; + +void test_bool() +{ + const boost::empty_value v1(boost::empty_init_t(), true); + BOOST_TEST(v1.get()); + boost::empty_value v2; + BOOST_TEST(!v2.get()); + v2 = v1; + BOOST_TEST(v2.get()); + v2.get() = false; + BOOST_TEST(!v2.get()); +} + +void test_empty() +{ + empty e; + const boost::empty_value v1(boost::empty_init_t(), e); + BOOST_TEST(!v1.get()); + boost::empty_value v2; + BOOST_TEST(v2.get()); + v2 = v1; + BOOST_TEST(v2.get()); + v2.get() = empty(); + BOOST_TEST(v2.get()); +} + +void test_type() +{ + const boost::empty_value v1(boost::empty_init_t(), true); + BOOST_TEST(v1.get()); + boost::empty_value v2; + BOOST_TEST(!v2.get()); + v2 = v1; + BOOST_TEST(v2.get()); + v2.get() = type(); + BOOST_TEST(!v2.get()); +} + +int main() +{ + test_bool(); + test_empty(); + test_type(); + return boost::report_errors(); +}