From 7b8385afc33dc9f8c4a8c281214d04c42b4050c5 Mon Sep 17 00:00:00 2001 From: Glen Fernandes Date: Wed, 4 Sep 2019 00:56:52 -0400 Subject: [PATCH] Implement NVP in Core for Serialization and other libraries --- doc/core.qbk | 1 + doc/nvp.qbk | 126 +++++++++++++++++++++++++++++++++++++ include/boost/core/nvp.hpp | 113 +++++++++++++++++++++++++++++++++ test/Jamfile.v2 | 2 + test/nvp_test.cpp | 123 ++++++++++++++++++++++++++++++++++++ 5 files changed, 365 insertions(+) create mode 100644 doc/nvp.qbk create mode 100644 include/boost/core/nvp.hpp create mode 100644 test/nvp_test.cpp diff --git a/doc/core.qbk b/doc/core.qbk index 0e2db2c..1aac342 100644 --- a/doc/core.qbk +++ b/doc/core.qbk @@ -55,6 +55,7 @@ criteria for inclusion is that the utility component be: [include noinit_adaptor.qbk] [include noncopyable.qbk] [include null_deleter.qbk] +[include nvp.qbk] [include pointer_traits.qbk] [include quick_exit.qbk] [include ref.qbk] diff --git a/doc/nvp.qbk b/doc/nvp.qbk new file mode 100644 index 0000000..3ef56ba --- /dev/null +++ b/doc/nvp.qbk @@ -0,0 +1,126 @@ +[/ +Copyright 2019 Glen Joseph Fernandes +(glenjofe@gmail.com) + +Distributed under the Boost Software License, Version 1.0. +(http://www.boost.org/LICENSE_1_0.txt) +] + +[section:nvp nvp] + +[section Overview] + +The header provides the class template `boost::nvp` that +pairs a name (`const char*`) with the address of a value (`T*`). It is the new +implementation of the NVP type previously provided by the Boost Serialization +library. This type now lives in the Core library so that other Boost libraries +can support named value serialization without taking a dependency on the +Serialization library. + +[endsect] + +[section Examples] + +The following snippet shows use in a member serialize function: + +``` +template +void serialize(Archive& archive, unsigned) +{ + archive & boost::make_nvp("x", x_) & boost::make_nvp("y", y_); +} +``` + +[endsect] + +[section Reference] + +``` +namespace boost { + +template +class nvp { + nvp(const char* name, T& value) noexcept; + + const char* name() const noexcept; + + T& value() const noexcept; + + const T& const_value() const noexcept; + + template + void save(Archive& archive, unsigned) const; + + template + void load(Archive& archive, unsigned); + + template + void serialize(Archive& archive, unsigned); +}; + +template +struct is_nvp; + +template +const nvp make_nvp(const char* name, T& value) noexcept; + +} /* boost */ +``` + +[section Constructors] + +[variablelist +[[`nvp(const char* name, T& value) noexcept;`] +[Initializes the stored name pointer with `name` and the value pointer with +`addressof(value)`.]]] + +[endsect] + +[section Members] + +[variablelist +[[`const char* name() const noexcept;`] +[Returns the stored name pointer.]] +[[`T& value() const noexcept;`] +[Returns the stored value pointer.]] +[[`const T& const_value() const noexcept;`] +[Returns the stored value pointer.]] +[[`template void save(Archvie& archive, unsigned) const;`] +[Calls `archive.operator<<(const_value())`.]] +[[`template void load(Archvie& archive, unsigned);`] +[Calls `archive.operator>>(value())`.]] +[[`template void serialize(Archvie& archive, +unsigned version);`] +[Calls `save(archive, version)` if `Archive::is_saving` is a true type, +otherwise `load(archive, version)`.]]] + +[endsect] + +[section Traits] + +[variablelist +[[`template class is_nvp;`] +[Provides static constant `value` equal to true if `T` is an NVP type, +otherwise false.]]] + +[endsect] + +[section Functions] + +[variablelist +[[`template const nvp make_nvp(const char* name, T& value) +noexcept;`] +[Returns `nvp(name, value)`.]]] + +[endsect] + +[endsect] + +[section Acknowledgments] + +Robert Ramey originally implemented nvp in the Serialization library. Glen +Fernandes implemented this new (but compatible) version in the Core library. + +[endsect] + +[endsect] diff --git a/include/boost/core/nvp.hpp b/include/boost/core/nvp.hpp new file mode 100644 index 0000000..d61a533 --- /dev/null +++ b/include/boost/core/nvp.hpp @@ -0,0 +1,113 @@ +/* +Copyright 2019 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_NVP_HPP +#define BOOST_CORE_NVP_HPP + +#include +#include + +namespace boost { +namespace detail { + +template +struct nvp_bool { + typedef bool value_type; + typedef nvp_bool type; + + BOOST_STATIC_CONSTANT(bool, value = V); + + BOOST_CONSTEXPR operator bool() const BOOST_NOEXCEPT { + return V; + } + + BOOST_CONSTEXPR bool operator()() const BOOST_NOEXCEPT { + return V; + } +}; + +} /* detail */ + +template +class nvp { +public: + nvp(const char* n, T& v) BOOST_NOEXCEPT + : n_(n) + , v_(boost::addressof(v)) { } + + const char* name() const BOOST_NOEXCEPT { + return n_; + } + + T& value() const BOOST_NOEXCEPT { + return *v_; + } + + const T& const_value() const BOOST_NOEXCEPT { + return *v_; + } + + template + void save(A& a, unsigned) const { + a.operator<<(*v_); + } + + template + void load(A& a, unsigned) { + a.operator>>(*v_); + } + + template + void serialize(A& a, unsigned) { + archive(a, detail::nvp_bool()); + } + +private: + template + void archive(A& a, detail::nvp_bool) const { + a.operator<<(*v_); + } + + template + void archive(A& a, detail::nvp_bool) { + a.operator>>(*v_); + } + + const char* n_; + T* v_; +}; + +template +struct is_nvp + : detail::nvp_bool { }; + +template +struct is_nvp > + : detail::nvp_bool { }; + +template +struct is_nvp > + : detail::nvp_bool { }; + +template +struct is_nvp > + : detail::nvp_bool { }; + +template +struct is_nvp > + : detail::nvp_bool { }; + +template +inline const nvp +make_nvp(const char* n, T& v) BOOST_NOEXCEPT +{ + return nvp(n, v); +} + +} /* boost */ + +#endif diff --git a/test/Jamfile.v2 b/test/Jamfile.v2 index d912c1c..d45b50d 100644 --- a/test/Jamfile.v2 +++ b/test/Jamfile.v2 @@ -145,6 +145,8 @@ run alloc_construct_test.cpp ; run alloc_construct_throws_test.cpp ; run alloc_construct_cxx11_test.cpp ; +run nvp_test.cpp ; + lib lib_typeid : lib_typeid.cpp : shared:LIB_TYPEID_DYN_LINK=1 ; run test_lib_typeid.cpp lib_typeid : : : shared : test_lib_typeid_shared ; diff --git a/test/nvp_test.cpp b/test/nvp_test.cpp new file mode 100644 index 0000000..257cf01 --- /dev/null +++ b/test/nvp_test.cpp @@ -0,0 +1,123 @@ +/* +Copyright 2019 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 + +class saver { +public: + struct is_saving { + static const bool value = true; + }; + + explicit saver(int value) + : value_(value) { } + + int get() const { + return value_; + } + + void operator<<(int value) { + value_ = value; + } + +private: + int value_; +}; + +class loader { +public: + struct is_saving { + static const bool value = false; + }; + + explicit loader(int value) + : value_(value) { } + + void operator>>(int& value) { + value = value_; + } + +private: + int value_; +}; + +void test() +{ + const char* n = "name"; + int v = 1; + boost::nvp p(n, v); + BOOST_TEST_EQ(p.name(), n); + BOOST_TEST_EQ(p.value(), 1); + BOOST_TEST_EQ(&p.value(), &v); +} + +void test_save() +{ + int v = 1; + boost::nvp p("name", v); + saver s(0); + p.save(s, unsigned()); + BOOST_TEST_EQ(s.get(), 1); +} + +void test_load() +{ + int v = 1; + boost::nvp p("name", v); + loader l(5); + p.load(l, unsigned()); + BOOST_TEST_EQ(p.value(), 5); +} + +void test_serialize() +{ + int v = 1; + boost::nvp p("name", v); + saver s(0); + p.serialize(s, unsigned()); + BOOST_TEST_EQ(s.get(), 1); +} + +void test_deserialize() +{ + int v = 1; + boost::nvp p("name", v); + loader l(5); + p.serialize(l, unsigned()); + BOOST_TEST_EQ(p.value(), 5); +} + +void test_trait() +{ + BOOST_TEST_TRAIT_TRUE((boost::is_nvp >)); + BOOST_TEST_TRAIT_FALSE((boost::is_nvp)); + BOOST_TEST_TRAIT_TRUE((boost::is_nvp >)); + BOOST_TEST_TRAIT_FALSE((boost::is_nvp)); +} + +void test_factory() +{ + const char* n = "name"; + int v = 1; + boost::nvp p = boost::make_nvp(n, v); + BOOST_TEST_EQ(p.name(), n); + BOOST_TEST_EQ(p.value(), 1); + BOOST_TEST_EQ(&p.value(), &v); +} + +int main() +{ + test(); + test_save(); + test_load(); + test_serialize(); + test_deserialize(); + test_trait(); + test_factory(); + return boost::report_errors(); +}