2
0
mirror of https://github.com/boostorg/pfr.git synced 2026-01-19 04:22:13 +00:00

More tests, some refactoring, flat functions now have their precise version, started improving the documents, fixed issues with const propagations, better separation of functions (now IO functions are not part of the core.hpp)

This commit is contained in:
Antony Polukhin
2016-12-28 22:19:29 +03:00
parent 63a41e0256
commit af0a937126
34 changed files with 757 additions and 391 deletions

View File

@@ -11,6 +11,8 @@ doxygen autodoc
:
[ glob ../../../boost/pfr.hpp ]
[ glob ../../../boost/pfr/*.hpp ]
[ glob ../../../boost/pfr/flat/*.hpp ]
[ glob ../../../boost/pfr/precise/*.hpp ]
:
<doxygen:param>EXTRACT_ALL=NO
<doxygen:param>HIDE_UNDOC_MEMBERS=YES
@@ -21,8 +23,10 @@ doxygen autodoc
<doxygen:param>INLINE_SIMPLE_STRUCTS=YES
<doxygen:param>SORT_MEMBER_DOCS=NO
<doxygen:param>"ALIASES= \\
\"flattening{1}=\\xmlonly<link linkend='boost_pod_flat_reflection.quick_start.flattening'>\\1</link>\\endxmlonly\" \\
\"podops=\\b See \\b Also: \\xmlonly<link linkend='boost_pod_flat_reflection.quick_start.three_ways_of_getting_operators'>Three ways of getting operators</link>\\endxmlonly\" \\
\"flattening{1}=\\xmlonly<link linkend='boost_precise_and_flat_reflectio.quick_start.flattening'>\\1</link>\\endxmlonly\" \\
\"podops=\\b See \\b Also: \\xmlonly<link linkend='boost_precise_and_flat_reflectio.quick_start.three_ways_of_getting_operators'>Three ways of getting operators</link>\\endxmlonly\" \\
\"constexprinit{1}=\\xmlonly<link linkend='boost_precise_and_flat_reflectio.requirements_and_limitations'>\\1</link>\\endxmlonly\" \\
\"flatpod{1}=\\xmlonly<link linkend='boost_precise_and_flat_reflectio.requirements_and_limitations'>\\1</link>\\endxmlonly\" \\
"
<doxygen:param>"PREDEFINED=\"BOOST_PFR_DOXYGEN_INVOKED\" \\
\"detail::stl_type_info=std::type_info\""

View File

@@ -1,4 +1,4 @@
[library Boost.POD Flat Reflection
[library Boost.Precise and Flat Reflection
[quickbook 1.6]
[version 1.0]
[copyright 2016 Antony Polukhin]
@@ -23,7 +23,7 @@ This library provides tuple like methods for POD types, making PODs usable in co
No macro or other type/member registrations required.]
Boost.POD Flat Reflection (Boost.PFR) adds following out-of-the-box functionality to PODs:
Boost.Precise and Flat Reflection (Boost.PFR) adds following out-of-the-box functionality to PODs:
* comparison operators
* heterogeneous comparators
@@ -45,7 +45,24 @@ Boost.POD Flat Reflection (Boost.PFR) adds following out-of-the-box functionalit
[section Accessing POD member by index] [pfr_example_get] [endsect]
[section Flattening] [pfr_example_flattening] [pfr_example_flattening_2] [endsect]
[/ [section Counting fields] [pfr_example_flat_tuple_size] [endsect] ]
[/ [section Counting fields] [pfr_example_tuple_size] [endsect] ]
[section Flat or Precise functions to chose]
All the functions that have `flat_` prefix and are defclared in `boost/pfr/flat/*` headers the [*flat] functions, other function are [*precise] and are defclared in `boost/pfr/precise/*`. In previous example you've seen how the the flattening works.
Flat functions are more limited in their reflection capabilities, but guarantee to not affect debug and release builds in C++14 mode (no additional code would be produced).
Precise functions have almost unlimited reflection capabilities, but may produce additional code in C++14 mode in debug builds and even in release builds (on old compilers or compilers with bad optimizers).
Here's how to chose your functions:
* If you use C++17 - use [*precise] functions
* If you work only with flat POD types in C++14 - use [*flat] functions
* If you work only with POD types in C++14 and wish them flattened - use [*flat] functions
* If you have modern compiler in C++14 mode and work with non-POD literal types with some hierarhy - you are forced to use [*precise] functions
[endsect]
[section Three ways of getting operators ]
There are three ways to start using Boost.PFR hashing, comparison and streaming operators for type `T` in your code. Each method has it's own drawbacks and suits own cases.
@@ -57,24 +74,24 @@ There are three ways to start using Boost.PFR hashing, comparison and streaming
[ Usable localy, without affecting code from other scopes ]
[ Ignores implicit conversion operators ]
[ Respects user defined operators ] ]
[[ [headerref boost/pfr/flat_ops.hpp] ] [ no ] [ no ] [ yes ] [ yes ] [ no ] [ yes ] ]
[[ [headerref boost/pfr/flat_functions_for.hpp] ] [ yes if T is in it ] [ yes ] [ no ] [ no, but could be limited to translation unit ] [ yes for T ] [ no (compile time error) ] ]
[[ [headerref boost/pfr/global_flat_ops.hpp] ] [ yes ] [ yes ] [ yes ] [ no, but could be limited to translation unit ] [ yes all ] [ yes ] ]
[[ [headerref boost/pfr/flat/ops.hpp] or [headerref boost/pfr/precise/ops.hpp] ] [ no ] [ no ] [ yes ] [ yes ] [ no ] [ yes ] ]
[[ [headerref boost/pfr/flat/functions_for.hpp] or [headerref boost/pfr/precise/functions_for.hpp] ] [ yes if T is in it ] [ yes ] [ no ] [ no, but could be limited to translation unit ] [ yes for T ] [ no (compile time error) ] ]
[[ [headerref boost/pfr/flat/global_ops.hpp] or [headerref boost/pfr/precise/global_ops.hpp] ] [ yes ] [ yes ] [ yes ] [ no, but could be limited to translation unit ] [ yes all ] [ yes ] ]
]
More detailed description:
[*1) [headerref boost/pfr/flat_ops.hpp] approach]
[*1) [headerref boost/pfr/precise/ops.hpp] and [headerref boost/pfr/flat/ops.hpp] approach]
This method is good if you're writing generic algorithms and need to use operators from Boost.PFR only if there's no operators defined for the type:
```
#include <boost/pfr/flat_ops.hpp>
#include <boost/pfr/precise/ops.hpp>
template <class T>
struct uniform_comparator_less {
bool operator()(const T& lhs, const T& rhs) const noexcept {
using namespace flat_ops; // Enables Boost.PFR operators usage in this scope.
using namespace boost::pfr::ops; // Enables Boost.PFR operators usage in this scope.
return lhs < rhs; // If T has operator< or conversion operator then will use it, otherwise will use boost::pfr::flat_less<T>.
}
};
@@ -83,7 +100,7 @@ This method's effects are local to the function. It works even for local types,
However *Argument Dependant Lookup* does not work with it:
```
#include <boost/pfr/flat_ops.hpp>
#include <boost/pfr/flat/ops.hpp>
template <class T>
struct uniform_comparator_less {
bool operator()(const T& lhs, const T& rhs) const noexcept {
@@ -93,11 +110,11 @@ struct uniform_comparator_less {
};
```
[*2) [headerref boost/pfr/flat_functions_for.hpp] approach]
[*2) [headerref boost/pfr/flat/functions_for.hpp] approach]
This method is good if you're writing POD structure and wish to define operators for that structure.
```
#include <boost/pfr/flat_functions_for.hpp>
#include <boost/pfr/flat/functions_for.hpp>
struct pair_like {
int first;
@@ -114,7 +131,7 @@ Argument Dependant Lookup works well, `std::less` will find the operators for `s
can not be used for local types, it must be called only once in namespace of `T`. It does not respect conversion operators of `T`, so for example the following code
will output different values:
```
#include <boost/pfr/flat_functions_for.hpp>
#include <boost/pfr/flat/functions_for.hpp>
struct empty {
operator std::string() { return "empty{}"; }
@@ -126,12 +143,12 @@ struct empty {
std::cout << empty{}; // Outputs `empty{}` if BOOST_PFR_FLAT_FUNCTIONS_FOR(empty) is commented out, '{}' otherwise.
```
[*3) [headerref boost/pfr/global_flat_ops.hpp] approach]
[*3) [headerref boost/pfr/flat/global_ops.hpp] approach]
This approach is for those, who wish to have comparisong/streaming/hashing for all their types.
```
#include <boost/pfr/global_flat_ops.hpp>
#include <boost/pfr/flat/global_ops.hpp>
struct pair_like {
int first;
@@ -161,22 +178,42 @@ Argument Dependant Lookup works well, `std::less` will find the operators for `s
* Static variables are ignored
* T must be aggregate initializable
C++14 limitations (C++17 fixes those):
[*Flat] functions limitations:
* T must be POD and must not contain references nor bitfields
* T must not contain pointers to user defined types
* Enums will be returned as their underlying type
* All the methods that provide access to filds have a `reinterpret_cast` to an unrelated type. All the possible efforts and compiler scpecific tricks were used to avoid issues. But strictly speaking *this is an Undefined Behavior.
C++14 [*precise] functions limitations (C++17 fixes those):
* T must be constexpr aggregate initializable and all it's fields must be constexpr default constructible
* [funcref boost::pfr::get], [funcref boost::pfr::structure_to_tuple], [funcref boost::pfr::structure_tie], [headerref boost/pfr/precise/core.hpp boost::pfr::tuple_element] require T to be a flat POD type
[endsect]
[section How it works]
Short description:
* at compile-time: uses aggregate initialization to detect fields count in user-provided structure
* at compile-time: makes a structure that is convertible to anything and remeber types it has been converted to during aggregate initialization of user-provided structure
* at compile-time: creates a tuple with exactly the same layout as in user-provided structure
* at run-time: `reinterpret_cast`s pointer to user-provided structure to the tuple pointer => all the tuple methods are available for the structure
* Flat functions:
# at compile-time: use aggregate initialization to detect fields count in user-provided structure
# at compile-time: make a structure that is convertible to anything and remeber types it has been converted to during aggregate initialization of user-provided structure
# at compile-time: create a tuple with exactly the same layout as in user-provided structure
# at run-time: `reinterpret_cast` a pointer to user-provided structure to the tuple pointer (this has no runtime penalty)
# at run-time: a tuple of references to fields is returned => all the tuple methods are available for the structure
* Precise functions:
# at compile-time: use aggregate initialization to detect fields count in user-provided structure
* C++17:
# at compile-time: structured bindings are used to decompose a type `T` to known amount of fields fields
* C++14:
# at compile-time: let `I` be is an index of current field, it equals 0
# at run-time: `T` is constructed and field `I` is aggregate initialized using a separate instance of structure that is convertible to anything [note Additional care is taken to make sure that all the information about `T` is avalable to the compiler and that operations on `T` have no side effects, so the compiler can optimize away the unnecessary temporary objects.]
# at compile-time: `I += 1`
# at compile-time: if `I` does not equal fields count goto step [~b.] from inside of the conversion operator of the structure that is convertible to anything
# at run-time: `reinterpret_cast` pointer to user-provided structure to the tuple pointer (this has no runtime penalty)
# at run-time: a tuple of references to fields is returned => all the tuple methods are available for the structure
Long description: [@https://www.youtube.com/watch?v=abdeAew3gmQ Antony Polukhin: C++14 Reflections Without Macros, Markup nor External Tooling. ].

View File

@@ -8,11 +8,11 @@
//[pfr_example_get
/*`
The following example shows how to access structure fields by index using [funcref boost::pfr::flat_get].
The following example shows how to access structure fields by index using [funcref boost::pfr::get].
Let's define some structure:
*/
#include <boost/pfr/flat/core.hpp>
#include <boost/pfr/precise/core.hpp>
struct foo { // defining structure
int some_integer;
@@ -23,15 +23,15 @@ struct foo { // defining structure
We can access fields of that structure by index:
*/
foo f {777, '!'};
auto& r1 = boost::pfr::flat_get<0>(f); // accessing field with index 0, returns reference to `foo::some_integer`
auto& r2 = boost::pfr::flat_get<1>(f); // accessing field with index 1, returns reference to `foo::c`
auto& r1 = boost::pfr::get<0>(f); // accessing field with index 0, returns reference to `foo::some_integer`
auto& r2 = boost::pfr::get<1>(f); // accessing field with index 1, returns reference to `foo::c`
//] [/pfr_example_get]
//[pfr_example_flat_tuple_size
//[pfr_example_tuple_size
/*`
The following example shows how to count fields using [classref boost::pfr::flat_tuple_size].
The following example shows how to count fields using [classref boost::pfr::tuple_size].
*/
#include <boost/pfr/flat/core.hpp>
#include <boost/pfr/precise/core.hpp>
struct foo2 { // defining structure
int some_integer;
@@ -41,15 +41,15 @@ struct foo2 { // defining structure
static_assert(
boost::pfr::flat_tuple_size<foo2>::value // returns total count of fields in `foo2`
boost::pfr::tuple_size<foo2>::value // returns total count of fields in `foo2`
== 3, ""
);
static_assert(
boost::pfr::flat_tuple_size<int[100]>::value // works with arrays too!
boost::pfr::tuple_size<int[100]>::value // works with arrays too!
== 100, ""
);
//] [/pfr_example_flat_tuple_size]
//] [/pfr_example_tuple_size]
@@ -59,6 +59,7 @@ static_assert(
Take a look at the `struct my_struct`:
*/
#include <boost/pfr/flat/core.hpp>
struct my_struct_nested { short a1; int a2; };

View File

@@ -7,7 +7,7 @@
#define BOOST_PFR_HPP
/// \file boost/pfr.hpp
/// Includes all the Boost.PFR headers, except \xmlonly<link linkend='header.boost.pfr.flat.global_ops_hpp'>boost/pfr/flat/global_ops.hpp</link>\endxmlonly
/// Includes all the Boost.PFR headers, except \xmlonly<link linkend='header.boost.pfr.flat.global_ops_hpp'>boost/pfr/flat/global_ops.hpp</link>\endxmlonly and \xmlonly<link linkend='header.boost.pfr.precise.global_ops_hpp'>boost/pfr/precise/global_ops.hpp</link>\endxmlonly
#include <boost/pfr/precise.hpp>
#include <boost/pfr/flat.hpp>

View File

@@ -3,8 +3,9 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_cast_to_layout_compatible_HPP
#define BOOST_PFR_DETAIL_cast_to_layout_compatible_HPP
#ifndef BOOST_PFR_DETAIL_CAST_TO_LAYOUT_COMPATIBLE_HPP
#define BOOST_PFR_DETAIL_CAST_TO_LAYOUT_COMPATIBLE_HPP
#pragma once
#if __cplusplus < 201402L
# error C++14 is required for this header.
@@ -55,7 +56,6 @@ MAY_ALIAS volatile To& cast_to_layout_compatible(volatile From& val) noexcept {
}
template <class To, class From>
MAY_ALIAS To& cast_to_layout_compatible(From& val) noexcept {
MAY_ALIAS To* const t = reinterpret_cast<To*>( std::addressof(val) );
@@ -75,4 +75,4 @@ MAY_ALIAS std::enable_if_t<std::is_rvalue_reference<From&&>::value, To&&> cast_t
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_cast_to_layout_compatible_HPP
#endif // BOOST_PFR_DETAIL_CAST_TO_LAYOUT_COMPATIBLE_HPP

View File

@@ -5,6 +5,7 @@
#ifndef BOOST_PFR_DETAIL_CORE14_HPP
#define BOOST_PFR_DETAIL_CORE14_HPP
#pragma once
#if __cplusplus < 201402L
# error C++14 is required for this header.
@@ -17,6 +18,7 @@
#include <boost/pfr/detail/cast_to_layout_compatible.hpp>
#include <boost/pfr/detail/fields_count.hpp>
#include <boost/pfr/detail/for_each_field_impl.hpp>
#include <boost/pfr/detail/size_array.hpp>
#ifdef __clang__
# pragma clang diagnostic push
@@ -39,67 +41,6 @@ constexpr T construct_helper() noexcept { // adding const here allows to deal wi
return {};
}
///////////////////// Array that has the constexpr
template <std::size_t N>
struct size_array { // libc++ misses constexpr on operator[]
typedef std::size_t type;
std::size_t data[N];
static constexpr std::size_t size() noexcept { return N; }
constexpr std::size_t count_nonzeros() const noexcept {
std::size_t count = 0;
for (std::size_t i = 0; i < size(); ++i) {
if (data[i]) {
++ count;
}
}
return count;
}
constexpr std::size_t count_from_opening_till_matching_parenthis_seq(std::size_t from, std::size_t opening_parenthis, std::size_t closing_parenthis) const noexcept {
if (data[from] != opening_parenthis) {
return 0;
}
std::size_t unclosed_parnthesis = 0;
std::size_t count = 0;
for (; ; ++from) {
if (data[from] == opening_parenthis) {
++ unclosed_parnthesis;
} else if (data[from] == closing_parenthis) {
-- unclosed_parnthesis;
}
++ count;
if (unclosed_parnthesis == 0) {
return count;
}
}
return count;
}
};
template <>
struct size_array<0> { // libc++ misses constexpr on operator[]
typedef std::size_t type;
std::size_t data[1];
static constexpr std::size_t size() noexcept { return 0; }
constexpr std::size_t count_nonzeros() const noexcept {
return 0;
}
};
template <std::size_t I, std::size_t N>
constexpr std::size_t get(const size_array<N>& a) noexcept {
static_assert(I < N, "Array index out of bounds");
return a.data[I];
}
template <class T> constexpr size_array<sizeof(T) * 3> fields_count_and_type_ids_with_zeros() noexcept;
template <class T> constexpr auto flat_array_of_type_ids() noexcept;
@@ -656,7 +597,7 @@ decltype(auto) tie_as_flat_tuple(T&& val) noexcept {
template <class T>
decltype(auto) as_tuple(T&& val) noexcept {
static_assert(
is_flat_refelectable<T>( std::make_index_sequence<fields_count<T>()>{} ),
is_flat_refelectable<std::remove_reference_t<T>>( std::make_index_sequence<fields_count<T>()>{} ),
"Not possible in C++14 to represent that type without loosing information. Use flat_ version or change type definition"
);
return tie_as_flat_tuple(std::forward<T>(val));
@@ -776,8 +717,6 @@ void for_each_field_dispatcher(T&& t, F&& f, std::index_sequence<I...>) {
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
#undef MAY_ALIAS
#ifdef __clang__
# pragma clang diagnostic pop
#endif

View File

@@ -5,7 +5,6 @@
#ifndef BOOST_PFR_DETAIL_FIELDS_COUNT_HPP
#define BOOST_PFR_DETAIL_FIELDS_COUNT_HPP
#pragma once
#if __cplusplus < 201402L

View File

@@ -0,0 +1,80 @@
// Copyright (c) 2016 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_DETAIL_SIZE_ARRAY_HPP
#define BOOST_PFR_DETAIL_SIZE_ARRAY_HPP
#if __cplusplus < 201402L
# error C++14 is required for this header.
#endif
#include <cstddef> // metaprogramming stuff
namespace boost { namespace pfr { namespace detail {
///////////////////// Array that has the constexpr
template <std::size_t N>
struct size_array { // libc++ misses constexpr on operator[]
typedef std::size_t type;
std::size_t data[N];
static constexpr std::size_t size() noexcept { return N; }
constexpr std::size_t count_nonzeros() const noexcept {
std::size_t count = 0;
for (std::size_t i = 0; i < size(); ++i) {
if (data[i]) {
++ count;
}
}
return count;
}
constexpr std::size_t count_from_opening_till_matching_parenthis_seq(std::size_t from, std::size_t opening_parenthis, std::size_t closing_parenthis) const noexcept {
if (data[from] != opening_parenthis) {
return 0;
}
std::size_t unclosed_parnthesis = 0;
std::size_t count = 0;
for (; ; ++from) {
if (data[from] == opening_parenthis) {
++ unclosed_parnthesis;
} else if (data[from] == closing_parenthis) {
-- unclosed_parnthesis;
}
++ count;
if (unclosed_parnthesis == 0) {
return count;
}
}
return count;
}
};
template <>
struct size_array<0> { // libc++ misses constexpr on operator[]
typedef std::size_t type;
std::size_t data[1];
static constexpr std::size_t size() noexcept { return 0; }
constexpr std::size_t count_nonzeros() const noexcept {
return 0;
}
};
template <std::size_t I, std::size_t N>
constexpr std::size_t get(const size_array<N>& a) noexcept {
static_assert(I < N, "Array index out of bounds");
return a.data[I];
}
}}} // namespace boost::pfr::detail
#endif // BOOST_PFR_DETAIL_SIZE_ARRAY_HPP

View File

@@ -12,6 +12,8 @@
#include <boost/pfr/flat/core.hpp>
#include <boost/pfr/flat/functors.hpp>
#include <boost/pfr/flat/ops.hpp>
#include <boost/pfr/flat/io.hpp>
#include <boost/pfr/flat/tuple_size.hpp>
#include <boost/pfr/flat/functions_for.hpp>
#endif // BOOST_PFR_FLAT_HPP

View File

@@ -14,10 +14,10 @@
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/io.hpp>
#include <boost/pfr/detail/stdtuple.hpp>
#include <boost/pfr/detail/core14.hpp>
#include <boost/pfr/detail/for_each_field_impl.hpp>
#include <boost/pfr/flat/tuple_size.hpp>
namespace boost { namespace pfr {
@@ -65,25 +65,6 @@ template <std::size_t I, class T>
using flat_tuple_element_t = typename flat_tuple_element<I, T>::type;
/// \brief Has a static const member variable `value` that contains fields count in a \flattening{flattened} T.
///
/// \b Example:
/// \code
/// std::array<int, boost::pfr::flat_tuple_size<my_structure>::value > a;
/// \endcode
template <class T>
using flat_tuple_size = boost::pfr::detail::size_t_<decltype(boost::pfr::detail::tie_as_flat_tuple(std::declval<T&>()))::size_v>;
/// \brief `flat_tuple_size_v` is a template variable that contains fields count in a \flattening{flattened} T.
///
/// \b Example:
/// \code
/// std::array<int, boost::pfr::flat_tuple_size_v<my_structure> > a;
/// \endcode
template <class T>
constexpr std::size_t flat_tuple_size_v = flat_tuple_size<T>::value;
/// \brief Creates an `std::tuple` from a \flattening{flattened} T.
///
/// \b Example:
@@ -121,56 +102,22 @@ auto flat_structure_tie(T& val /* @cond */, std::enable_if_t< std::is_trivially_
);
}
/// \brief Writes \flattening{flattened} POD `value` to `out`
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s{12, 13};
/// flat_write(std::cout, s); // outputs '{12, 13}'
/// \endcode
template <class Char, class Traits, class T>
void flat_write(std::basic_ostream<Char, Traits>& out, const T& value) {
out << '{';
detail::print_impl<0, flat_tuple_size_v<T> >::print(out, detail::tie_as_flat_tuple(value));
out << '}';
}
/// Reads \flattening{flattened} POD `value` from stream `in`
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s;
/// std::stringstream ss;
/// ss << "{ 12, 13 }";
/// ss >> s;
/// assert(s.i == 12);
/// assert(s.i == 13);
/// \endcode
template <class Char, class Traits, class T>
void flat_read(std::basic_istream<Char, Traits>& in, T& value) {
const auto prev_exceptions = in.exceptions();
in.exceptions( typename std::basic_istream<Char, Traits>::iostate(0) );
const auto prev_flags = in.flags( typename std::basic_istream<Char, Traits>::fmtflags(0) );
char parenthis = {};
in >> parenthis;
if (parenthis != '{') in.setstate(std::basic_istream<Char, Traits>::failbit);
detail::read_impl<0, flat_tuple_size_v<T> >::read(in, detail::tie_as_flat_tuple(value));
in >> parenthis;
if (parenthis != '}') in.setstate(std::basic_istream<Char, Traits>::failbit);
in.flags(prev_flags);
in.exceptions(prev_exceptions);
}
/// Calls `func` for each field of a \flattening{flattened} POD `value`.
/// `func` must have one of the following signatures:
/// * any_return_type(auto value)
/// * any_return_type(auto value, std::size_t i)
/// * any_return_type(auto value, auto i). Here decltype(i) is an `std::integral_constant<size_t, field_index>`
///
/// \param func must have one of the following signatures:
/// * template <class U> any_return_type func(U&& field) // field of value is perfect forwarded to function
/// * template <class U> any_return_type func(U&& field, std::size_t i)
/// * template <class U, class I> any_return_type func(U&& value, I i) // Here I is an `std::integral_constant<size_t, field_index>`
///
/// \param value After \flattening{flattening} to each field of this variable will be the `func` applied.
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// int sum = 0;
/// for_each_field(my_struct{20, 22}, [&sum](const auto& field) { sum += field; });
/// assert(sum == 42);
/// \endcode
template <class T, class F>
void flat_for_each_field(T&& value, F&& func) {
::boost::pfr::detail::for_each_field_impl(

View File

@@ -3,6 +3,8 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_FUNCTIONS_FOR_HPP
#define BOOST_PFR_FLAT_FUNCTIONS_FOR_HPP
#pragma once
#if __cplusplus < 201402L
@@ -10,6 +12,7 @@
#endif
#include <boost/pfr/flat/functors.hpp>
#include <boost/pfr/flat/io.hpp>
/// \def BOOST_PFR_FLAT_FUNCTIONS_FOR(T)
/// Defines comparison operators and stream operators for T.
@@ -73,4 +76,6 @@
} \
/**/
#endif // BOOST_PFR_FLAT_FUNCTIONS_FOR_HPP

View File

@@ -11,14 +11,16 @@
#endif
#include <boost/pfr/flat/functors.hpp>
#include <boost/pfr/flat/core.hpp>
#include <boost/pfr/flat/io.hpp>
/// \file boost/pfr/global_flat_ops.hpp
/// \file boost/pfr/flat/global_ops.hpp
/// Contains comparison operators and stream operators for any POD types that do not have their own operators.
/// If POD is comparable or streamable using it's own operator (but not it's conversion operator), then the original operator is used.
///
/// \b Example:
/// \code
/// #include <boost/pfr/global_flat_ops.hpp>
/// #include <boost/pfr/flat/global_ops.hpp>
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
@@ -37,7 +39,7 @@
namespace boost { namespace pfr { namespace detail {
template <class T, class U>
using enable_comparisons = std::enable_if_t<
using enable_flat_comparisons = std::enable_if_t<
std::is_same<T, U>::value && std::is_pod<T>::value,
bool
>;
@@ -63,32 +65,32 @@ namespace boost { namespace pfr { namespace detail {
template <class T> std::size_t hash_value(const T& value) noexcept;
#else
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator==(const T& lhs, const U& rhs) noexcept {
static boost::pfr::detail::enable_flat_comparisons<T, U> operator==(const T& lhs, const U& rhs) noexcept {
return ::boost::pfr::flat_equal_to<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator!=(const T& lhs, const U& rhs) noexcept {
static boost::pfr::detail::enable_flat_comparisons<T, U> operator!=(const T& lhs, const U& rhs) noexcept {
return ::boost::pfr::flat_not_equal<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator<(const T& lhs, const U& rhs) noexcept {
static boost::pfr::detail::enable_flat_comparisons<T, U> operator<(const T& lhs, const U& rhs) noexcept {
return ::boost::pfr::flat_less<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator>(const T& lhs, const U& rhs) noexcept {
static boost::pfr::detail::enable_flat_comparisons<T, U> operator>(const T& lhs, const U& rhs) noexcept {
return ::boost::pfr::flat_greater<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator<=(const T& lhs, const U& rhs) noexcept {
static boost::pfr::detail::enable_flat_comparisons<T, U> operator<=(const T& lhs, const U& rhs) noexcept {
return ::boost::pfr::flat_less_equal<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator>=(const T& lhs, const U& rhs) noexcept {
static boost::pfr::detail::enable_flat_comparisons<T, U> operator>=(const T& lhs, const U& rhs) noexcept {
return ::boost::pfr::flat_greater_equal<T>{}(lhs, rhs);
}

View File

@@ -0,0 +1,70 @@
// Copyright (c) 2016 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_IO_HPP
#define BOOST_PFR_FLAT_IO_HPP
#if __cplusplus < 201402L
# error C++14 is required for this header.
#endif
#include <type_traits>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/io.hpp>
#include <boost/pfr/detail/core14.hpp>
#include <boost/pfr/flat/tuple_size.hpp>
namespace boost { namespace pfr {
/// \brief Writes \flattening{flattened} POD `value` to `out`
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s{12, 13};
/// flat_write(std::cout, s); // outputs '{12, 13}'
/// \endcode
template <class Char, class Traits, class T>
void flat_write(std::basic_ostream<Char, Traits>& out, const T& value) {
out << '{';
detail::print_impl<0, flat_tuple_size_v<T> >::print(out, detail::tie_as_flat_tuple(value));
out << '}';
}
/// Reads \flattening{flattened} POD `value` from stream `in`
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s;
/// std::stringstream ss;
/// ss << "{ 12, 13 }";
/// ss >> s;
/// assert(s.i == 12);
/// assert(s.i == 13);
/// \endcode
template <class Char, class Traits, class T>
void flat_read(std::basic_istream<Char, Traits>& in, T& value) {
const auto prev_exceptions = in.exceptions();
in.exceptions( typename std::basic_istream<Char, Traits>::iostate(0) );
const auto prev_flags = in.flags( typename std::basic_istream<Char, Traits>::fmtflags(0) );
char parenthis = {};
in >> parenthis;
if (parenthis != '{') in.setstate(std::basic_istream<Char, Traits>::failbit);
detail::read_impl<0, flat_tuple_size_v<T> >::read(in, detail::tie_as_flat_tuple(value));
in >> parenthis;
if (parenthis != '}') in.setstate(std::basic_istream<Char, Traits>::failbit);
in.flags(prev_flags);
in.exceptions(prev_exceptions);
}
}} // namespace boost::pfr
#endif // BOOST_PFR_FLAT_IO_HPP

View File

@@ -12,6 +12,7 @@
#include <boost/pfr/detail/detectors.hpp>
#include <boost/pfr/flat/functors.hpp>
#include <boost/pfr/flat/io.hpp>
/// \file boost/pfr/flat/ops.hpp
/// Contains comparison operators and stream operators for any POD types that do not have their own operators.

View File

@@ -0,0 +1,41 @@
// Copyright (c) 2016 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_FLAT_TUPLE_SIZE_HPP
#define BOOST_PFR_FLAT_TUPLE_SIZE_HPP
#if __cplusplus < 201402L
# error C++14 is required for this header.
#endif
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/core14.hpp>
namespace boost { namespace pfr {
/// \brief Has a static const member variable `value` that contains fields count in a \flattening{flattened} T.
///
/// \b Example:
/// \code
/// std::array<int, boost::pfr::flat_tuple_size<my_structure>::value > a;
/// \endcode
template <class T>
using flat_tuple_size = boost::pfr::detail::size_t_<decltype(boost::pfr::detail::tie_as_flat_tuple(std::declval<T&>()))::size_v>;
/// \brief `flat_tuple_size_v` is a template variable that contains fields count in a \flattening{flattened} T.
///
/// \b Example:
/// \code
/// std::array<int, boost::pfr::flat_tuple_size_v<my_structure> > a;
/// \endcode
template <class T>
constexpr std::size_t flat_tuple_size_v = flat_tuple_size<T>::value;
}} // namespace boost::pfr
#endif // BOOST_PFR_FLAT_TUPLE_SIZE_HPP

View File

@@ -12,5 +12,8 @@
#include <boost/pfr/precise/core.hpp>
#include <boost/pfr/precise/functors.hpp>
#include <boost/pfr/precise/ops.hpp>
#include <boost/pfr/precise/io.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
#include <boost/pfr/precise/functions_for.hpp>
#endif // BOOST_PFR_PRECISE_HPP

View File

@@ -3,17 +3,17 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_CORE_HPP
#define BOOST_PFR_PRECISE_CORE_HPP
#pragma once
#include <type_traits>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/io.hpp>
#include <boost/pfr/detail/stdtuple.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
#if __cplusplus >= 201606L /* Oulu meeting, not the exact value */
# include <boost/pfr/detail/core17.hpp>
#else
@@ -22,36 +22,9 @@
namespace boost { namespace pfr {
/// \brief Has a static const member variable `value` that constins fields count in a T.
/// Works for any T that supports aggregate initialization even if T is not POD.
/// \flattening{Flattens} only multidimensional arrays.
///
/// \b Requires: C++14.
///
/// \b Example:
/// \code
/// std::array<int, boost::pfr::tuple_size<my_structure>::value > a;
/// \endcode
template <class T>
using tuple_size = detail::size_t_< boost::pfr::detail::fields_count<T>() >;
/// \brief `tuple_size_v` is a template variable that contains fields count in a T and
/// works for any T that supports aggregate initialization even if T is not POD.
/// \flattening{Flattens} only multidimensional arrays.
///
/// \b Requires: C++14.
///
/// \b Example:
/// \code
/// std::array<int, boost::pfr::tuple_size_v<my_structure> > a;
/// \endcode
template <class T>
constexpr std::size_t tuple_size_v = tuple_size<T>::value;
/// \brief Returns reference or const reference to a field with index `I` in aggregate T.
///
/// \b Requires: C++17 or \simplepod{C++14 simple POD}.
/// \b Requires: C++17 or \flatpod{C++14 flat POD}.
///
/// \b Example:
/// \code
@@ -75,7 +48,7 @@ constexpr decltype(auto) get(T& val) noexcept {
/// \brief `tuple_element` has a `typedef type-of-a-field-with-index-I-in-aggregate-T type;`
///
/// \b Requires: C++17 or \simplepod{C++14 simple POD}.
/// \b Requires: C++17 or \flatpod{C++14 flat POD}.
///
/// \b Example:
/// \code
@@ -87,7 +60,7 @@ using tuple_element = typename detail::sequence_tuple::tuple_element<I, detail::
/// \brief Type of a field with index `I` in aggregate `T`.
///
/// \b Requires: C++17 or \simplepod{C++14 simple POD}.
/// \b Requires: C++17 or \flatpod{C++14 flat POD}.
///
/// \b Example:
/// \code
@@ -99,7 +72,7 @@ using tuple_element_t = typename tuple_element<I, T>::type;
/// \brief Creates an `std::tuple` from an aggregate T.
///
/// \b Requires: C++17 or \simplepod{C++14 simple POD}.
/// \b Requires: C++17 or \flatpod{C++14 flat POD}.
///
/// \b Example:
/// \code
@@ -121,7 +94,7 @@ constexpr auto structure_to_tuple(const T& val) noexcept {
/// \brief Creates an `std::tuple` with lvalue references to fields of an aggregate T.
///
/// \b Requires: C++17 or \simplepod{C++14 simple POD}.
/// \b Requires: C++17 or \flatpod{C++14 flat POD}.
///
/// \b Example:
/// \code
@@ -140,85 +113,24 @@ constexpr auto structure_tie(T& val) noexcept {
);
}
/// \brief Writes aggregate `value` to `out`
/// Calls `func` for each field of a `value`.
///
/// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}.
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s{12, 13};
/// write(std::cout, s); // outputs '{12, 13}'
/// \endcode
template <class Char, class Traits, class T>
void write(std::basic_ostream<Char, Traits>& out, const T& value) {
constexpr std::size_t fields_count = detail::fields_count<std::remove_reference_t<T>>();
out << '{';
#if __cplusplus >= 201606L /* Oulu meeting, not the exact value */
detail::print_impl<0, tuple_size_v<T> >::print(out, detail::as_tuple(value));
#else
::boost::pfr::detail::for_each_field_dispatcher(
value,
[&out](const auto& val) {
detail::print_impl<0, fields_count>::print(out, val);
},
std::make_index_sequence<fields_count>{}
);
#endif
out << '}';
}
/// Reads aggregate `value` from stream `in`
/// \param func must have one of the following signatures:
/// * template <class U> any_return_type func(U&& field) // field of value is perfect forwarded to function
/// * template <class U> any_return_type func(U&& field, std::size_t i)
/// * template <class U, class I> any_return_type func(U&& value, I i) // Here I is an `std::integral_constant<size_t, field_index>`
///
/// \b Requires: C++17 or \simplepod{C++14 simple POD}.
/// \param value To each field of this variable will be the `func` applied.
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s;
/// std::stringstream ss;
/// ss << "{ 12, 13 }";
/// ss >> s;
/// assert(s.i == 12);
/// assert(s.i == 13);
/// int sum = 0;
/// for_each_field(my_struct{20, 22}, [&sum](const auto& field) { sum += field; });
/// assert(sum == 42);
/// \endcode
template <class Char, class Traits, class T>
void read(std::basic_istream<Char, Traits>& in, T& value) {
constexpr std::size_t fields_count = detail::fields_count<std::remove_reference_t<T>>();
const auto prev_exceptions = in.exceptions();
in.exceptions( typename std::basic_istream<Char, Traits>::iostate(0) );
const auto prev_flags = in.flags( typename std::basic_istream<Char, Traits>::fmtflags(0) );
char parenthis = {};
in >> parenthis;
if (parenthis != '{') in.setstate(std::basic_istream<Char, Traits>::failbit);
#if __cplusplus >= 201606L /* Oulu meeting, not the exact value */
detail::read_impl<0, tuple_size_v<T> >::read(in, detail::as_tuple(value));
#else
::boost::pfr::detail::for_each_field_dispatcher(
value,
[&in](const auto& val) {
detail::read_impl<0, fields_count>::read(in, val);
},
std::make_index_sequence<fields_count>{}
);
#endif
in >> parenthis;
if (parenthis != '}') in.setstate(std::basic_istream<Char, Traits>::failbit);
in.flags(prev_flags);
in.exceptions(prev_exceptions);
}
/// Calls `func` for each field of a `value`.
/// `func` must have one of the following signatures:
/// * any_return_type(auto value)
/// * any_return_type(auto value, std::size_t i)
/// * any_return_type(auto value, auto i). Here decltype(i) is an `std::integral_constant<size_t, field_index>`
template <class T, class F>
void for_each_field(T&& value, F&& func) {
constexpr std::size_t fields_count = detail::fields_count<std::remove_reference_t<T>>();

View File

@@ -0,0 +1,81 @@
// Copyright (c) 2016 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_FUNCTIONS_FOR_HPP
#define BOOST_PFR_PRECISE_FUNCTIONS_FOR_HPP
#pragma once
#if __cplusplus < 201402L
# error C++14 is required for this header.
#endif
#include <boost/pfr/precise/functors.hpp>
#include <boost/pfr/precise/io.hpp>
/// \def BOOST_PFR_PRECISE_FUNCTIONS_FOR(T)
/// Defines comparison operators and stream operators for T.
/// If type T is comparable or streamable using it's own operator (but not it's conversion operator), then the original operator is used.
///
/// \b Example:
/// \code
/// #include <boost/pfr/precise/functions_for.hpp>
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// BOOST_PFR_PRECISE_FUNCTIONS_FOR(comparable_struct)
/// // ...
///
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
/// assert(s1 < s2);
/// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11}
/// \endcode
///
/// \podops for other ways to define operators and more details.
///
/// \b Defines \b following \b for \b T:
/// \code
/// bool operator==(const T& lhs, const T& rhs);
/// bool operator!=(const T& lhs, const T& rhs);
/// bool operator< (const T& lhs, const T& rhs);
/// bool operator> (const T& lhs, const T& rhs);
/// bool operator<=(const T& lhs, const T& rhs);
/// bool operator>=(const T& lhs, const T& rhs);
///
/// template <class Char, class Traits>
/// std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, const T& value);
///
/// template <class Char, class Traits>
/// std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, T& value);
///
/// // helper function for Boost unordered containers and boost::hash<>.
/// std::size_t hash_value(const T& value);
/// \endcode
#define BOOST_PFR_PRECISE_FUNCTIONS_FOR(T) \
static inline bool operator==(const T& lhs, const T& rhs) { return ::boost::pfr::equal_to<T>{}(lhs, rhs); } \
static inline bool operator!=(const T& lhs, const T& rhs) { return ::boost::pfr::not_equal<T>{}(lhs, rhs); } \
static inline bool operator< (const T& lhs, const T& rhs) { return ::boost::pfr::less<T>{}(lhs, rhs); } \
static inline bool operator> (const T& lhs, const T& rhs) { return ::boost::pfr::greater<T>{}(lhs, rhs); } \
static inline bool operator<=(const T& lhs, const T& rhs) { return ::boost::pfr::less_equal<T>{}(lhs, rhs); } \
static inline bool operator>=(const T& lhs, const T& rhs) { return ::boost::pfr::greater_equal<T>{}(lhs, rhs); } \
template <class Char, class Traits> \
static ::std::basic_ostream<Char, Traits>& operator<<(::std::basic_ostream<Char, Traits>& out, const T& value) { \
::boost::pfr::write(out, value); \
return out; \
} \
template <class Char, class Traits> \
static ::std::basic_istream<Char, Traits>& operator>>(::std::basic_istream<Char, Traits>& in, T& value) { \
::boost::pfr::read(in, value); \
return in; \
} \
static inline std::size_t hash_value(const T& v) { \
return ::boost::pfr::hash<T>{}(v); \
} \
/**/
#endif // BOOST_PFR_PRECISE_FUNCTIONS_FOR_HPP

View File

@@ -18,7 +18,8 @@
/// \file boost/pfr/functors.hpp
/// Contains functors that are close to the Standard Library ones.
/// Each functor iterates over fields of the type.
///
/// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}.
namespace boost { namespace pfr {
namespace detail {

View File

@@ -0,0 +1,115 @@
// Copyright (c) 2016 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_GLOBAL_OPS_HPP
#define BOOST_PFR_PRECISE_GLOBAL_OPS_HPP
#if __cplusplus < 201402L
# error C++14 is required for this header.
#endif
#include <boost/pfr/precise/functors.hpp>
#include <boost/pfr/precise/core.hpp>
#include <boost/pfr/precise/io.hpp>
/// \file boost/pfr/precise/global_ops.hpp
/// Contains comparison operators and stream operators for any types that do not have their own operators.
/// If type is comparable or streamable using it's own operator (but not it's conversion operator), then the original operator is used.
///
/// \b Example:
/// \code
/// #include <boost/pfr/precise/global_ops.hpp>
/// struct comparable_struct { // No operators defined for that structure
/// int i; short s; char data[7]; bool bl; int a,b,c,d,e,f;
/// };
/// // ...
///
/// comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
/// comparable_struct s2 {0, 1, "Hello", false, 6,7,8,9,10,11111};
/// assert(s1 < s2);
/// std::cout << s1 << std::endl; // Outputs: {0, 1, H, e, l, l, o, , , 0, 6, 7, 8, 9, 10, 11}
/// \endcode
///
/// \podops for other ways to define operators and more details.
///
/// \b This \b header \b defines:
/// @cond
namespace boost { namespace pfr { namespace detail {
template <class T, class U>
using enable_comparisons = std::enable_if_t<
std::is_same<T, U>::value,
bool
>;
}}} // namespace boost::pfr::detail
/// @endcond
#ifdef BOOST_PFR_DOXYGEN_INVOKED
template <class T> bool operator==(const T& lhs, const T& rhs);
template <class T> bool operator!=(const T& lhs, const T& rhs);
template <class T> bool operator< (const T& lhs, const T& rhs);
template <class T> bool operator> (const T& lhs, const T& rhs);
template <class T> bool operator<=(const T& lhs, const T& rhs);
template <class T> bool operator>=(const T& lhs, const T& rhs);
template <class Char, class Traits, class T>
std::basic_ostream<Char, Traits>& operator<<(std::basic_ostream<Char, Traits>& out, const T& value);
template <class Char, class Traits, class T>
std::basic_istream<Char, Traits>& operator>>(std::basic_istream<Char, Traits>& in, T& value);
/// \brief helper function for Boost unordered containers and boost::hash<>.
template <class T> std::size_t hash_value(const T& value);
#else
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator==(const T& lhs, const U& rhs) {
return ::boost::pfr::equal_to<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator!=(const T& lhs, const U& rhs) {
return ::boost::pfr::not_equal<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator<(const T& lhs, const U& rhs) {
return ::boost::pfr::less<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator>(const T& lhs, const U& rhs) {
return ::boost::pfr::greater<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator<=(const T& lhs, const U& rhs) {
return ::boost::pfr::less_equal<T>{}(lhs, rhs);
}
template <class T, class U>
static boost::pfr::detail::enable_comparisons<T, U> operator>=(const T& lhs, const U& rhs) {
return ::boost::pfr::greater_equal<T>{}(lhs, rhs);
}
template <class Char, class Traits, class T>
static std::enable_if_t<std::is_pod<T>::value, std::basic_ostream<Char, Traits>&> operator<<(std::basic_ostream<Char, Traits>& out, const T& value) {
::boost::pfr::write(out, value);
return out;
}
template <class Char, class Traits, class T>
static std::enable_if_t<std::is_pod<T>::value, std::basic_istream<Char, Traits>&> operator>>(std::basic_istream<Char, Traits>& in, T& value) {
::boost::pfr::read(in, value);
return in;
}
template <class T>
static std::size_t hash_value(const T& value) {
return ::boost::pfr::hash<T>{}(value);
}
#endif
#endif // BOOST_PFR_PRECISE_GLOBAL_OPS_HPP

View File

@@ -0,0 +1,100 @@
// Copyright (c) 2016 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_IO_HPP
#define BOOST_PFR_PRECISE_IO_HPP
#include <type_traits>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/io.hpp>
#include <boost/pfr/precise/tuple_size.hpp>
#if __cplusplus >= 201606L /* Oulu meeting, not the exact value */
# include <boost/pfr/detail/core17.hpp>
#else
# include <boost/pfr/detail/core14.hpp>
#endif
namespace boost { namespace pfr {
/// \brief Writes aggregate `value` to `out`
///
/// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}.
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s{12, 13};
/// write(std::cout, s); // outputs '{12, 13}'
/// \endcode
template <class Char, class Traits, class T>
void write(std::basic_ostream<Char, Traits>& out, const T& value) {
constexpr std::size_t fields_count = detail::fields_count<std::remove_reference_t<T>>();
out << '{';
#if __cplusplus >= 201606L /* Oulu meeting, not the exact value */
detail::print_impl<0, fields_count>::print(out, detail::as_tuple(value));
#else
::boost::pfr::detail::for_each_field_dispatcher(
value,
[&out](const auto& val) {
detail::print_impl<0, fields_count>::print(out, val);
},
std::make_index_sequence<fields_count>{}
);
#endif
out << '}';
}
/// Reads aggregate `value` from stream `in`
///
/// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}.
///
/// \b Example:
/// \code
/// struct my_struct { int i, short s; };
/// my_struct s;
/// std::stringstream ss;
/// ss << "{ 12, 13 }";
/// ss >> s;
/// assert(s.i == 12);
/// assert(s.i == 13);
/// \endcode
template <class Char, class Traits, class T>
void read(std::basic_istream<Char, Traits>& in, T& value) {
constexpr std::size_t fields_count = detail::fields_count<std::remove_reference_t<T>>();
const auto prev_exceptions = in.exceptions();
in.exceptions( typename std::basic_istream<Char, Traits>::iostate(0) );
const auto prev_flags = in.flags( typename std::basic_istream<Char, Traits>::fmtflags(0) );
char parenthis = {};
in >> parenthis;
if (parenthis != '{') in.setstate(std::basic_istream<Char, Traits>::failbit);
#if __cplusplus >= 201606L /* Oulu meeting, not the exact value */
detail::read_impl<0, fields_count>::read(in, detail::as_tuple(value));
#else
::boost::pfr::detail::for_each_field_dispatcher(
value,
[&in](const auto& val) {
detail::read_impl<0, fields_count>::read(in, val);
},
std::make_index_sequence<fields_count>{}
);
#endif
in >> parenthis;
if (parenthis != '}') in.setstate(std::basic_istream<Char, Traits>::failbit);
in.flags(prev_flags);
in.exceptions(prev_exceptions);
}
}} // namespace boost::pfr
#endif // BOOST_PFR_PRECISE_IO_HPP

View File

@@ -13,6 +13,7 @@
#include <boost/pfr/detail/detectors.hpp>
#include <boost/pfr/precise/functors.hpp>
#include <boost/pfr/precise/core.hpp>
#include <boost/pfr/precise/io.hpp>
/// \file boost/pfr/precise/ops.hpp
/// Contains comparison operators and stream operators for types that do not have their own operators.
@@ -20,6 +21,8 @@
///
/// Just write \b using \b namespace \b ops; and operators will be available in scope.
///
/// \b Requires: C++17 or \constexprinit{C++14 constexpr aggregate intializable type}.
///
/// \b Example:
/// \code
/// #include <boost/pfr/precise/ops.hpp>
@@ -39,7 +42,7 @@
/// \podops for other ways to define operators and more details.
///
/// \b This \b header \b contains:
namespace boost { namespace pfr {
namespace boost { namespace pfr {
namespace detail {

View File

@@ -0,0 +1,47 @@
// Copyright (c) 2016 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_PRECISE_TUPLE_SIZE_HPP
#define BOOST_PFR_PRECISE_TUPLE_SIZE_HPP
#include <type_traits>
#include <utility> // metaprogramming stuff
#include <boost/pfr/detail/sequence_tuple.hpp>
#include <boost/pfr/detail/fields_count.hpp>
namespace boost { namespace pfr {
/// \brief Has a static const member variable `value` that constins fields count in a T.
/// Works for any T that supports aggregate initialization even if T is not POD.
/// \flattening{Flattens} only multidimensional arrays.
///
/// \b Requires: C++14.
///
/// \b Example:
/// \code
/// std::array<int, boost::pfr::tuple_size<my_structure>::value > a;
/// \endcode
template <class T>
using tuple_size = detail::size_t_< boost::pfr::detail::fields_count<T>() >;
/// \brief `tuple_size_v` is a template variable that contains fields count in a T and
/// works for any T that supports aggregate initialization even if T is not POD.
/// \flattening{Flattens} only multidimensional arrays.
///
/// \b Requires: C++14.
///
/// \b Example:
/// \code
/// std::array<int, boost::pfr::tuple_size_v<my_structure> > a;
/// \endcode
template <class T>
constexpr std::size_t tuple_size_v = tuple_size<T>::value;
}} // namespace boost::pfr
#endif // BOOST_PFR_PRECISE_TUPLE_SIZE_HPP

View File

@@ -7,22 +7,26 @@
test-suite pfr
:
[ run common/ops.cpp : : : <define>BOOST_PFR_TEST_FLAT : flat_ops ]
[ run common/ops.cpp : : : <define>BOOST_PFR_TEST_PRECISE : precise_ops ]
[ run common/read_write.cpp : : : <define>BOOST_PFR_TEST_FLAT : flat_read_write ]
[ run common/read_write.cpp : : : <define>BOOST_PFR_TEST_PRECISE : precise_read_write ]
[ run common/ops.cpp : : : <define>BOOST_PFR_TEST_FLAT : flat_ops ]
[ run common/ops.cpp : : : <define>BOOST_PFR_TEST_PRECISE : precise_ops ]
[ run common/global_ops.cpp : : : <define>BOOST_PFR_TEST_FLAT : flat_global_ops ]
[ run common/global_ops.cpp : : : <define>BOOST_PFR_TEST_PRECISE : precise_global_ops ]
[ run common/functions_for.cpp : : : <define>BOOST_PFR_TEST_FLAT : flat_function_for ]
[ run common/functions_for.cpp : : : <define>BOOST_PFR_TEST_PRECISE : precise_function_for ]
[ run common/read_write.cpp : : : <define>BOOST_PFR_TEST_FLAT : flat_read_write ]
[ run common/read_write.cpp : : : <define>BOOST_PFR_TEST_PRECISE : precise_read_write ]
[ run common/std_interactions.cpp : : : <define>BOOST_PFR_TEST_FLAT : flat_std_interactions ]
[ run common/std_interactions.cpp : : : <define>BOOST_PFR_TEST_PRECISE : precise_std_interactions ]
[ run common/test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=char : test_tuple_sizes_on_chars ]
[ run common/test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=int : test_tuple_sizes_on_ints ]
[ run common/test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=short : test_tuple_sizes_on_shorts ]
[ run common/test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=void* : test_tuple_sizes_on_voidptrs ]
[ run common/test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=std::size_t : test_tuple_sizes_on_size_ts ]
[ run common/test_tuple_sizes_on.cpp : : : <define>BOOST_PFR_RUN_TEST_ON=char <define>BOOST_PFR_RUN_HUGE_TESTS : test_tuple_sizes_on_chars_huge ]
[ run flat/core.cpp ]
[ run flat/count_fields_on_chars.cpp ]
[ run flat/count_fields_on_chars.cpp : : : <define>BOOST_PFR_RUN_HUGE_TESTS : count_fields_on_chars_huge ]
[ run flat/count_fields_on_ints.cpp ]
[ run flat/count_fields_on_long_longs.cpp ]
[ run flat/count_fields_on_shorts.cpp ]
[ run flat/count_fields_on_void_ptrs.cpp ]
[ run flat/flat_tuple_size.cpp ]
[ run flat/std_interactions.cpp ]
[ run flat/flat_functions_for.cpp ]
[ run flat/global_flat_ops.cpp ]
[ run flat/flat_motivating_example.cpp ]
[ run flat/flat_for_each_field.cpp ]
[ compile-fail flat/flat_tuple_size_on_non_aggregate.cpp ]

View File

@@ -3,7 +3,16 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifdef BOOST_PFR_TEST_FLAT
#include <boost/pfr/flat/functions_for.hpp>
#define BOOST_PFR_TEST_FUNCTIONS_FOR BOOST_PFR_FLAT_FUNCTIONS_FOR
#endif
#ifdef BOOST_PFR_TEST_PRECISE
#include <boost/pfr/precise/functions_for.hpp>
#define BOOST_PFR_TEST_FUNCTIONS_FOR BOOST_PFR_PRECISE_FUNCTIONS_FOR
#endif
#include <boost/core/lightweight_test.hpp>
#include <iostream>
@@ -28,7 +37,7 @@ struct comparable_struct {
int i; short s; char data[50]; bool bl; int a,b,c,d,e,f;
};
BOOST_PFR_FLAT_FUNCTIONS_FOR(comparable_struct)
BOOST_PFR_TEST_FUNCTIONS_FOR(comparable_struct)
void test_comparable_struct() {
comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
@@ -59,7 +68,7 @@ void test_comparable_struct() {
}
struct empty { operator std::string() { return "empty{}"; } };
BOOST_PFR_FLAT_FUNCTIONS_FOR(empty)
BOOST_PFR_TEST_FUNCTIONS_FOR(empty)
void test_empty_struct() {
BOOST_TEST_EQ(empty{}, empty{});
@@ -67,7 +76,7 @@ void test_empty_struct() {
namespace foo {
struct testing { bool b1, b2; int i; };
BOOST_PFR_FLAT_FUNCTIONS_FOR(testing);
BOOST_PFR_TEST_FUNCTIONS_FOR(testing);
}
template <class Comparator>
@@ -93,7 +102,7 @@ void test_implicit_conversions() {
ss.str("");
ss << empty{};
BOOST_TEST_EQ(ss.str(), "{}"); // Breaks implicit conversion for types marked with BOOST_PFR_FLAT_FUNCTIONS_FOR
BOOST_TEST_EQ(ss.str(), "{}"); // Breaks implicit conversion for types marked with BOOST_PFR_TEST_FUNCTIONS_FOR
}
int main() {

View File

@@ -3,7 +3,16 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifdef BOOST_PFR_TEST_FLAT
#include <boost/pfr/flat/global_ops.hpp>
#endif
#ifdef BOOST_PFR_TEST_PRECISE
#include <boost/pfr/precise/global_ops.hpp>
#endif
#include <boost/core/lightweight_test.hpp>
#include <iostream>

View File

@@ -9,7 +9,7 @@
#ifdef BOOST_PFR_TEST_FLAT
#include <boost/pfr/flat/core.hpp>
#include <boost/pfr/flat/io.hpp>
namespace boost { namespace test {
template <class Char, class Traits, class T>
@@ -26,7 +26,7 @@ namespace boost { namespace test {
#endif
#ifdef BOOST_PFR_TEST_PRECISE
#include <boost/pfr/precise/core.hpp>
#include <boost/pfr/precise/io.hpp>
namespace boost { namespace test {
using boost::pfr::read;
using boost::pfr::write;

View File

@@ -3,13 +3,22 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifdef BOOST_PFR_TEST_FLAT
#include <boost/pfr/flat/core.hpp>
#define BOOST_PFR_TEST_FUNCTION(x) boost::pfr::flat_get<I>(x)
#endif
#ifdef BOOST_PFR_TEST_PRECISE
#include <boost/pfr/precise/core.hpp>
#define BOOST_PFR_TEST_FUNCTION(x) boost::pfr::get<I>(x)
#endif
#include <boost/core/lightweight_test.hpp>
namespace helper {
template <std::size_t I, class T>
decltype(auto) get(T&& v) {
return boost::pfr::flat_get<I>(std::forward<T>(v));
return BOOST_PFR_TEST_FUNCTION(std::forward<T>(v));
}
}

View File

@@ -3,21 +3,21 @@
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#ifndef BOOST_PFR_TEST_TEST_COUNTS_ON_HPP
#define BOOST_PFR_TEST_TEST_COUNTS_ON_HPP
#include <boost/pfr/flat/core.hpp>
#include <boost/pfr/precise/core.hpp>
template <class T1, std::size_t CountInT, std::size_t CountHelpers>
void test_counts_on_multiple_chars_impl_1() {
using namespace boost::pfr;
using boost::pfr::flat_tuple_size_v;
using boost::pfr::tuple_size_v;
struct t1_c { T1 v1; char c[CountHelpers]; };
static_assert(flat_tuple_size_v<t1_c> == CountInT + CountHelpers, "");
struct t1_s { T1 v1; short s[CountHelpers]; };
static_assert(flat_tuple_size_v<t1_s> == CountInT + CountHelpers, "");
struct t1_i { T1 v1; int i[CountHelpers]; };
struct t1_i { T1 v1; const int i[CountHelpers]; };
static_assert(flat_tuple_size_v<t1_i> == CountInT + CountHelpers, "");
struct t1_p { T1 v1; void* p[CountHelpers]; };
@@ -30,7 +30,7 @@ void test_counts_on_multiple_chars_impl_1() {
struct rt1_c { char c[CountHelpers]; T1 v1; };
static_assert(flat_tuple_size_v<rt1_c> == CountInT + CountHelpers, "");
struct rt1_s { short s[CountHelpers]; T1 v1; };
struct rt1_s { const short s[CountHelpers]; T1 v1; };
static_assert(flat_tuple_size_v<rt1_s> == CountInT + CountHelpers, "");
struct rt1_i { int i[CountHelpers]; T1 v1; };
@@ -41,28 +41,41 @@ void test_counts_on_multiple_chars_impl_1() {
struct rt1_ll { long long ll[CountHelpers]; T1 v1; };
static_assert(flat_tuple_size_v<rt1_ll> == CountInT + CountHelpers, "");
struct rt1_ll_1 { rt1_ll v1; };
static_assert(flat_tuple_size_v<rt1_ll_1> == CountInT + CountHelpers, "");
static_assert(tuple_size_v<rt1_ll_1> == 1, "");
}
template <class T1, std::size_t CountInT>
void test_counts_on_multiple_chars_impl() {
using namespace boost::pfr;
using boost::pfr::flat_tuple_size_v;
using boost::pfr::tuple_size_v;
struct t1_0 { T1 v1; };
static_assert(flat_tuple_size_v<t1_0> == CountInT, "");
static_assert(flat_tuple_size_v<T1> == CountInT, "");
static_assert(flat_tuple_size_v<std::conditional_t<std::is_fundamental<T1>::value, T1*, void*> > == 1, "");
static_assert(tuple_size_v<T1*> == 1, "");
struct t1_0_1 { t1_0 t1; };
static_assert(flat_tuple_size_v<t1_0_1> == CountInT, "");
static_assert(tuple_size_v<t1_0_1> == 1, "");
static_assert(flat_tuple_size_v<T1[5]> == CountInT*5, "");
struct t1_0_2 { t1_0 t1; t1_0 t2; };
static_assert(flat_tuple_size_v<t1_0_2> == CountInT * 2, "");
static_assert(tuple_size_v<t1_0_2> == 2, "");
static_assert(flat_tuple_size_v<T1[5]> == CountInT * 5, "");
test_counts_on_multiple_chars_impl_1<T1, CountInT, 1>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 2>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 3>();
#ifdef BOOST_PFR_RUN_HUGE_TESTS
test_counts_on_multiple_chars_impl_1<T1, CountInT, 4>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 5>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 6>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 7>();
#ifdef BOOST_PFR_RUN_HUGE_TESTS
test_counts_on_multiple_chars_impl_1<T1, CountInT, 8>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 9>();
test_counts_on_multiple_chars_impl_1<T1, CountInT, 10>();
@@ -83,9 +96,13 @@ void test_counts_on_multiple_chars_impl() {
template <class T>
void test_counts_on_multiple_chars() {
using boost::pfr::tuple_size_v;
test_counts_on_multiple_chars_impl<T, 1>();
struct t2 { T v1; T v2; };
static_assert(tuple_size_v<t2> == 2, "");
test_counts_on_multiple_chars_impl<t2, 2>();
test_counts_on_multiple_chars_impl<T[2], 2>();
@@ -96,6 +113,9 @@ void test_counts_on_multiple_chars() {
test_counts_on_multiple_chars_impl<t8, 8>();
}
#endif
int main() {
test_counts_on_multiple_chars< BOOST_PFR_RUN_TEST_ON >();
return 0;
}

View File

@@ -1,15 +0,0 @@
// Copyright (c) 2016 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr.hpp>
#include "test_counts_on.hpp"
int main() {
test_counts_on_multiple_chars<char>();
return 0;
}

View File

@@ -1,15 +0,0 @@
// Copyright (c) 2016 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr.hpp>
#include "test_counts_on.hpp"
int main() {
test_counts_on_multiple_chars<int>();
return 0;
}

View File

@@ -1,15 +0,0 @@
// Copyright (c) 2016 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr.hpp>
#include "test_counts_on.hpp"
int main() {
test_counts_on_multiple_chars<long long>();
return 0;
}

View File

@@ -1,15 +0,0 @@
// Copyright (c) 2016 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr.hpp>
#include "test_counts_on.hpp"
int main() {
test_counts_on_multiple_chars<short>();
return 0;
}

View File

@@ -1,15 +0,0 @@
// Copyright (c) 2016 Antony Polukhin
//
// Distributed under the Boost Software License, Version 1.0. (See accompanying
// file LICENSE_1_0.txt or copy at http://www.boost.org/LICENSE_1_0.txt)
#include <boost/pfr.hpp>
#include "test_counts_on.hpp"
int main() {
test_counts_on_multiple_chars<void*>();
return 0;
}