1
0
forked from boostorg/core

Implement NVP in Core for Serialization and other libraries

This commit is contained in:
Glen Fernandes
2019-09-04 00:56:52 -04:00
parent 106a7c0939
commit 7b8385afc3
5 changed files with 365 additions and 0 deletions

View File

@ -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]

126
doc/nvp.qbk Normal file
View File

@ -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 <boost/core/nvp.hpp> 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<class Archive>
void serialize(Archive& archive, unsigned)
{
archive & boost::make_nvp("x", x_) & boost::make_nvp("y", y_);
}
```
[endsect]
[section Reference]
```
namespace boost {
template<class T>
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<class Archive>
void save(Archive& archive, unsigned) const;
template<class Archive>
void load(Archive& archive, unsigned);
template<class Archive>
void serialize(Archive& archive, unsigned);
};
template<class T>
struct is_nvp;
template<class T>
const nvp<T> 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<class Archive> void save(Archvie& archive, unsigned) const;`]
[Calls `archive.operator<<(const_value())`.]]
[[`template<class Archive> void load(Archvie& archive, unsigned);`]
[Calls `archive.operator>>(value())`.]]
[[`template<class Archive> 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 T> class is_nvp;`]
[Provides static constant `value` equal to true if `T` is an NVP type,
otherwise false.]]]
[endsect]
[section Functions]
[variablelist
[[`template<class T> const nvp<T> make_nvp(const char* name, T& value)
noexcept;`]
[Returns `nvp<T>(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]

113
include/boost/core/nvp.hpp Normal file
View File

@ -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 <boost/core/addressof.hpp>
#include <boost/config.hpp>
namespace boost {
namespace detail {
template<bool V>
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 T>
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<class A>
void save(A& a, unsigned) const {
a.operator<<(*v_);
}
template<class A>
void load(A& a, unsigned) {
a.operator>>(*v_);
}
template<class A>
void serialize(A& a, unsigned) {
archive(a, detail::nvp_bool<A::is_saving::value>());
}
private:
template<class A>
void archive(A& a, detail::nvp_bool<true>) const {
a.operator<<(*v_);
}
template<class A>
void archive(A& a, detail::nvp_bool<false>) {
a.operator>>(*v_);
}
const char* n_;
T* v_;
};
template<class>
struct is_nvp
: detail::nvp_bool<false> { };
template<class T>
struct is_nvp<nvp<T> >
: detail::nvp_bool<true> { };
template<class T>
struct is_nvp<const nvp<T> >
: detail::nvp_bool<true> { };
template<class T>
struct is_nvp<volatile nvp<T> >
: detail::nvp_bool<true> { };
template<class T>
struct is_nvp<const volatile nvp<T> >
: detail::nvp_bool<true> { };
template<class T>
inline const nvp<T>
make_nvp(const char* n, T& v) BOOST_NOEXCEPT
{
return nvp<T>(n, v);
}
} /* boost */
#endif

View File

@ -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 : <link>shared:<define>LIB_TYPEID_DYN_LINK=1 ;
run test_lib_typeid.cpp lib_typeid : : : <link>shared : test_lib_typeid_shared ;

123
test/nvp_test.cpp Normal file
View File

@ -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 <boost/core/nvp.hpp>
#include <boost/core/lightweight_test_trait.hpp>
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<int> 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<int> p("name", v);
saver s(0);
p.save(s, unsigned());
BOOST_TEST_EQ(s.get(), 1);
}
void test_load()
{
int v = 1;
boost::nvp<int> p("name", v);
loader l(5);
p.load(l, unsigned());
BOOST_TEST_EQ(p.value(), 5);
}
void test_serialize()
{
int v = 1;
boost::nvp<int> p("name", v);
saver s(0);
p.serialize(s, unsigned());
BOOST_TEST_EQ(s.get(), 1);
}
void test_deserialize()
{
int v = 1;
boost::nvp<int> 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::nvp<double> >));
BOOST_TEST_TRAIT_FALSE((boost::is_nvp<double>));
BOOST_TEST_TRAIT_TRUE((boost::is_nvp<const boost::nvp<int> >));
BOOST_TEST_TRAIT_FALSE((boost::is_nvp<const int>));
}
void test_factory()
{
const char* n = "name";
int v = 1;
boost::nvp<int> 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();
}