mirror of
https://github.com/boostorg/pfr.git
synced 2026-01-22 17:32:35 +00:00
Compare commits
67 Commits
pre_boost
...
before_pre
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
26fffe6ff0 | ||
|
|
e353fd63f2 | ||
|
|
a277cdac19 | ||
|
|
48b86158f0 | ||
|
|
8e0f27baee | ||
|
|
9c88c56cb3 | ||
|
|
c110bdf0e6 | ||
|
|
5ae2e2fd5f | ||
|
|
7c252b4ca5 | ||
|
|
a144d044df | ||
|
|
558734e7f8 | ||
|
|
940cb1507f | ||
|
|
378acb1fe9 | ||
|
|
c9bc21ed9c | ||
|
|
d6687e5d18 | ||
|
|
b0347fb617 | ||
|
|
ac034a6ef7 | ||
|
|
138a7aff2e | ||
|
|
12940c6ed9 | ||
|
|
282094999e | ||
|
|
72c831cb1a | ||
|
|
3dad4f6271 | ||
|
|
46ca2b70b2 | ||
|
|
558a49daee | ||
|
|
fd381c5dd4 | ||
|
|
313d667664 | ||
|
|
4c2f7fbce4 | ||
|
|
f4126ca464 | ||
|
|
217b4f9d50 | ||
|
|
b5dea7e0c4 | ||
|
|
79a79332ae | ||
|
|
16e28d3c3c | ||
|
|
452e01ff0b | ||
|
|
9fbb780839 | ||
|
|
494a9cf6ca | ||
|
|
67b1b5c06a | ||
|
|
212efb1be0 | ||
|
|
135faf692d | ||
|
|
9ecedfe6ca | ||
|
|
27cd2d78e3 | ||
|
|
7d9dec3b44 | ||
|
|
2751725148 | ||
|
|
4211404f20 | ||
|
|
6ef486f0b7 | ||
|
|
2ca4142e93 | ||
|
|
c9bb66911a | ||
|
|
1b0ae91a52 | ||
|
|
74a1bb1eac | ||
|
|
b9987c70ab | ||
|
|
54f82e9482 | ||
|
|
3ee92b6a14 | ||
|
|
a83f1043f3 | ||
|
|
1405b1ab64 | ||
|
|
2854894a74 | ||
|
|
d78d300380 | ||
|
|
2284d6f703 | ||
|
|
dc585f67fd | ||
|
|
ebd3750681 | ||
|
|
9fb1071862 | ||
|
|
f058b9b771 | ||
|
|
96b0c9b7d7 | ||
|
|
620f9f4f80 | ||
|
|
36d22fe4de | ||
|
|
efe421e982 | ||
|
|
db967a38a8 | ||
|
|
11aa87e21f | ||
|
|
99e3c623f4 |
34
.travis.yml
34
.travis.yml
@@ -7,14 +7,13 @@
|
||||
#
|
||||
# See https://svn.boost.org/trac/boost/wiki/TravisCoverals for description of this file
|
||||
# and how it can be used with Boost libraries.
|
||||
#
|
||||
# File revision #6 modified
|
||||
|
||||
env:
|
||||
matrix:
|
||||
- CXX_STANDARD=c++14 TOOLSET=g++-5
|
||||
- CXX_STANDARD=c++1z TOOLSET=g++-5
|
||||
- CXX_STANDARD=c++14 TOOLSET=clang++-3.7
|
||||
#- CXX_STANDARD=c++1y TOOLSET=clang++
|
||||
#- CXX_STANDARD=c++14 TOOLSET=clang++-3.7
|
||||
|
||||
|
||||
###############################################################################################################
|
||||
@@ -33,13 +32,36 @@ addons:
|
||||
apt:
|
||||
sources:
|
||||
- ubuntu-toolchain-r-test
|
||||
- llvm-toolchain-precise-3.7
|
||||
#- llvm-toolchain-precise-3.7
|
||||
packages:
|
||||
- valgrind
|
||||
- gcc-5
|
||||
- g++-5
|
||||
- clang-3.7
|
||||
#- clang
|
||||
#- clang-3.7
|
||||
|
||||
script:
|
||||
- git clone https://github.com/boostorg/core.git ../boost_core
|
||||
- git clone https://github.com/boostorg/assert.git ../boost_assert
|
||||
- git clone https://github.com/boostorg/config.git ../boost_config
|
||||
- git clone https://github.com/boostorg/functional.git ../boost_functional
|
||||
- git clone https://github.com/boostorg/integer.git ../boost_integer
|
||||
- git clone https://github.com/boostorg/type_traits.git ../boost_tt
|
||||
- git clone https://github.com/boostorg/mpl.git ../boost_mpl
|
||||
- git clone https://github.com/boostorg/detail.git ../boost_detail
|
||||
- git clone https://github.com/boostorg/static_assert.git ../boost_sa
|
||||
- git clone https://github.com/boostorg/preprocessor.git ../boost_preprocessor
|
||||
- INCLUDES="-I../boost_core/include/ -I../boost_config/include/ -I../boost_assert/include/ -I../boost_preprocessor/include/ -I../boost_sa/include/ -I../boost_functional/include/ -I../boost_detail/include/ -I../boost_integer/include/ -I../boost_tt/include/ -I../boost_mpl/include/ -I./include/"
|
||||
# `--coverage` flags required to generate coverage info for Coveralls
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage main.cpp && valgrind ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/core.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/count_fields_on_chars.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/count_fields_on_ints.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/count_fields_on_long_longs.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/count_fields_on_shorts.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/count_fields_on_void_ptrs.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/flat_functions_for.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/global_flat_ops.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/minimal.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/flat_ops.cpp && valgrind ./a.out && rm ./a.out
|
||||
- $TOOLSET -std=$CXX_STANDARD --coverage $INCLUDES test/std_interactions.cpp && valgrind ./a.out && rm ./a.out
|
||||
|
||||
|
||||
156
README.md
156
README.md
@@ -1,170 +1,50 @@
|
||||
#Magic Get [](https://travis-ci.org/apolukhin/magic_get)
|
||||
#POD Flat Reflection (Magic Get) [](https://travis-ci.org/apolukhin/magic_get) [](https://travis-ci.org/apolukhin/magic_get)
|
||||
|
||||
This C++14 library is meant for accessing structure elements by index and providing other std::tuple like methods for user defined POD types.
|
||||
|
||||
|
||||
[Latest documentation](http://apolukhin.github.com/magic_get/index.html)
|
||||
|
||||
[Pre Boost version](https://github.com/apolukhin/magic_get/tree/pre_boost)
|
||||
|
||||
|
||||
### Motivating example
|
||||
```c++
|
||||
#include <iostream>
|
||||
#include "magic_get.hpp"
|
||||
#include "boost/pfr.hpp"
|
||||
|
||||
struct my_struct {
|
||||
struct my_struct { // no ostream operator defined!
|
||||
int i;
|
||||
char c;
|
||||
double d;
|
||||
};
|
||||
|
||||
int main() {
|
||||
my_struct s{100, 'H', 3.141593 };
|
||||
std::cout << "my_struct has " << flat_tuple_size<my_struct>::value << " fields: "
|
||||
<< "{ " << flat_get<0>(s) << ", " << flat_get<1>(s)<< ", " << flat_get<2>(s) << " }\n";
|
||||
using namespace boost::pfr::flat_ops; // for ostream operator out-of-the-box for all PODs!
|
||||
|
||||
my_struct s{100, 'H', 3.141593};
|
||||
std::cout << "my_struct has " << boost::pfr::flat_tuple_size<my_struct>::value
|
||||
<< " fields: " << s << "\n";
|
||||
}
|
||||
|
||||
|
||||
```
|
||||
|
||||
Outputs:
|
||||
```
|
||||
my_struct has 3 fields: { 100, H, 3.14159 }
|
||||
my_struct has 3 fields: {100, H, 3.14159}
|
||||
```
|
||||
|
||||
### Flattening
|
||||
All the methods with prefix `flat_` represent a template parameter type as flat structure without static members:
|
||||
|
||||
```c++
|
||||
// Helper structure.
|
||||
struct my_struct_nested { short a1; int a2; };
|
||||
|
||||
// This structure:
|
||||
struct my_struct {
|
||||
int a0;
|
||||
static const cvalue = 1000;
|
||||
my_struct_nested nested;
|
||||
short a3_a4[2];
|
||||
};
|
||||
|
||||
// will be flattened and represented as:
|
||||
struct my_struct_flat {
|
||||
int a0;
|
||||
short a1;
|
||||
int a2
|
||||
short a3;
|
||||
short a4
|
||||
};
|
||||
```
|
||||
So that
|
||||
* `flat_get<2>(my_struct{})` will return `my_struct::my_struct_nested::a2` field
|
||||
* `flat_get<3>(my_struct{})` will return `my_struct::a3_a4[0]` field
|
||||
|
||||
Same story with arrays:
|
||||
```c++
|
||||
int i[2][2] = {{10, 11}, {12, 13} };
|
||||
assert(flat_get<1>(i) == 11);
|
||||
```
|
||||
|
||||
### API
|
||||
```c++
|
||||
/// Returns const reference to a field with index `I` in flattened `T`.
|
||||
/// Example usage: flat_get<0>(my_structure());
|
||||
template <std::size_t I, class T>
|
||||
decltype(auto) flat_get(const T& val) noexcept;
|
||||
|
||||
|
||||
/// Returns reference to a field with index `I` in flattened `T`.
|
||||
/// Requires: `T` must not have const fields.
|
||||
/// Example usage: flat_get<0>(my_structure());
|
||||
template <std::size_t I, class T>
|
||||
decltype(auto) flat_get(T& val, typename std::enable_if< std::is_trivially_assignable<T, T>::value>::type* = 0);
|
||||
|
||||
|
||||
/// `flat_tuple_element` has a `typedef type-of-a-field-with-index-I-in-flattened-T type;`
|
||||
/// Example usage: std::vector< flat_tuple_element<0, my_structure>::type > v;
|
||||
template <std::size_t I, class T>
|
||||
using flat_tuple_element;
|
||||
|
||||
|
||||
/// Type of a field with index `I` in flattened `T`
|
||||
/// Example usage: std::vector< flat_tuple_element_t<0, my_structure> > v;
|
||||
template <std::size_t I, class T>
|
||||
using flat_tuple_element_t = typename flat_tuple_element<I, T>::type;
|
||||
|
||||
|
||||
/// `flat_tuple_size` has a member `value` that constins fields count in a flattened `T`.
|
||||
/// Example usage: std::array<int, flat_tuple_size<my_structure>::value > a;
|
||||
template <class T>
|
||||
using flat_tuple_size;
|
||||
|
||||
|
||||
/// `flat_tuple_size_v` is a template variable that constins fields count in a flattened `T`.
|
||||
/// Example usage: std::array<int, flat_tuple_size_v<my_structure> > a;
|
||||
template <class T>
|
||||
constexpr std::size_t flat_tuple_size_v = flat_tuple_size<T>::value;
|
||||
|
||||
|
||||
/// Creates an `std::tuple` from a flattened T.
|
||||
/// Example usage:
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// my_struct s {10, 11};
|
||||
/// std::tuple<int, short> t = flat_to_tuple(s);
|
||||
/// assert(get<0>(t) == 10);
|
||||
template <class T>
|
||||
auto flat_make_tuple(const T& val) noexcept;
|
||||
|
||||
|
||||
/// Creates an `std::tuple` with lvalue references to fields of a flattened T.
|
||||
/// Example usage:
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// my_struct s;
|
||||
/// flat_tie(s) = std::tuple<int, short>{10, 11};
|
||||
/// assert(s.s == 11);
|
||||
template <class T>
|
||||
auto flat_tie(T& val, typename std::enable_if< std::is_trivially_assignable<T, T>::value>::type* = 0 ) noexcept;
|
||||
|
||||
|
||||
/// Writes to `out` POD `value`
|
||||
/// Example usage:
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// my_struct s{12, 13};
|
||||
/// flat_write(std::cout, s); // outputs '{12, 13}'
|
||||
template <class Char, class Traits, class T>
|
||||
void flat_write(std::basic_ostream<Char, Traits>& out, const T& value);
|
||||
|
||||
|
||||
/// Reads POD `value` from stream `in`
|
||||
/// Example usage:
|
||||
/// 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);
|
||||
template <class Char, class Traits, class T>
|
||||
void flat_read(std::basic_istream<Char, Traits>& in, T& value);
|
||||
|
||||
|
||||
/// Contains comparison operators and stream operators for any POD types that does not have it's own operators.
|
||||
/// If POD is comparable or streamable using it's own operator or it's conversion operator, then the original operator is be used.
|
||||
///
|
||||
/// Example usage:
|
||||
/// 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;
|
||||
/// };
|
||||
/// using namespace pod_ops;
|
||||
///
|
||||
/// 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}
|
||||
namespace pod_ops;
|
||||
```
|
||||
|
||||
### Requirements and Limitations
|
||||
|
||||
* C++14 compatible compiler (GCC-5.0+, Clang, ...)
|
||||
* Static variables are ignored
|
||||
|
||||
C++14 limitations (C++17 fixes those):
|
||||
* 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
|
||||
* Static variables are ignored
|
||||
|
||||
### License
|
||||
|
||||
|
||||
41
doc/Jamfile.v2
Normal file
41
doc/Jamfile.v2
Normal file
@@ -0,0 +1,41 @@
|
||||
# Copyright Antony Polukhin 2016.
|
||||
# Use, modification, and distribution are
|
||||
# subject to 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)
|
||||
|
||||
using quickbook ;
|
||||
using boostbook ;
|
||||
using doxygen ;
|
||||
|
||||
doxygen autodoc
|
||||
:
|
||||
[ glob ../../../boost/pfr.hpp ]
|
||||
[ glob ../../../boost/pfr/*.hpp ]
|
||||
:
|
||||
<doxygen:param>EXTRACT_ALL=NO
|
||||
<doxygen:param>HIDE_UNDOC_MEMBERS=YES
|
||||
<doxygen:param>EXTRACT_PRIVATE=NO
|
||||
<doxygen:param>ENABLE_PREPROCESSING=YES
|
||||
<doxygen:param>EXPAND_ONLY_PREDEF=YES
|
||||
<doxygen:param>MACRO_EXPANSION=YES
|
||||
<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\" \\
|
||||
"
|
||||
<doxygen:param>"PREDEFINED=\"BOOST_PFR_DOXYGEN_INVOKED\" \\
|
||||
\"detail::stl_type_info=std::type_info\""
|
||||
<xsl:param>"boost.doxygen.reftitle=Boost.PFR Header Reference"
|
||||
;
|
||||
|
||||
xml pfr : pfr.qbk : <dependency>autodoc ;
|
||||
boostbook standalone
|
||||
:
|
||||
pfr
|
||||
:
|
||||
<xsl:param>boost.root=http://www.boost.org/doc/libs/1_61_0
|
||||
# <xsl:param>boost.root=../../../..
|
||||
<format>pdf:<xsl:param>boost.url.prefix=http://www.boost.org/doc/libs/release/doc/html
|
||||
;
|
||||
|
||||
185
doc/pfr.qbk
Normal file
185
doc/pfr.qbk
Normal file
@@ -0,0 +1,185 @@
|
||||
[library Boost.POD Flat Reflection
|
||||
[quickbook 1.6]
|
||||
[version 1.0]
|
||||
[copyright 2016 Antony Polukhin]
|
||||
[category Language Features Emulation]
|
||||
[license
|
||||
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])
|
||||
]
|
||||
]
|
||||
|
||||
[section Motivation]
|
||||
|
||||
In C++ we have:
|
||||
|
||||
* tuples - types that provide access to members by index. Those are useful for generic programming.
|
||||
* PODs - types with named fields that do not provide access to members by index. Those are just easy to use.
|
||||
|
||||
This library provides tuple like methods for POD types, making PODs usable in contexts were only tuples were useful.
|
||||
|
||||
[note All you have to do is to add `#include <boost/pfr.hpp>`.
|
||||
|
||||
No macro or other type/member registrations required.]
|
||||
|
||||
Boost.POD Flat Reflection (Boost.PFR) adds following out-of-the-box functionality to PODs:
|
||||
|
||||
* comparison operators
|
||||
* heterogeneous comparators
|
||||
* hash
|
||||
* stream operators
|
||||
* access to members by index
|
||||
* member reflections
|
||||
* methods for cooperation with `std::tuple`
|
||||
|
||||
[warning This is not an official Boost library! It wasn't reviewed and can't be downloaded from www.boost.org. This library is available to the community to know real interest and get comments for refinement. The intention is to submit library to formal review, if community think that it is interesting!]
|
||||
|
||||
[caution This is a C++14 library! Pre C++14 compilers (C++11, C++03...) are not supported]
|
||||
|
||||
[endsect]
|
||||
|
||||
[section Quick Start]
|
||||
|
||||
[import ../example/examples.cpp]
|
||||
|
||||
[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 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.
|
||||
|
||||
[table:flat_ops_comp Different approaches for operators
|
||||
[[ Approach ] [ Defines operators in global namespace ]
|
||||
[ Defined operators could be found by ADL ]
|
||||
[ Works for local types ]
|
||||
[ 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 ] ]
|
||||
]
|
||||
|
||||
More detailed description:
|
||||
|
||||
[*1) [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>
|
||||
|
||||
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.
|
||||
return lhs < rhs; // If T has operator< or conversion operator then will use it, otherwise will use boost::pfr::flat_less<T>.
|
||||
}
|
||||
};
|
||||
```
|
||||
This method's effects are local to the function. It works even for local types, like structures defined in functions.
|
||||
However *Argument Dependant Lookup* does not work with it:
|
||||
|
||||
```
|
||||
#include <boost/pfr/flat_ops.hpp>
|
||||
template <class T>
|
||||
struct uniform_comparator_less {
|
||||
bool operator()(const T& lhs, const T& rhs) const noexcept {
|
||||
using namespace flat_ops;
|
||||
return std::less{}(lhs, rhs); // Compile time error if T has neither operator< nor conversion operator to comparable type.
|
||||
}
|
||||
};
|
||||
```
|
||||
|
||||
[*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>
|
||||
|
||||
struct pair_like {
|
||||
int first;
|
||||
short second;
|
||||
};
|
||||
|
||||
BOOST_PFR_FLAT_FUNCTIONS_FOR(pair_like) // Defines operators
|
||||
|
||||
// ...
|
||||
|
||||
assert(pair_like{1, 2} < pair_like{1, 3});
|
||||
```
|
||||
Argument Dependant Lookup works well, `std::less` will find the operators for `struct pair_like`. [macroref BOOST_PFR_FLAT_FUNCTIONS_FOR BOOST_PFR_FLAT_FUNCTIONS_FOR(T)]
|
||||
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>
|
||||
|
||||
struct empty {
|
||||
operator std::string() { return "empty{}"; }
|
||||
};
|
||||
// Uncomment to get different output:
|
||||
// BOOST_PFR_FLAT_FUNCTIONS_FOR(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]
|
||||
|
||||
This approach is for those, who wish to have comparisong/streaming/hashing for all their types.
|
||||
|
||||
```
|
||||
#include <boost/pfr/global_flat_ops.hpp>
|
||||
|
||||
struct pair_like {
|
||||
int first;
|
||||
short second;
|
||||
};
|
||||
|
||||
// ...
|
||||
|
||||
assert(pair_like{1, 2} < pair_like{1, 3});
|
||||
```
|
||||
Argument Dependant Lookup works well, `std::less` will find the operators for `struct pair_like`. Operators for local types will be also defined.
|
||||
*All conversion operators of all POD types won't be used during comparisons/streaming/hashing.*
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
|
||||
|
||||
[endsect]
|
||||
|
||||
|
||||
[section Requirements and Limitations]
|
||||
|
||||
[note Boost.PFR does not depend on any Boost library. You may use it's headers even without Boost. ]
|
||||
|
||||
* Boost.PFR *requires C++14 compatible compiler* (GCC-5.0+, Clang, ...)
|
||||
* Static variables are ignored
|
||||
* T must be aggregate initializable
|
||||
|
||||
C++14 limitations (C++17 fixes those):
|
||||
* 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.
|
||||
|
||||
[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
|
||||
|
||||
Long description: [@https://www.youtube.com/watch?v=abdeAew3gmQ Antony Polukhin: C++14 Reflections Without Macros, Markup nor External Tooling. ].
|
||||
|
||||
[endsect]
|
||||
|
||||
[xinclude autodoc.xml]
|
||||
102
example/examples.cpp
Normal file
102
example/examples.cpp
Normal file
@@ -0,0 +1,102 @@
|
||||
// Copyright 2016 Antony Polukhin
|
||||
|
||||
// Distributed under the Boost Software License, Version 1.0.
|
||||
// (See the accompanying file LICENSE_1_0.txt
|
||||
// or a copy at <http://www.boost.org/LICENSE_1_0.txt>.)
|
||||
|
||||
#include <cassert>
|
||||
|
||||
//[pfr_example_get
|
||||
/*`
|
||||
The following example shows how to access structure fields by index using [funcref boost::pfr::flat_get].
|
||||
|
||||
Let's define some structure:
|
||||
*/
|
||||
#include <boost/pfr/core.hpp>
|
||||
|
||||
struct foo { // defining structure
|
||||
int some_integer;
|
||||
char c;
|
||||
};
|
||||
|
||||
/*`
|
||||
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`
|
||||
//] [/pfr_example_get]
|
||||
|
||||
//[pfr_example_flat_tuple_size
|
||||
/*`
|
||||
The following example shows how to count fields using [classref boost::pfr::flat_tuple_size].
|
||||
*/
|
||||
#include <boost/pfr/core.hpp>
|
||||
|
||||
struct foo2 { // defining structure
|
||||
int some_integer;
|
||||
char c;
|
||||
short some_other_field;
|
||||
};
|
||||
|
||||
|
||||
static_assert(
|
||||
boost::pfr::flat_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!
|
||||
== 100, ""
|
||||
);
|
||||
//] [/pfr_example_flat_tuple_size]
|
||||
|
||||
|
||||
|
||||
//[pfr_example_flattening
|
||||
/*`
|
||||
[warning All the functions and metafunctions in Boost.PFR that start with `flat_` represent template parameter type as flat structure without static members! ]
|
||||
|
||||
Take a look at the `struct my_struct`:
|
||||
*/
|
||||
|
||||
struct my_struct_nested { short a1; int a2; };
|
||||
|
||||
struct my_struct {
|
||||
int a0;
|
||||
static const int cvalue = 1000;
|
||||
my_struct_nested nested;
|
||||
short a3_a4[2];
|
||||
};
|
||||
|
||||
/*` It will be flattened and represented as: */
|
||||
|
||||
struct my_struct_flat {
|
||||
int a0;
|
||||
short a1;
|
||||
int a2;
|
||||
short a3;
|
||||
short a4;
|
||||
};
|
||||
//] [/pfr_example_flattening]
|
||||
|
||||
void example_get() {
|
||||
//[pfr_example_flattening_2
|
||||
/*`
|
||||
It means, that:
|
||||
*/
|
||||
boost::pfr::flat_get<2>(my_struct{}); // ... will return `my_struct::my_struct_nested::a2` field.
|
||||
boost::pfr::flat_get<3>(my_struct{}); // ... will return `my_struct::a3_a4[0]` field.
|
||||
|
||||
/*` Exactly the same story with arrays: */
|
||||
|
||||
int i[2][2] = {{10, 11}, {12, 13} };
|
||||
const int& r = boost::pfr::flat_get<1>(i);
|
||||
assert(r == 11);
|
||||
//] [/pfr_example_flattening_2]
|
||||
(void)r;
|
||||
}
|
||||
|
||||
int main() {
|
||||
example_get();
|
||||
}
|
||||
16
include/boost/pfr.hpp
Normal file
16
include/boost/pfr.hpp
Normal file
@@ -0,0 +1,16 @@
|
||||
// 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)
|
||||
|
||||
#pragma once
|
||||
|
||||
/// \file boost/pfr.hpp
|
||||
/// Includes all the Boost.PFR headers, except \xmlonly<link linkend='header.boost.pfr.global_flat_ops_hpp'>boost/pfr/global_flat_ops.hpp</link>\endxmlonly
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
//#include <boost/pfr/core17.hpp>
|
||||
#include <boost/pfr/functors.hpp>
|
||||
#include <boost/pfr/flat_ops.hpp>
|
||||
#include <boost/pfr/flat_functions_for.hpp>
|
||||
|
||||
993
include/boost/pfr/core.hpp
Normal file
993
include/boost/pfr/core.hpp
Normal file
@@ -0,0 +1,993 @@
|
||||
// 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_CORE_HPP
|
||||
#define BOOST_PFR_CORE_HPP
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus < 201402L
|
||||
# error C++14 is required for this header.
|
||||
#endif
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility> // metaprogramming stuff
|
||||
#include <tuple>
|
||||
#include <iosfwd> // stream operators
|
||||
|
||||
#include <boost/pfr/fields_count.hpp>
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wmissing-braces"
|
||||
# pragma clang diagnostic ignored "-Wundefined-inline"
|
||||
# pragma clang diagnostic ignored "-Wundefined-internal"
|
||||
# pragma clang diagnostic ignored "-Wmissing-field-initializers"
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
namespace detail {
|
||||
|
||||
///////////////////// General utility stuff
|
||||
|
||||
template <class T> struct identity{
|
||||
typedef T type;
|
||||
};
|
||||
|
||||
template <class T>
|
||||
constexpr T construct_helper() noexcept { // adding const here allows to deal with copyable only types
|
||||
return {};
|
||||
}
|
||||
|
||||
|
||||
///////////////////// Tuple that holds it's values in the supplied order
|
||||
namespace sequence_tuple {
|
||||
|
||||
|
||||
template <std::size_t N, class T>
|
||||
struct base_from_member {
|
||||
T value;
|
||||
};
|
||||
|
||||
template <class I, class ...Tail>
|
||||
struct tuple_base;
|
||||
|
||||
|
||||
|
||||
template <std::size_t... I, class ...Tail>
|
||||
struct tuple_base< std::index_sequence<I...>, Tail... >
|
||||
: base_from_member<I , Tail>...
|
||||
{
|
||||
static constexpr std::size_t size_v = sizeof...(I);
|
||||
|
||||
constexpr tuple_base() noexcept = default;
|
||||
constexpr tuple_base(tuple_base&&) noexcept = default;
|
||||
constexpr tuple_base(const tuple_base&) noexcept = default;
|
||||
|
||||
constexpr tuple_base(Tail... v) noexcept
|
||||
: base_from_member<I, Tail>{ v }...
|
||||
{}
|
||||
};
|
||||
|
||||
template <>
|
||||
struct tuple_base<std::index_sequence<> > {
|
||||
static constexpr std::size_t size_v = 0;
|
||||
};
|
||||
|
||||
template <std::size_t N, class T>
|
||||
constexpr T& get_impl(base_from_member<N, T>& t) noexcept {
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <std::size_t N, class T>
|
||||
constexpr const T& get_impl(const base_from_member<N, T>& t) noexcept {
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <std::size_t N, class T>
|
||||
constexpr volatile T& get_impl(volatile base_from_member<N, T>& t) noexcept {
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <std::size_t N, class T>
|
||||
constexpr const volatile T& get_impl(const volatile base_from_member<N, T>& t) noexcept {
|
||||
return t.value;
|
||||
}
|
||||
|
||||
template <std::size_t N, class T>
|
||||
constexpr T&& get_impl(base_from_member<N, T>&& t) noexcept {
|
||||
return std::forward<T>(t.value);
|
||||
}
|
||||
|
||||
|
||||
template <class ...Values>
|
||||
struct tuple: tuple_base<
|
||||
std::make_index_sequence<sizeof...(Values)>,
|
||||
Values...>
|
||||
{
|
||||
using tuple_base<
|
||||
std::make_index_sequence<sizeof...(Values)>,
|
||||
Values...
|
||||
>::tuple_base;
|
||||
};
|
||||
|
||||
|
||||
template <std::size_t N, class ...T>
|
||||
constexpr decltype(auto) get(tuple<T...>& t) noexcept {
|
||||
static_assert(N < tuple<T...>::size_v, "Tuple index out of bounds");
|
||||
return get_impl<N>(t);
|
||||
}
|
||||
|
||||
template <std::size_t N, class ...T>
|
||||
constexpr decltype(auto) get(const tuple<T...>& t) noexcept {
|
||||
static_assert(N < tuple<T...>::size_v, "Tuple index out of bounds");
|
||||
return get_impl<N>(t);
|
||||
}
|
||||
|
||||
template <std::size_t N, class ...T>
|
||||
constexpr decltype(auto) get(const volatile tuple<T...>& t) noexcept {
|
||||
static_assert(N < tuple<T...>::size_v, "Tuple index out of bounds");
|
||||
return get_impl<N>(t);
|
||||
}
|
||||
|
||||
template <std::size_t N, class ...T>
|
||||
constexpr decltype(auto) get(volatile tuple<T...>& t) noexcept {
|
||||
static_assert(N < tuple<T...>::size_v, "Tuple index out of bounds");
|
||||
return get_impl<N>(t);
|
||||
}
|
||||
|
||||
template <std::size_t N, class ...T>
|
||||
constexpr decltype(auto) get(tuple<T...>&& t) noexcept {
|
||||
static_assert(N < tuple<T...>::size_v, "Tuple index out of bounds");
|
||||
return get_impl<N>(std::move(t));
|
||||
}
|
||||
|
||||
template <size_t I, class T>
|
||||
using tuple_element = std::remove_reference< decltype(
|
||||
::boost::pfr::detail::sequence_tuple::get<I>( std::declval<T>() )
|
||||
) >;
|
||||
|
||||
|
||||
} // namespace sequence_tuple
|
||||
|
||||
|
||||
template <std::size_t I, std::size_t N>
|
||||
struct print_impl {
|
||||
template <class Stream, class T>
|
||||
static void print (Stream& out, const T& value) {
|
||||
if (!!I) out << ", ";
|
||||
out << boost::pfr::detail::sequence_tuple::get<I>(value);
|
||||
print_impl<I + 1, N>::print(out, value);
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t I>
|
||||
struct print_impl<I, I> {
|
||||
template <class Stream, class T> static void print (Stream&, const T&) noexcept {}
|
||||
};
|
||||
|
||||
|
||||
template <std::size_t I, std::size_t N>
|
||||
struct read_impl {
|
||||
template <class Stream, class T>
|
||||
static void read (Stream& in, const T& value) {
|
||||
char ignore = {};
|
||||
if (!!I) {
|
||||
in >> ignore;
|
||||
if (ignore != ',') in.setstate(Stream::failbit);
|
||||
in >> ignore;
|
||||
if (ignore != ' ') in.setstate(Stream::failbit);
|
||||
}
|
||||
in >> boost::pfr::detail::sequence_tuple::get<I>(value);
|
||||
read_impl<I + 1, N>::read(in, value);
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t I>
|
||||
struct read_impl<I, I> {
|
||||
template <class Stream, class T> static void read (Stream&, const T&) {}
|
||||
};
|
||||
|
||||
|
||||
///////////////////// 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;
|
||||
|
||||
///////////////////// All the stuff for representing Type as integer and converting integer back to type
|
||||
namespace typeid_conversions {
|
||||
|
||||
///////////////////// Helper constants and typedefs
|
||||
constexpr std::size_t native_types_mask = 31;
|
||||
constexpr std::size_t bits_per_extension = 3;
|
||||
constexpr std::size_t extension_maks = (
|
||||
static_cast<std::size_t>((1 << bits_per_extension) - 1)
|
||||
<< static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
|
||||
);
|
||||
constexpr std::size_t native_ptr_type = (
|
||||
static_cast<std::size_t>(1)
|
||||
<< static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
|
||||
);
|
||||
constexpr std::size_t native_const_ptr_type = (
|
||||
static_cast<std::size_t>(2)
|
||||
<< static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
|
||||
);
|
||||
|
||||
constexpr std::size_t native_const_volatile_ptr_type = (
|
||||
static_cast<std::size_t>(3)
|
||||
<< static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
|
||||
);
|
||||
|
||||
constexpr std::size_t native_volatile_ptr_type = (
|
||||
static_cast<std::size_t>(4)
|
||||
<< static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
|
||||
);
|
||||
|
||||
constexpr std::size_t native_ref_type = (
|
||||
static_cast<std::size_t>(5)
|
||||
<< static_cast<std::size_t>(sizeof(std::size_t) * 8 - bits_per_extension)
|
||||
);
|
||||
|
||||
template <std::size_t Index, std::size_t Extension>
|
||||
using if_extension = std::enable_if_t< (Index & extension_maks) == Extension >*;
|
||||
|
||||
///////////////////// Helper functions
|
||||
template <std::size_t Unptr>
|
||||
constexpr std::size_t type_to_id_extension_apply(std::size_t ext) noexcept {
|
||||
constexpr std::size_t native_id = (Unptr & native_types_mask);
|
||||
constexpr std::size_t extensions = (Unptr & ~native_types_mask);
|
||||
static_assert(
|
||||
!((extensions >> bits_per_extension) & native_types_mask),
|
||||
"Too many extensions for a single field (something close to `int************************** p;` is in the POD type)."
|
||||
);
|
||||
|
||||
return (extensions >> bits_per_extension) | native_id | ext;
|
||||
}
|
||||
|
||||
template <std::size_t Index>
|
||||
using remove_1_ext = size_t_<
|
||||
((Index & ~native_types_mask) << bits_per_extension) | (Index & native_types_mask)
|
||||
>;
|
||||
|
||||
|
||||
///////////////////// Forward declarations
|
||||
|
||||
template <class Type> constexpr std::size_t type_to_id(identity<Type*>) noexcept;
|
||||
template <class Type> constexpr std::size_t type_to_id(identity<const Type*>) noexcept;
|
||||
template <class Type> constexpr std::size_t type_to_id(identity<const volatile Type*>) noexcept;
|
||||
template <class Type> constexpr std::size_t type_to_id(identity<volatile Type*>) noexcept;
|
||||
template <class Type> constexpr std::size_t type_to_id(identity<Type&>) noexcept;
|
||||
template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_enum<Type>::value>* = 0) noexcept;
|
||||
template <class Type> constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_empty<Type>::value>* = 0) noexcept;
|
||||
template <class Type> constexpr size_array<sizeof(Type) * 3> type_to_id(identity<Type>, std::enable_if_t<!std::is_enum<Type>::value && !std::is_empty<Type>::value>* = 0) noexcept;
|
||||
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_ptr_type> = 0) noexcept;
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ptr_type> = 0) noexcept;
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_volatile_ptr_type> = 0) noexcept;
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_volatile_ptr_type> = 0) noexcept;
|
||||
template <std::size_t Index> constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ref_type> = 0) noexcept;
|
||||
|
||||
|
||||
///////////////////// Definitions of type_to_id and id_to_type for fundamental types
|
||||
/// @cond
|
||||
#define BOOST_MAGIC_GET_REGISTER_TYPE(Type, Index) \
|
||||
constexpr std::size_t type_to_id(identity<Type>) noexcept { \
|
||||
return Index; \
|
||||
} \
|
||||
constexpr Type id_to_type( size_t_<Index > ) noexcept { \
|
||||
return construct_helper<Type>(); \
|
||||
} \
|
||||
/**/
|
||||
/// @endcond
|
||||
|
||||
|
||||
// Register all base types here
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(unsigned char , 1)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(unsigned short , 2)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(unsigned int , 3)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(unsigned long , 4)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(unsigned long long , 5)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(signed char , 6)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(short , 7)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(int , 8)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(long , 9)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(long long , 10)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(char , 11)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(wchar_t , 12)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(char16_t , 13)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(char32_t , 14)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(float , 15)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(double , 16)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(long double , 17)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(bool , 18)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(void* , 19)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(const void* , 20)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(volatile void* , 21)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(const volatile void* , 22)
|
||||
BOOST_MAGIC_GET_REGISTER_TYPE(std::nullptr_t , 23)
|
||||
constexpr std::size_t tuple_begin_tag = 24;
|
||||
constexpr std::size_t tuple_end_tag = 25;
|
||||
|
||||
#undef BOOST_MAGIC_GET_REGISTER_TYPE
|
||||
|
||||
///////////////////// Definitions of type_to_id and id_to_type for types with extensions and nested types
|
||||
template <class Type>
|
||||
constexpr std::size_t type_to_id(identity<Type*>) noexcept {
|
||||
constexpr auto unptr = type_to_id(identity<Type>{});
|
||||
static_assert(
|
||||
std::is_same<const std::size_t, decltype(unptr)>::value,
|
||||
"Pointers to user defined types are not supported."
|
||||
);
|
||||
return type_to_id_extension_apply<unptr>(native_ptr_type);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
constexpr std::size_t type_to_id(identity<const Type*>) noexcept {
|
||||
constexpr auto unptr = type_to_id(identity<Type>{});
|
||||
static_assert(
|
||||
std::is_same<const std::size_t, decltype(unptr)>::value,
|
||||
"Const pointers to user defined types are not supported."
|
||||
);
|
||||
return type_to_id_extension_apply<unptr>(native_const_ptr_type);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
constexpr std::size_t type_to_id(identity<const volatile Type*>) noexcept {
|
||||
constexpr auto unptr = type_to_id(identity<Type>{});
|
||||
static_assert(
|
||||
std::is_same<const std::size_t, decltype(unptr)>::value,
|
||||
"Const volatile pointers to user defined types are not supported."
|
||||
);
|
||||
return type_to_id_extension_apply<unptr>(native_const_volatile_ptr_type);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
constexpr std::size_t type_to_id(identity<volatile Type*>) noexcept {
|
||||
constexpr auto unptr = type_to_id(identity<Type>{});
|
||||
static_assert(
|
||||
std::is_same<const std::size_t, decltype(unptr)>::value,
|
||||
"Volatile pointers to user defined types are not supported."
|
||||
);
|
||||
return type_to_id_extension_apply<unptr>(native_volatile_ptr_type);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
constexpr std::size_t type_to_id(identity<Type&>) noexcept {
|
||||
constexpr auto unptr = type_to_id(identity<Type>{});
|
||||
static_assert(
|
||||
std::is_same<const std::size_t, decltype(unptr)>::value,
|
||||
"References to user defined types are not supported."
|
||||
);
|
||||
return type_to_id_extension_apply<unptr>(native_ref_type);
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_enum<Type>::value>*) noexcept {
|
||||
return type_to_id(identity<typename std::underlying_type<Type>::type >{});
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
constexpr std::size_t type_to_id(identity<Type>, std::enable_if_t<std::is_empty<Type>::value>*) noexcept {
|
||||
static_assert(!std::is_empty<Type>::value, "Empty classes/structures as members are not supported.");
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
constexpr size_array<sizeof(Type) * 3> type_to_id(identity<Type>, std::enable_if_t<!std::is_enum<Type>::value && !std::is_empty<Type>::value>*) noexcept {
|
||||
constexpr auto t = flat_array_of_type_ids<Type>();
|
||||
size_array<sizeof(Type) * 3> result {{tuple_begin_tag}};
|
||||
constexpr bool requires_tuplening = (
|
||||
(t.count_nonzeros() != 1) || (t.count_nonzeros() == t.count_from_opening_till_matching_parenthis_seq(0, tuple_begin_tag, tuple_end_tag))
|
||||
);
|
||||
|
||||
if (requires_tuplening) {
|
||||
for (std::size_t i = 0; i < t.size(); ++i)
|
||||
result.data[i + 1] = t.data[i];
|
||||
result.data[result.size() - 1] = tuple_end_tag;
|
||||
} else {
|
||||
for (std::size_t i = 0; i < t.size(); ++i)
|
||||
result.data[i] = t.data[i];
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
|
||||
template <std::size_t Index>
|
||||
constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ptr_type>) noexcept {
|
||||
typedef decltype( id_to_type(remove_1_ext<Index>()) )* res_t;
|
||||
return construct_helper<res_t>();
|
||||
}
|
||||
|
||||
template <std::size_t Index>
|
||||
constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_ptr_type>) noexcept {
|
||||
typedef const decltype( id_to_type(remove_1_ext<Index>()) )* res_t;
|
||||
return construct_helper<res_t>();
|
||||
}
|
||||
|
||||
template <std::size_t Index>
|
||||
constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_const_volatile_ptr_type>) noexcept {
|
||||
typedef const volatile decltype( id_to_type(remove_1_ext<Index>()) )* res_t;
|
||||
return construct_helper<res_t>();
|
||||
}
|
||||
|
||||
|
||||
template <std::size_t Index>
|
||||
constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_volatile_ptr_type>) noexcept {
|
||||
typedef volatile decltype( id_to_type(remove_1_ext<Index>()) )* res_t;
|
||||
return construct_helper<res_t>();
|
||||
}
|
||||
|
||||
|
||||
template <std::size_t Index>
|
||||
constexpr auto id_to_type(size_t_<Index >, if_extension<Index, native_ref_type>) noexcept {
|
||||
static_assert(!Index, "References are not supported");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
} // namespace typeid_conversions
|
||||
|
||||
///////////////////// Structure that remembers types as integers on a `constexpr operator Type()` call
|
||||
struct ubiq_val {
|
||||
std::size_t* ref_;
|
||||
|
||||
template <class T>
|
||||
constexpr void assign(const T& typeids) const noexcept {
|
||||
for (std::size_t i = 0; i < T::size(); ++i)
|
||||
ref_[i] = typeids.data[i];
|
||||
}
|
||||
|
||||
constexpr void assign(std::size_t val) const noexcept {
|
||||
ref_[0] = val;
|
||||
}
|
||||
|
||||
template <class Type>
|
||||
constexpr operator Type() const noexcept {
|
||||
constexpr auto typeids = typeid_conversions::type_to_id(identity<Type>{});
|
||||
assign(typeids);
|
||||
return construct_helper<Type>();
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////// Structure that remembers size of the type on a `constexpr operator Type()` call
|
||||
struct ubiq_sizes {
|
||||
std::size_t& ref_;
|
||||
|
||||
template <class Type>
|
||||
constexpr operator Type() const noexcept {
|
||||
ref_ = sizeof(Type);
|
||||
return construct_helper<Type>();
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////// Returns array of (offsets without accounting alignments). Required for keeping places for nested type ids
|
||||
template <class T, std::size_t N, std::size_t... I>
|
||||
constexpr size_array<N> get_type_offsets() noexcept {
|
||||
typedef size_array<N> array_t;
|
||||
array_t sizes{};
|
||||
T tmp{ ubiq_sizes{sizes.data[I]}... };
|
||||
(void)tmp;
|
||||
|
||||
array_t offsets{{0}};
|
||||
for (std::size_t i = 1; i < N; ++i)
|
||||
offsets.data[i] = offsets.data[i - 1] + sizes.data[i - 1];
|
||||
|
||||
return offsets;
|
||||
}
|
||||
|
||||
///////////////////// Returns array of typeids and zeros if construtor of a type accepts sizeof...(I) parameters, substitution failure otherwise
|
||||
template <class T, std::size_t N, std::size_t... I>
|
||||
constexpr auto flat_type_to_array_of_type_ids(std::size_t* types, std::index_sequence<I...>) noexcept
|
||||
-> typename std::add_pointer<decltype(T{ ubiq_constructor{I}... })>::type
|
||||
{
|
||||
static_assert(
|
||||
N <= sizeof(T),
|
||||
"Bit fields are not supported."
|
||||
);
|
||||
|
||||
constexpr auto offsets = get_type_offsets<T, N, I...>();
|
||||
T tmp{ ubiq_val{types + get<I>(offsets) * 3}... };
|
||||
(void)types;
|
||||
(void)tmp;
|
||||
(void)offsets; // If type is empty offsets are not used
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
///////////////////// Returns array of typeids and zeros
|
||||
template <class T>
|
||||
constexpr size_array<sizeof(T) * 3> fields_count_and_type_ids_with_zeros() noexcept {
|
||||
size_array<sizeof(T) * 3> types{};
|
||||
constexpr std::size_t N = fields_count<T>();
|
||||
flat_type_to_array_of_type_ids<T, N>(types.data, std::make_index_sequence<N>());
|
||||
return types;
|
||||
}
|
||||
|
||||
///////////////////// Returns array of typeids without zeros
|
||||
template <class T>
|
||||
constexpr auto flat_array_of_type_ids() noexcept {
|
||||
constexpr auto types = fields_count_and_type_ids_with_zeros<T>();
|
||||
constexpr std::size_t count = types.count_nonzeros();
|
||||
size_array<count> res{};
|
||||
std::size_t j = 0;
|
||||
for (std::size_t i = 0; i < decltype(types)::size(); ++i) {
|
||||
if (types.data[i]) {
|
||||
res.data[j] = types.data[i];
|
||||
++ j;
|
||||
}
|
||||
}
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
///////////////////// Convert array of typeids into sequence_tuple::tuple
|
||||
|
||||
template <class T, std::size_t First, std::size_t... I>
|
||||
constexpr auto as_flat_tuple_impl(std::index_sequence<First, I...>) noexcept;
|
||||
|
||||
template <class T>
|
||||
constexpr sequence_tuple::tuple<> as_flat_tuple_impl(std::index_sequence<>) noexcept {
|
||||
return sequence_tuple::tuple<>{};
|
||||
}
|
||||
|
||||
template <std::size_t Increment, std::size_t... I>
|
||||
constexpr auto increment_index_sequence(std::index_sequence<I...>) noexcept {
|
||||
return std::index_sequence<I + Increment...>{};
|
||||
}
|
||||
|
||||
template <class T, std::size_t V, std::size_t I, std::size_t SubtupleLength>
|
||||
constexpr auto prepare_subtuples(size_t_<V>, size_t_<I>, size_t_<SubtupleLength>) noexcept {
|
||||
static_assert(SubtupleLength == 0, "Internal error while representing nested field as tuple");
|
||||
return typeid_conversions::id_to_type(size_t_<V>{});
|
||||
}
|
||||
|
||||
template <class T, std::size_t I, std::size_t SubtupleLength>
|
||||
constexpr auto prepare_subtuples(size_t_<typeid_conversions::tuple_end_tag>, size_t_<I>, size_t_<SubtupleLength>) noexcept {
|
||||
static_assert(sizeof(T) == 0, "Internal error while representing nested field as tuple");
|
||||
return int{};
|
||||
}
|
||||
|
||||
template <class T, std::size_t I, std::size_t SubtupleLength>
|
||||
constexpr auto prepare_subtuples(size_t_<typeid_conversions::tuple_begin_tag>, size_t_<I>, size_t_<SubtupleLength>) noexcept {
|
||||
static_assert(SubtupleLength > 2, "Internal error while representing nested field as tuple");
|
||||
constexpr auto seq = std::make_index_sequence<SubtupleLength - 2>{};
|
||||
return as_flat_tuple_impl<T>( increment_index_sequence<I + 1>(seq) );
|
||||
}
|
||||
|
||||
|
||||
template <class Array>
|
||||
constexpr Array remove_subtuples(Array indexes_plus_1, const Array& subtuple_lengths) noexcept {
|
||||
for (std::size_t i = 0; i < subtuple_lengths.size(); ++i) {
|
||||
if (subtuple_lengths.data[i]) {
|
||||
const std::size_t skips_count = subtuple_lengths.data[i];
|
||||
for (std::size_t j = i + 1; j < skips_count + i; ++j) {
|
||||
indexes_plus_1.data[j] = 0;
|
||||
}
|
||||
i += skips_count - 1;
|
||||
}
|
||||
}
|
||||
return indexes_plus_1;
|
||||
}
|
||||
|
||||
template <std::size_t N, class Array>
|
||||
constexpr size_array<N> resize_dropping_zeros_and_decrementing(size_t_<N>, const Array& a) noexcept {
|
||||
size_array<N> result{};
|
||||
std::size_t result_indx = 0;
|
||||
for (std::size_t i = 0; i < a.size(); ++i) {
|
||||
if (a.data[i]) {
|
||||
result.data[result_indx] = static_cast<std::size_t>(a.data[i] - 1);
|
||||
++ result_indx;
|
||||
}
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
template <class T, std::size_t First, std::size_t... I, std::size_t... INew>
|
||||
constexpr auto as_flat_tuple_impl_drop_helpers(std::index_sequence<First, I...>, std::index_sequence<INew...>) noexcept {
|
||||
constexpr auto a = flat_array_of_type_ids<T>();
|
||||
|
||||
constexpr size_array<sizeof...(I) + 1> subtuples_length {{
|
||||
a.count_from_opening_till_matching_parenthis_seq(First, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag),
|
||||
a.count_from_opening_till_matching_parenthis_seq(I, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag)...
|
||||
}};
|
||||
|
||||
constexpr size_array<sizeof...(I) + 1> type_indexes_with_subtuple_internals {{ 1, 1 + I - First...}};
|
||||
constexpr auto type_indexes_plus_1_and_zeros_as_skips = remove_subtuples(type_indexes_with_subtuple_internals, subtuples_length);
|
||||
constexpr auto new_size = size_t_<type_indexes_plus_1_and_zeros_as_skips.count_nonzeros()>{};
|
||||
constexpr auto type_indexes = resize_dropping_zeros_and_decrementing(new_size, type_indexes_plus_1_and_zeros_as_skips);
|
||||
|
||||
typedef sequence_tuple::tuple<
|
||||
decltype(prepare_subtuples<T>(
|
||||
size_t_< a.data[ First + type_indexes.data[INew] ] >{}, // id of type
|
||||
size_t_< First + type_indexes.data[INew] >{}, // index of current id in `a`
|
||||
size_t_< subtuples_length.data[ type_indexes.data[INew] ] >{} // if id of type is tuple, then length of that tuple
|
||||
))...
|
||||
> subtuples_uncleanuped_t;
|
||||
|
||||
return subtuples_uncleanuped_t{};
|
||||
}
|
||||
|
||||
template <class Array>
|
||||
constexpr std::size_t count_skips_in_array(std::size_t begin_index, std::size_t end_index, const Array& a) noexcept {
|
||||
std::size_t skips = 0;
|
||||
for (std::size_t i = begin_index; i < end_index; ++i) {
|
||||
if (a.data[i] == typeid_conversions::tuple_begin_tag) {
|
||||
const std::size_t this_tuple_size = a.count_from_opening_till_matching_parenthis_seq(i, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag) - 1;
|
||||
skips += this_tuple_size;
|
||||
i += this_tuple_size - 1;
|
||||
}
|
||||
}
|
||||
|
||||
return skips;
|
||||
}
|
||||
|
||||
template <class T, std::size_t First, std::size_t... I>
|
||||
constexpr auto as_flat_tuple_impl(std::index_sequence<First, I...>) noexcept {
|
||||
constexpr auto a = flat_array_of_type_ids<T>();
|
||||
constexpr std::size_t count_of_I = sizeof...(I);
|
||||
|
||||
return as_flat_tuple_impl_drop_helpers<T>(
|
||||
std::index_sequence<First, I...>{},
|
||||
std::make_index_sequence< 1 + count_of_I - count_skips_in_array(First, First + count_of_I, a) >{}
|
||||
);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr auto internal_tuple_with_same_alignment() noexcept {
|
||||
typedef typename std::remove_cv<T>::type type;
|
||||
|
||||
|
||||
#ifdef BOOST_PFR_RELAX_POD_REQUIREMENT
|
||||
static_assert(std::is_standard_layout<type>::value, "Not applyable");
|
||||
static_assert(std::is_move_constructible<type>::value || std::is_array<type>::value, "Not applyable");
|
||||
#else
|
||||
static_assert(std::is_pod<type>::value, "Not applyable");
|
||||
#endif
|
||||
|
||||
static_assert(!std::is_reference<type>::value, "Not applyable");
|
||||
constexpr auto res = as_flat_tuple_impl<type>(
|
||||
std::make_index_sequence< decltype(flat_array_of_type_ids<type>())::size() >()
|
||||
);
|
||||
|
||||
static_assert(
|
||||
std::alignment_of<decltype(res)>::value == std::alignment_of<type>::value,
|
||||
"Alignment check failed, probably your structure has user-defined alignment for the whole structure or for some of the fields."
|
||||
);
|
||||
static_assert(sizeof(res) == sizeof(type), "Size check failed, probably your structure has bitfields or user-defined alignment.");
|
||||
|
||||
return res;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
using internal_tuple_with_same_alignment_t = decltype( internal_tuple_with_same_alignment<T>() );
|
||||
|
||||
|
||||
///////////////////// Flattening
|
||||
template <class Tuple, std::size_t Begin, std::size_t Size>
|
||||
constexpr auto make_flat_tuple_of_references(Tuple&& t, size_t_<Begin>, size_t_<Size>) noexcept;
|
||||
|
||||
template <class Tuple, std::size_t Begin>
|
||||
constexpr detail::sequence_tuple::tuple<> make_flat_tuple_of_references(Tuple&& t, size_t_<Begin>, size_t_<0>) noexcept;
|
||||
|
||||
template <class Tuple, std::size_t Begin>
|
||||
constexpr auto make_flat_tuple_of_references(Tuple&& t, size_t_<Begin>, size_t_<1>) noexcept;
|
||||
|
||||
template <class... T>
|
||||
constexpr auto as_tuple_with_references(T&&... args) noexcept {
|
||||
return detail::sequence_tuple::tuple<T&...>{ std::forward<T>(args)... };
|
||||
}
|
||||
|
||||
template <class... T>
|
||||
constexpr decltype(auto) as_tuple_with_references(detail::sequence_tuple::tuple<T...>& t) noexcept {
|
||||
return make_flat_tuple_of_references(t, size_t_<0>{}, size_t_<detail::sequence_tuple::tuple<T...>::size_v>{});
|
||||
}
|
||||
|
||||
template <class... T>
|
||||
constexpr decltype(auto) as_tuple_with_references(const detail::sequence_tuple::tuple<T...>& t) noexcept {
|
||||
return make_flat_tuple_of_references(t, size_t_<0>{}, size_t_<detail::sequence_tuple::tuple<T...>::size_v>{});
|
||||
}
|
||||
|
||||
template <class Tuple1, std::size_t... I1, class Tuple2, std::size_t... I2>
|
||||
constexpr auto my_tuple_cat_impl(const Tuple1& t1, std::index_sequence<I1...>, const Tuple2& t2, std::index_sequence<I2...>) noexcept {
|
||||
return as_tuple_with_references(
|
||||
detail::sequence_tuple::get<I1>(t1)...,
|
||||
detail::sequence_tuple::get<I2>(t2)...
|
||||
);
|
||||
}
|
||||
|
||||
template <class Tuple1, class Tuple2>
|
||||
constexpr auto my_tuple_cat(const Tuple1& t1, const Tuple2& t2) noexcept {
|
||||
return my_tuple_cat_impl(
|
||||
t1, std::make_index_sequence< Tuple1::size_v >{},
|
||||
t2, std::make_index_sequence< Tuple2::size_v >{}
|
||||
);
|
||||
}
|
||||
|
||||
template <class Tuple, std::size_t Begin, std::size_t Size>
|
||||
constexpr auto make_flat_tuple_of_references(Tuple&& t, size_t_<Begin>, size_t_<Size>) noexcept {
|
||||
constexpr std::size_t next_size = Size / 2;
|
||||
return my_tuple_cat(
|
||||
make_flat_tuple_of_references(std::forward<Tuple>(t), size_t_<Begin>{}, size_t_<next_size>{}),
|
||||
make_flat_tuple_of_references(std::forward<Tuple>(t), size_t_<Begin + Size / 2>{}, size_t_<Size - next_size>{})
|
||||
);
|
||||
}
|
||||
|
||||
template <class Tuple, std::size_t Begin>
|
||||
constexpr detail::sequence_tuple::tuple<> make_flat_tuple_of_references(Tuple&& /*t*/, size_t_<Begin>, size_t_<0>) noexcept {
|
||||
return detail::sequence_tuple::tuple<>{};
|
||||
}
|
||||
|
||||
template <class Tuple, std::size_t Begin>
|
||||
constexpr auto make_flat_tuple_of_references(Tuple&& t, size_t_<Begin>, size_t_<1>) noexcept {
|
||||
return as_tuple_with_references(
|
||||
detail::sequence_tuple::get<Begin>(std::forward<Tuple>(t))
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/// @cond
|
||||
#ifdef __GNUC__
|
||||
#define MAY_ALIAS __attribute__((__may_alias__))
|
||||
#else
|
||||
#define MAY_ALIAS
|
||||
#endif
|
||||
/// @endcond
|
||||
|
||||
template <class T>
|
||||
decltype(auto) tie_as_flat_tuple(const T& val) noexcept {
|
||||
MAY_ALIAS const auto* const t = reinterpret_cast<const detail::internal_tuple_with_same_alignment_t<T>*>( std::addressof(val) );
|
||||
return make_flat_tuple_of_references(*t, size_t_<0>{}, size_t_<detail::internal_tuple_with_same_alignment_t<T>::size_v>{});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
decltype(auto) tie_as_flat_tuple(const volatile T& val) noexcept {
|
||||
MAY_ALIAS const volatile auto* const t = reinterpret_cast<const volatile detail::internal_tuple_with_same_alignment_t<T>*>( std::addressof(val) );
|
||||
return make_flat_tuple_of_references(*t, size_t_<0>{}, size_t_<detail::internal_tuple_with_same_alignment_t<T>::size_v>{});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
decltype(auto) tie_as_flat_tuple(volatile T& val) noexcept {
|
||||
MAY_ALIAS volatile auto* const t = reinterpret_cast<volatile detail::internal_tuple_with_same_alignment_t<T>*>( std::addressof(val) );
|
||||
return make_flat_tuple_of_references(*t, size_t_<0>{}, size_t_<detail::internal_tuple_with_same_alignment_t<T>::size_v>{});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
decltype(auto) tie_as_flat_tuple(T& val) noexcept {
|
||||
MAY_ALIAS auto* const t = reinterpret_cast<detail::internal_tuple_with_same_alignment_t<T>*>( std::addressof(val) );
|
||||
return make_flat_tuple_of_references(*t, size_t_<0>{}, size_t_<detail::internal_tuple_with_same_alignment_t<T>::size_v>{});
|
||||
}
|
||||
|
||||
#undef MAY_ALIAS
|
||||
|
||||
template <class T, std::size_t... I>
|
||||
constexpr auto make_stdtuple_from_tietuple(const T& t, std::index_sequence<I...>) noexcept {
|
||||
return std::make_tuple(
|
||||
boost::pfr::detail::sequence_tuple::get<I>(t)...
|
||||
);
|
||||
}
|
||||
|
||||
template <class T, std::size_t... I>
|
||||
constexpr auto make_stdtiedtuple_from_tietuple(const T& t, std::index_sequence<I...>) noexcept {
|
||||
return std::tie(
|
||||
boost::pfr::detail::sequence_tuple::get<I>(t)...
|
||||
);
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
/// \brief Returns reference or const reference to a field with index `I` in \flattening{flattened} T.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// my_struct s {10, 11};
|
||||
/// assert(boost::pfr::flat_get<0>(s) == 10);
|
||||
/// boost::pfr::flat_get<1>(s) = 0;
|
||||
/// \endcode
|
||||
template <std::size_t I, class T>
|
||||
decltype(auto) flat_get(const T& val) noexcept {
|
||||
return boost::pfr::detail::sequence_tuple::get<I>( boost::pfr::detail::tie_as_flat_tuple(val) );
|
||||
}
|
||||
|
||||
|
||||
/// \overload flat_get
|
||||
template <std::size_t I, class T>
|
||||
decltype(auto) flat_get(T& val /* @cond */, std::enable_if_t< std::is_trivially_assignable<T, T>::value>* = 0/* @endcond */ ) noexcept {
|
||||
return boost::pfr::detail::sequence_tuple::get<I>( boost::pfr::detail::tie_as_flat_tuple(val) );
|
||||
}
|
||||
|
||||
|
||||
/// \brief `flat_tuple_element` has a `typedef type-of-the-field-with-index-I-in-\flattening{flattened}-T type;`
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// std::vector< boost::pfr::flat_tuple_element<0, my_structure>::type > v;
|
||||
/// \endcode
|
||||
template <std::size_t I, class T>
|
||||
using flat_tuple_element = std::remove_reference<
|
||||
typename boost::pfr::detail::sequence_tuple::tuple_element<I, decltype(boost::pfr::detail::tie_as_flat_tuple(std::declval<T&>())) >::type
|
||||
>;
|
||||
|
||||
|
||||
/// \brief Type of a field with index `I` in \flattening{flattened} `T`
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// std::vector< boost::pfr::flat_tuple_element_t<0, my_structure> > v;
|
||||
/// \endcode
|
||||
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:
|
||||
/// \code
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// my_struct s {10, 11};
|
||||
/// std::tuple<int, short> t = flat_make_tuple(s);
|
||||
/// assert(flat_get<0>(t) == 10);
|
||||
/// \endcode
|
||||
template <class T>
|
||||
auto flat_structure_to_tuple(const T& val) noexcept {
|
||||
return detail::make_stdtuple_from_tietuple(
|
||||
detail::tie_as_flat_tuple(val),
|
||||
std::make_index_sequence< flat_tuple_size_v<T> >()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/// \brief Creates an `std::tuple` with lvalue references to fields of a \flattening{flattened} T.
|
||||
///
|
||||
/// \b Requires: `T` must not have const fields.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// my_struct s;
|
||||
/// flat_structure_tie(s) = std::tuple<int, short>{10, 11};
|
||||
/// assert(s.s == 11);
|
||||
/// \endcode
|
||||
template <class T>
|
||||
auto flat_structure_tie(T& val /* @cond */, std::enable_if_t< std::is_trivially_assignable<T, T>::value>* = 0 /* @endcond */) noexcept {
|
||||
return detail::make_stdtiedtuple_from_tietuple(
|
||||
detail::tie_as_flat_tuple(val),
|
||||
std::make_index_sequence< flat_tuple_size_v<T> >()
|
||||
);
|
||||
}
|
||||
|
||||
/// \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_CORE_HPP
|
||||
175
include/boost/pfr/core17.hpp
Normal file
175
include/boost/pfr/core17.hpp
Normal file
@@ -0,0 +1,175 @@
|
||||
// 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_CORE17_HPP
|
||||
#define BOOST_PFR_CORE17_HPP
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus >= 201606L /* Oulu meeting, not the exact value */
|
||||
# include <boost/pfr/detail/core17_generated.hpp>
|
||||
#else
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
template <class T>
|
||||
constexpr auto as_tuple(T&& val) noexcept {
|
||||
static_assert(!sizeof(val), "C++17 required for this function");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
using as_tuple_t = decltype( ::boost::pfr::detail::as_tuple(std::declval<T&>()) );
|
||||
}}} // namespace boost::pfr::detail
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
/// \brief Returns reference or const reference to a field with index `I` in aggregate T.
|
||||
///
|
||||
/// \b Requires: C++17.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// my_struct s {10, 11};
|
||||
/// assert(boost::pfr::get<0>(s) == 10);
|
||||
/// boost::pfr::get<1>(s) = 0;
|
||||
/// \endcode
|
||||
template <std::size_t I, class T>
|
||||
constexpr decltype(auto) get(const T& val) noexcept {
|
||||
return detail::sequence_tuple::get<I>( detail::as_tuple(val) );
|
||||
}
|
||||
|
||||
|
||||
/// \overload get
|
||||
template <std::size_t I, class T>
|
||||
constexpr decltype(auto) get(T& val) noexcept {
|
||||
return detail::sequence_tuple::get<I>( detail::as_tuple(val) );
|
||||
}
|
||||
|
||||
|
||||
/// \brief `tuple_element` has a `typedef type-of-a-field-with-index-I-in-aggregate-T type;`
|
||||
///
|
||||
/// \b Requires: C++17.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// std::vector< boost::pfr::tuple_element<0, my_structure>::type > v;
|
||||
/// \endcode
|
||||
template <std::size_t I, class T>
|
||||
using tuple_element = detail::teleport_extents<
|
||||
T,
|
||||
typename detail::sequence_tuple::tuple_element<I, detail::as_tuple_t<T> >::type
|
||||
>;
|
||||
|
||||
|
||||
/// \brief Type of a field with index `I` in aggregate `T`.
|
||||
///
|
||||
/// \b Requires: C++17.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// std::vector< boost::pfr::tuple_element_t<0, my_structure> > v;
|
||||
/// \endcode
|
||||
template <std::size_t I, class T>
|
||||
using tuple_element_t = typename tuple_element<I, T>::type;
|
||||
|
||||
|
||||
/// \brief Creates an `std::tuple` from an aggregate T.
|
||||
///
|
||||
/// \b Requires: C++17.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// my_struct s {10, 11};
|
||||
/// std::tuple<int, short> t = make_tuple(s);
|
||||
/// assert(get<0>(t) == 10);
|
||||
/// \endcode
|
||||
template <class T>
|
||||
constexpr auto structure_to_tuple(const T& val) noexcept {
|
||||
typedef detail::as_tuple_t<T> internal_tuple_t;
|
||||
|
||||
return detail::make_stdtuple_from_seqtuple(
|
||||
detail::as_tuple(val),
|
||||
std::make_index_sequence< internal_tuple_t::size_v >()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/// \brief Creates an `std::tuple` with lvalue references to fields of an aggregate T.
|
||||
///
|
||||
/// \b Requires: C++17.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// struct my_struct { int i, short s; };
|
||||
/// my_struct s;
|
||||
/// tie(s) = std::tuple<int, short>{10, 11};
|
||||
/// assert(s.s == 11);
|
||||
/// \endcode
|
||||
template <class T>
|
||||
constexpr auto structure_tie(T& val) noexcept {
|
||||
typedef detail::as_tuple_t<T> internal_tuple_t;
|
||||
|
||||
return detail::tie_sequence_tuple_impl(
|
||||
detail::as_tuple(val),
|
||||
std::make_index_sequence< internal_tuple_t::size_v >()
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
/// \brief Writes aggregate `value` to `out`
|
||||
///
|
||||
/// \b Requires: C++17.
|
||||
///
|
||||
/// \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) {
|
||||
out << '{';
|
||||
detail::sequence_tuple::print_impl<0, tuple_size_v<T> >::print(out, detail::as_tuple(value));
|
||||
out << '}';
|
||||
}
|
||||
|
||||
/// Reads aggregate `value` from stream `in`
|
||||
///
|
||||
/// \b Requires: C++17.
|
||||
///
|
||||
/// \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) {
|
||||
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::sequence_tuple::read_impl<0, tuple_size_v<T> >::read(in, detail::as_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_CORE17_HPP
|
||||
1028
include/boost/pfr/detail/core17_generated.hpp
Normal file
1028
include/boost/pfr/detail/core17_generated.hpp
Normal file
File diff suppressed because it is too large
Load Diff
149
include/boost/pfr/fields_count.hpp
Normal file
149
include/boost/pfr/fields_count.hpp
Normal file
@@ -0,0 +1,149 @@
|
||||
// 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_FIELDS_COUNT_HPP
|
||||
#define BOOST_PFR_FIELDS_COUNT_HPP
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus < 201402L
|
||||
# error C++14 is required for this header.
|
||||
#endif
|
||||
|
||||
#include <type_traits>
|
||||
#include <utility> // metaprogramming stuff
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic push
|
||||
# pragma clang diagnostic ignored "-Wmissing-braces"
|
||||
# pragma clang diagnostic ignored "-Wundefined-inline"
|
||||
# pragma clang diagnostic ignored "-Wundefined-internal"
|
||||
# pragma clang diagnostic ignored "-Wmissing-field-initializers"
|
||||
#endif
|
||||
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
namespace detail {
|
||||
|
||||
///////////////////// General utility stuff
|
||||
template <std::size_t Index>
|
||||
using size_t_ = std::integral_constant<std::size_t, Index >;
|
||||
|
||||
///////////////////// Structure that can be converted to reference to anything
|
||||
struct ubiq_constructor {
|
||||
std::size_t ignore;
|
||||
template <class Type> constexpr operator Type&() const noexcept; // Undefined, allows initialization of reference fields (T& and const T&)
|
||||
//template <class Type> constexpr operator Type&&() const noexcept; // Undefined, allows initialization of rvalue reference fields and move-only types
|
||||
};
|
||||
|
||||
///////////////////// Structure that can be converted to reference to anything except reference to T
|
||||
template <class T>
|
||||
struct ubiq_constructor_except {
|
||||
template <class Type> constexpr operator std::enable_if_t<!std::is_same<T, Type>::value, Type&> () const noexcept; // Undefined
|
||||
};
|
||||
|
||||
///////////////////// Hand-made is_aggregate_initializable_n<T> trait:
|
||||
|
||||
// `std::is_constructible<T, ubiq_constructor_except<T>>` consumes a lot of time, so we made a separate lazy trait for it.
|
||||
template <std::size_t N, class T> struct is_single_field_and_aggregate_initializable: std::false_type {};
|
||||
template <class T> struct is_single_field_and_aggregate_initializable<1, T>: std::integral_constant<
|
||||
bool, !std::is_constructible<T, ubiq_constructor_except<T>>::value
|
||||
> {};
|
||||
|
||||
template <class T, std::size_t N>
|
||||
struct is_aggregate_initializable_n {
|
||||
template <std::size_t ...I>
|
||||
static constexpr bool is_not_constructible_n(std::index_sequence<I...>) noexcept {
|
||||
return !std::is_constructible<T, decltype(ubiq_constructor{I})...>::value
|
||||
|| is_single_field_and_aggregate_initializable<N, T>::value
|
||||
;
|
||||
}
|
||||
|
||||
static constexpr bool value =
|
||||
std::is_empty<T>::value
|
||||
|| std::is_fundamental<T>::value
|
||||
|| is_not_constructible_n(std::make_index_sequence<N>{})
|
||||
;
|
||||
};
|
||||
|
||||
///////////////////// Methods for detecting max parameters for construction of T
|
||||
|
||||
template <class T, std::size_t... I>
|
||||
constexpr auto enable_if_constructible_helper(std::index_sequence<I...>) noexcept
|
||||
-> typename std::add_pointer<decltype(T{ ubiq_constructor{I}... })>::type;
|
||||
|
||||
template <class T, std::size_t N>
|
||||
constexpr void detect_fields_count(std::size_t& count, size_t_<N>, size_t_<N>, long) noexcept {
|
||||
// Hand-made is_aggregate<T> trait:
|
||||
// Aggregates could be constructed from `decltype(ubiq_constructor{I})...` but report that there's no constructor from `decltype(ubiq_constructor{I})...`
|
||||
// Special case for N == 1: `std::is_constructible<T, ubiq_constructor>` returns true if N == 1 and T is copy/move constructible.
|
||||
static_assert(
|
||||
is_aggregate_initializable_n<T, N>::value,
|
||||
"Types with user specified constructors (non-aggregate types) are not supported."
|
||||
);
|
||||
|
||||
count = N;
|
||||
}
|
||||
|
||||
template <class T, std::size_t Begin, std::size_t Middle>
|
||||
constexpr void detect_fields_count(std::size_t& count, size_t_<Begin>, size_t_<Middle>, int) noexcept;
|
||||
|
||||
template <class T, std::size_t Begin, std::size_t Middle>
|
||||
constexpr auto detect_fields_count(std::size_t& count, size_t_<Begin>, size_t_<Middle>, long) noexcept
|
||||
-> decltype( enable_if_constructible_helper<T>(std::make_index_sequence<Middle>()) )
|
||||
{
|
||||
constexpr std::size_t next = Middle + (Middle - Begin + 1) / 2;
|
||||
detect_fields_count<T>(count, size_t_<Middle>{}, size_t_<next>{}, 1L);
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <class T, std::size_t Begin, std::size_t Middle>
|
||||
constexpr void detect_fields_count(std::size_t& count, size_t_<Begin>, size_t_<Middle>, int) noexcept {
|
||||
constexpr std::size_t next = (Begin + Middle) / 2;
|
||||
detect_fields_count<T>(count, size_t_<Begin>{}, size_t_<next>{}, 1L);
|
||||
}
|
||||
|
||||
///////////////////// Returns non-flattened fields count
|
||||
template <class T>
|
||||
constexpr std::size_t fields_count() noexcept {
|
||||
static_assert(std::is_copy_constructible<std::remove_all_extents_t<T>>::value, "Structure and each field in structure must be copy constructible");
|
||||
std::size_t res = 0u;
|
||||
constexpr std::size_t next = (sizeof(T) * 8) / 2 + 1; // We multiply by 8 because we may have bitfields in T
|
||||
detect_fields_count<T>(res, size_t_<0>{}, size_t_<next>{}, 1L);
|
||||
return res;
|
||||
}
|
||||
|
||||
} // namespace detail
|
||||
|
||||
#ifdef __clang__
|
||||
# pragma clang diagnostic pop
|
||||
#endif
|
||||
|
||||
/// \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 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 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_FIELDS_COUNT_HPP
|
||||
76
include/boost/pfr/flat_functions_for.hpp
Normal file
76
include/boost/pfr/flat_functions_for.hpp
Normal file
@@ -0,0 +1,76 @@
|
||||
// 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)
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus < 201402L
|
||||
# error C++14 is required for this header.
|
||||
#endif
|
||||
|
||||
#include <boost/pfr/functors.hpp>
|
||||
|
||||
/// \def BOOST_PFR_FLAT_FUNCTIONS_FOR(T)
|
||||
/// Defines comparison operators and stream operators for T.
|
||||
/// 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/flat_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_FLAT_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) noexcept;
|
||||
/// bool operator!=(const T& lhs, const T& rhs) noexcept;
|
||||
/// bool operator< (const T& lhs, const T& rhs) noexcept;
|
||||
/// bool operator> (const T& lhs, const T& rhs) noexcept;
|
||||
/// bool operator<=(const T& lhs, const T& rhs) noexcept;
|
||||
/// bool operator>=(const T& lhs, const T& rhs) noexcept;
|
||||
///
|
||||
/// 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) noexcept;
|
||||
/// \endcode
|
||||
|
||||
#define BOOST_PFR_FLAT_FUNCTIONS_FOR(T) \
|
||||
static inline bool operator==(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_equal_to<T>{}(lhs, rhs); } \
|
||||
static inline bool operator!=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_not_equal<T>{}(lhs, rhs); } \
|
||||
static inline bool operator< (const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_less<T>{}(lhs, rhs); } \
|
||||
static inline bool operator> (const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_greater<T>{}(lhs, rhs); } \
|
||||
static inline bool operator<=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_less_equal<T>{}(lhs, rhs); } \
|
||||
static inline bool operator>=(const T& lhs, const T& rhs) noexcept { return ::boost::pfr::flat_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::flat_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::flat_read(in, value); \
|
||||
return in; \
|
||||
} \
|
||||
static inline std::size_t hash_value(const T& v) noexcept { \
|
||||
return ::boost::pfr::flat_hash<T>{}(v); \
|
||||
} \
|
||||
/**/
|
||||
|
||||
|
||||
162
include/boost/pfr/flat_ops.hpp
Normal file
162
include/boost/pfr/flat_ops.hpp
Normal file
@@ -0,0 +1,162 @@
|
||||
// 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)
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus < 201402L
|
||||
# error C++14 is required for this header.
|
||||
#endif
|
||||
|
||||
#include <boost/pfr/functors.hpp>
|
||||
|
||||
/// \file boost/pfr/flat_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 or it's conversion operator, then the original operator is used.
|
||||
///
|
||||
/// Just write \b using \b namespace \b flat_ops; and operators will be available in scope.
|
||||
///
|
||||
/// \b Example:
|
||||
/// \code
|
||||
/// #include <boost/pfr/flat_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;
|
||||
/// };
|
||||
/// // ...
|
||||
///
|
||||
/// using namespace flat_ops;
|
||||
///
|
||||
/// 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 contains:
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
namespace detail {
|
||||
///////////////////// `value` is true if Detector<Tleft, Tright> does not compile (SFINAE)
|
||||
template <template <class, class> class Detector, class Tleft, class Tright>
|
||||
struct not_appliable {
|
||||
struct success{};
|
||||
template <class Tl, class Tr> static Detector<Tl, Tr> detector_impl(long) noexcept;
|
||||
template <class Tl, class Tr> static success detector_impl(int) noexcept;
|
||||
|
||||
static constexpr bool value = std::is_same<
|
||||
decltype(detector_impl<Tleft, Tright>(1L)),
|
||||
success
|
||||
>::value;
|
||||
};
|
||||
|
||||
///////////////////// Detectors for different operators
|
||||
template <class T1, class T2> using comp_eq_detector = decltype(std::declval<T1>() == std::declval<T2>());
|
||||
template <class T1, class T2> using comp_ne_detector = decltype(std::declval<T1>() != std::declval<T2>());
|
||||
template <class T1, class T2> using comp_lt_detector = decltype(std::declval<T1>() < std::declval<T2>());
|
||||
template <class T1, class T2> using comp_le_detector = decltype(std::declval<T1>() <= std::declval<T2>());
|
||||
template <class T1, class T2> using comp_gt_detector = decltype(std::declval<T1>() > std::declval<T2>());
|
||||
template <class T1, class T2> using comp_ge_detector = decltype(std::declval<T1>() >= std::declval<T2>());
|
||||
template <class S, class T> using ostreamable_detector = decltype(std::declval<S>() << std::declval<T>());
|
||||
template <class S, class T> using istreamable_detector = decltype(std::declval<S>() >> std::declval<T>());
|
||||
|
||||
///////////////////// Helper typedef that it used by all the enable_not_*_comp_t
|
||||
template <template <class, class> class Detector, class T>
|
||||
using enable_not_comp_base_t = typename std::enable_if<
|
||||
not_appliable<Detector, T const&, T const&>::value && std::is_pod<T>::value,
|
||||
bool
|
||||
>::type;
|
||||
|
||||
///////////////////// std::enable_if_t like functions that enable only if types do not support operation and are PODs
|
||||
|
||||
template <class T> using enable_not_eq_comp_t = enable_not_comp_base_t<comp_eq_detector, T>;
|
||||
template <class T> using enable_not_ne_comp_t = enable_not_comp_base_t<comp_ne_detector, T>;
|
||||
template <class T> using enable_not_lt_comp_t = enable_not_comp_base_t<comp_lt_detector, T>;
|
||||
template <class T> using enable_not_le_comp_t = enable_not_comp_base_t<comp_le_detector, T>;
|
||||
template <class T> using enable_not_gt_comp_t = enable_not_comp_base_t<comp_gt_detector, T>;
|
||||
template <class T> using enable_not_ge_comp_t = enable_not_comp_base_t<comp_ge_detector, T>;
|
||||
|
||||
template <class Stream, class Type>
|
||||
using enable_not_ostreamable_t = typename std::enable_if<
|
||||
not_appliable<ostreamable_detector, Stream&, Type const&>::value && std::is_pod<Type>::value,
|
||||
Stream&
|
||||
>::type;
|
||||
|
||||
template <class Stream, class Type>
|
||||
using enable_not_istreamable_t = typename std::enable_if<
|
||||
not_appliable<istreamable_detector, Stream&, Type&>::value && std::is_pod<Type>::value,
|
||||
Stream&
|
||||
>::type;
|
||||
} // namespace detail
|
||||
|
||||
namespace flat_ops {
|
||||
#ifdef BOOST_PFR_DOXYGEN_INVOKED
|
||||
template <class T> bool operator==(const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator!=(const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator< (const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator> (const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator<=(const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator>=(const T& lhs, const T& rhs) noexcept;
|
||||
|
||||
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
|
||||
template <class T> std::size_t hash_value(const T& value) noexcept;
|
||||
#else
|
||||
template <class T>
|
||||
static detail::enable_not_eq_comp_t<T> operator==(const T& lhs, const T& rhs) noexcept {
|
||||
return flat_equal_to<T>{}(lhs, rhs);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static detail::enable_not_ne_comp_t<T> operator!=(const T& lhs, const T& rhs) noexcept {
|
||||
return flat_not_equal<T>{}(lhs, rhs);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static detail::enable_not_lt_comp_t<T> operator<(const T& lhs, const T& rhs) noexcept {
|
||||
return flat_less<T>{}(lhs, rhs);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static detail::enable_not_gt_comp_t<T> operator>(const T& lhs, const T& rhs) noexcept {
|
||||
return flat_greater<T>{}(lhs, rhs);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static detail::enable_not_le_comp_t<T> operator<=(const T& lhs, const T& rhs) noexcept {
|
||||
return flat_less_equal<T>{}(lhs, rhs);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static detail::enable_not_ge_comp_t<T> operator>=(const T& lhs, const T& rhs) noexcept {
|
||||
return flat_greater_equal<T>{}(lhs, rhs);
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
static detail::enable_not_ostreamable_t<std::basic_ostream<Char, Traits>, T> operator<<(std::basic_ostream<Char, Traits>& out, const T& value) {
|
||||
flat_write(out, value);
|
||||
return out;
|
||||
}
|
||||
|
||||
template <class Char, class Traits, class T>
|
||||
static detail::enable_not_istreamable_t<std::basic_istream<Char, Traits>, T> operator>>(std::basic_istream<Char, Traits>& in, T& value) {
|
||||
flat_read(in, value);
|
||||
return in;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::enable_if_t<std::is_pod<T>::value, std::size_t> hash_value(const T& value) noexcept {
|
||||
return flat_hash<T>{}(value);
|
||||
}
|
||||
|
||||
#endif
|
||||
} // namespace flat_ops
|
||||
|
||||
}} // namespace boost::pfr
|
||||
357
include/boost/pfr/functors.hpp
Normal file
357
include/boost/pfr/functors.hpp
Normal file
@@ -0,0 +1,357 @@
|
||||
// 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_FUNCTORS_HPP
|
||||
#define BOOST_PFR_FUNCTORS_HPP
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus < 201402L
|
||||
# error C++14 is required for this header.
|
||||
#endif
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
|
||||
/// \file boost/pfr/functors.hpp
|
||||
/// Contains functors that can work with PODs and are close to the Standard Library ones.
|
||||
/// Each functor \flattening{flattens} the POD type and iterates over its fields.
|
||||
|
||||
namespace boost { namespace pfr {
|
||||
|
||||
namespace detail {
|
||||
template <std::size_t I, std::size_t N>
|
||||
struct equal_impl {
|
||||
template <class T, class U>
|
||||
constexpr static bool cmp(const T& v1, const U& v2) noexcept {
|
||||
return ::boost::pfr::detail::sequence_tuple::get<I>(v1) == ::boost::pfr::detail::sequence_tuple::get<I>(v2)
|
||||
&& equal_impl<I + 1, N>::cmp(v1, v2);
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct equal_impl<N, N> {
|
||||
template <class T, class U>
|
||||
constexpr static bool cmp(const T&, const U&) noexcept {
|
||||
return T::size_v == U::size_v;
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t I, std::size_t N>
|
||||
struct not_equal_impl {
|
||||
template <class T, class U>
|
||||
constexpr static bool cmp(const T& v1, const U& v2) noexcept {
|
||||
return ::boost::pfr::detail::sequence_tuple::get<I>(v1) != ::boost::pfr::detail::sequence_tuple::get<I>(v2)
|
||||
|| not_equal_impl<I + 1, N>::cmp(v1, v2);
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct not_equal_impl<N, N> {
|
||||
template <class T, class U>
|
||||
constexpr static bool cmp(const T&, const U&) noexcept {
|
||||
return T::size_v != U::size_v;
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t I, std::size_t N>
|
||||
struct less_impl {
|
||||
template <class T, class U>
|
||||
constexpr static bool cmp(const T& v1, const U& v2) noexcept {
|
||||
using ::boost::pfr::detail::sequence_tuple::get;
|
||||
return get<I>(v1) < get<I>(v2)
|
||||
|| (get<I>(v1) == get<I>(v2) && less_impl<I + 1, N>::cmp(v1, v2));
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct less_impl<N, N> {
|
||||
template <class T, class U>
|
||||
constexpr static bool cmp(const T&, const U&) noexcept {
|
||||
return T::size_v < U::size_v;
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t I, std::size_t N>
|
||||
struct less_equal_impl {
|
||||
template <class T, class U>
|
||||
constexpr static bool cmp(const T& v1, const U& v2) noexcept {
|
||||
using ::boost::pfr::detail::sequence_tuple::get;
|
||||
return get<I>(v1) < get<I>(v2)
|
||||
|| (get<I>(v1) == get<I>(v2) && less_equal_impl<I + 1, N>::cmp(v1, v2));
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct less_equal_impl<N, N> {
|
||||
template <class T, class U>
|
||||
constexpr static bool cmp(const T&, const U&) noexcept {
|
||||
return T::size_v <= U::size_v;
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t I, std::size_t N>
|
||||
struct greater_impl {
|
||||
template <class T, class U>
|
||||
constexpr static bool cmp(const T& v1, const U& v2) noexcept {
|
||||
using ::boost::pfr::detail::sequence_tuple::get;
|
||||
return get<I>(v1) > get<I>(v2)
|
||||
|| (get<I>(v1) == get<I>(v2) && greater_impl<I + 1, N>::cmp(v1, v2));
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct greater_impl<N, N> {
|
||||
template <class T, class U>
|
||||
constexpr static bool cmp(const T&, const U&) noexcept {
|
||||
return T::size_v > U::size_v;
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t I, std::size_t N>
|
||||
struct greater_equal_impl {
|
||||
template <class T, class U>
|
||||
constexpr static bool cmp(const T& v1, const U& v2) noexcept {
|
||||
using ::boost::pfr::detail::sequence_tuple::get;
|
||||
return get<I>(v1) > get<I>(v2)
|
||||
|| (get<I>(v1) == get<I>(v2) && greater_equal_impl<I + 1, N>::cmp(v1, v2));
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct greater_equal_impl<N, N> {
|
||||
template <class T, class U>
|
||||
constexpr static bool cmp(const T&, const U&) noexcept {
|
||||
return T::size_v >= U::size_v;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename SizeT>
|
||||
constexpr void hash_combine(SizeT& seed, SizeT value) noexcept {
|
||||
seed ^= value + 0x9e3779b9 + (seed<<6) + (seed>>2);
|
||||
}
|
||||
|
||||
template <std::size_t I, std::size_t N>
|
||||
struct hash_impl {
|
||||
template <class T>
|
||||
constexpr static std::size_t compute(const T& val) noexcept {
|
||||
typedef std::decay_t<typename detail::sequence_tuple::tuple_element<I, T>::type> elem_t;
|
||||
std::size_t h = std::hash<elem_t>()( ::boost::pfr::detail::sequence_tuple::get<I>(val) );
|
||||
hash_combine(h, hash_impl<I + 1, N>::compute(val) );
|
||||
return h;
|
||||
}
|
||||
};
|
||||
|
||||
template <std::size_t N>
|
||||
struct hash_impl<N, N> {
|
||||
template <class T>
|
||||
constexpr static std::size_t compute(const T&) noexcept {
|
||||
return 0;
|
||||
}
|
||||
};
|
||||
|
||||
///////////////////// Define min_element and to avoid inclusion of <algorithm>
|
||||
constexpr std::size_t min_size(std::size_t x, std::size_t y) noexcept {
|
||||
return x < y ? x : y;
|
||||
}
|
||||
} // namespace detail
|
||||
|
||||
///////////////////// Comparisons
|
||||
|
||||
/// \brief std::equal_to like flattening comparator
|
||||
template <class T = void> struct flat_equal_to {
|
||||
/// \return \b true if each field of \b x equals the field with same index of \b y
|
||||
bool operator()(const T& x, const T& y) const noexcept {
|
||||
return detail::equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
}
|
||||
|
||||
#ifdef BOOST_PFR_DOXYGEN_INVOKED
|
||||
/// This typedef exists only if T \b is void
|
||||
typedef std::true_type is_transparent;
|
||||
|
||||
/// This operator allows comparison of \b x and \b y that have different type.
|
||||
/// \pre Exists only if T \b is void.
|
||||
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// @cond
|
||||
template <> struct flat_equal_to<void> {
|
||||
template <class T, class U>
|
||||
bool operator()(const T& x, const U& y) const noexcept {
|
||||
return detail::equal_impl<
|
||||
0,
|
||||
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
|
||||
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
}
|
||||
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
/// \brief std::not_equal like flattening comparator
|
||||
template <class T = void> struct flat_not_equal {
|
||||
/// \return \b true if at least one field \b x not equals the field with same index of \b y
|
||||
bool operator()(const T& x, const T& y) const noexcept {
|
||||
return detail::not_equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
}
|
||||
|
||||
#ifdef BOOST_PFR_DOXYGEN_INVOKED
|
||||
/// This typedef exists only if T \b is void
|
||||
typedef std::true_type is_transparent;
|
||||
|
||||
/// This operator allows comparison of \b x and \b y that have different type.
|
||||
/// \pre Exists only if T \b is void.
|
||||
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// @cond
|
||||
template <> struct flat_not_equal<void> {
|
||||
template <class T, class U>
|
||||
bool operator()(const T& x, const U& y) const noexcept {
|
||||
return detail::not_equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
}
|
||||
|
||||
typedef std::true_type is_transparent;
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
/// \brief std::greater like flattening comparator
|
||||
template <class T = void> struct flat_greater {
|
||||
/// \return \b true if field of \b x greater than the field with same index of \b y and all previous fields of \b x eqeal to the same fields of \b y
|
||||
bool operator()(const T& x, const T& y) const noexcept {
|
||||
return detail::greater_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
}
|
||||
|
||||
#ifdef BOOST_PFR_DOXYGEN_INVOKED
|
||||
/// This typedef exists only if T \b is void
|
||||
typedef std::true_type is_transparent;
|
||||
|
||||
/// This operator allows comparison of \b x and \b y that have different type.
|
||||
/// \pre Exists only if T \b is void.
|
||||
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// @cond
|
||||
template <> struct flat_greater<void> {
|
||||
template <class T, class U>
|
||||
bool operator()(const T& x, const U& y) const noexcept {
|
||||
return detail::greater_impl<
|
||||
0,
|
||||
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
|
||||
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
}
|
||||
|
||||
typedef std::true_type is_transparent;
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
/// \brief std::less like flattening comparator
|
||||
template <class T = void> struct flat_less {
|
||||
/// \return \b true if field of \b x less than the field with same index of \b y and all previous fields of \b x eqeal to the same fields of \b y
|
||||
bool operator()(const T& x, const T& y) const noexcept {
|
||||
return detail::less_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
}
|
||||
|
||||
#ifdef BOOST_PFR_DOXYGEN_INVOKED
|
||||
/// This typedef exists only if T \b is void
|
||||
typedef std::true_type is_transparent;
|
||||
|
||||
/// This operator allows comparison of \b x and \b y that have different type.
|
||||
/// \pre Exists only if T \b is void.
|
||||
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// @cond
|
||||
template <> struct flat_less<void> {
|
||||
template <class T, class U>
|
||||
bool operator()(const T& x, const U& y) const noexcept {
|
||||
return detail::less_impl<
|
||||
0,
|
||||
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
|
||||
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
}
|
||||
|
||||
typedef std::true_type is_transparent;
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
/// \brief std::greater_equal like flattening comparator
|
||||
template <class T = void> struct flat_greater_equal {
|
||||
/// \return \b true if field of \b x greater than the field with same index of \b y and all previous fields of \b x eqeal to the same fields of \b y;
|
||||
/// or if each field of \b x equals the field with same index of \b y .
|
||||
bool operator()(const T& x, const T& y) const noexcept {
|
||||
return detail::greater_equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
}
|
||||
|
||||
#ifdef BOOST_PFR_DOXYGEN_INVOKED
|
||||
/// This typedef exists only if T \b is void
|
||||
typedef std::true_type is_transparent;
|
||||
|
||||
/// This operator allows comparison of \b x and \b y that have different type.
|
||||
/// \pre Exists only if T \b is void.
|
||||
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// @cond
|
||||
template <> struct flat_greater_equal<void> {
|
||||
template <class T, class U>
|
||||
bool operator()(const T& x, const U& y) const noexcept {
|
||||
return detail::greater_equal_impl<
|
||||
0,
|
||||
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
|
||||
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
}
|
||||
|
||||
typedef std::true_type is_transparent;
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
/// \brief std::less_equal like flattening comparator
|
||||
template <class T = void> struct flat_less_equal {
|
||||
/// \return \b true if field of \b x less than the field with same index of \b y and all previous fields of \b x eqeal to the same fields of \b y;
|
||||
/// or if each field of \b x equals the field with same index of \b y .
|
||||
bool operator()(const T& x, const T& y) const noexcept {
|
||||
return detail::less_equal_impl<0, flat_tuple_size_v<T> >::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
}
|
||||
|
||||
#ifdef BOOST_PFR_DOXYGEN_INVOKED
|
||||
/// This typedef exists only if T \b is void
|
||||
typedef std::true_type is_transparent;
|
||||
|
||||
/// This operator allows comparison of \b x and \b y that have different type.
|
||||
/// \pre Exists only if T \b is void.
|
||||
template <class V, class U> bool operator()(const V& x, const U& y) const noexcept;
|
||||
#endif
|
||||
};
|
||||
|
||||
/// @cond
|
||||
template <> struct flat_less_equal<void> {
|
||||
template <class T, class U>
|
||||
bool operator()(const T& x, const U& y) const noexcept {
|
||||
return detail::less_equal_impl<
|
||||
0,
|
||||
detail::min_size(flat_tuple_size_v<T>, flat_tuple_size_v<U>)
|
||||
>::cmp(detail::tie_as_flat_tuple(x), detail::tie_as_flat_tuple(y));
|
||||
}
|
||||
|
||||
typedef std::true_type is_transparent;
|
||||
};
|
||||
/// @endcond
|
||||
|
||||
|
||||
/// \brief std::hash like flattening functor
|
||||
template <class T> struct flat_hash {
|
||||
/// \return hash value of \b x
|
||||
std::size_t operator()(const T& x) const noexcept {
|
||||
return detail::hash_impl<0, flat_tuple_size_v<T> >::compute(detail::tie_as_flat_tuple(x));
|
||||
}
|
||||
};
|
||||
|
||||
}} // namespace boost::pfr
|
||||
|
||||
#endif // BOOST_PFR_FUNCTORS_HPP
|
||||
110
include/boost/pfr/global_flat_ops.hpp
Normal file
110
include/boost/pfr/global_flat_ops.hpp
Normal file
@@ -0,0 +1,110 @@
|
||||
// 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)
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus < 201402L
|
||||
# error C++14 is required for this header.
|
||||
#endif
|
||||
|
||||
#include <boost/pfr/functors.hpp>
|
||||
|
||||
/// \file boost/pfr/global_flat_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>
|
||||
/// 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 && std::is_pod<T>::value,
|
||||
bool
|
||||
>;
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
/// @endcond
|
||||
|
||||
#ifdef BOOST_PFR_DOXYGEN_INVOKED
|
||||
template <class T> bool operator==(const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator!=(const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator< (const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator> (const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator<=(const T& lhs, const T& rhs) noexcept;
|
||||
template <class T> bool operator>=(const T& lhs, const T& rhs) noexcept;
|
||||
|
||||
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) noexcept;
|
||||
#else
|
||||
template <class T, class U>
|
||||
static boost::pfr::detail::enable_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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
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 {
|
||||
return ::boost::pfr::flat_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::flat_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::flat_read(in, value);
|
||||
return in;
|
||||
}
|
||||
|
||||
template <class T>
|
||||
static std::enable_if_t<std::is_pod<T>::value, std::size_t> hash_value(const T& value) noexcept {
|
||||
return ::boost::pfr::flat_hash<T>{}(value);
|
||||
}
|
||||
#endif
|
||||
1127
magic_get.hpp
1127
magic_get.hpp
File diff suppressed because it is too large
Load Diff
471
main.cpp
471
main.cpp
@@ -1,471 +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 "magic_get.hpp"
|
||||
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#include <tuple>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <cassert>
|
||||
#include <algorithm>
|
||||
#include <unordered_set>
|
||||
|
||||
template <std::size_t I, class T>
|
||||
void print(T& f) {
|
||||
std::cout << flat_get<I>(f) << "\t\t"
|
||||
<< typeid(flat_tuple_element_t<I, T>).name()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
|
||||
struct make_my_life_harder { int a0; short a1; };
|
||||
struct make_my_life_even_more_harder { unsigned int b0; unsigned short b1; make_my_life_harder cr;};
|
||||
struct foo {
|
||||
unsigned char v0;
|
||||
unsigned int v1;
|
||||
unsigned short v2;
|
||||
unsigned long long v3;
|
||||
unsigned char v4and5[2];
|
||||
int v6;
|
||||
std::size_t v7;
|
||||
int* v8;
|
||||
const void* v9;
|
||||
int const**const volatile**volatile** v10;
|
||||
const double v11;
|
||||
make_my_life_harder v12and13;
|
||||
make_my_life_even_more_harder v14and15andv16and17;
|
||||
};
|
||||
|
||||
void test_print() {
|
||||
foo f {
|
||||
'A', 11, 12, 13, {'B', 'C'}, 16, 17, 0, 0, 0, 30.1
|
||||
, {18, 19}
|
||||
, {20, 21, {22, 23}}
|
||||
};
|
||||
print<0>(f); print<1>(f); print<2>(f);
|
||||
print<3>(f); print<4>(f); print<5>(f);
|
||||
print<6>(f); print<7>(f); print<8>(f);
|
||||
print<9>(f); print<10>(f); print<11>(f);
|
||||
print<12>(f); print<13>(f); print<14>(f);
|
||||
print<15>(f); print<16>(f); print<17>(f);
|
||||
static_assert(flat_tuple_size_v<foo> == 18, "failed tuple size check");
|
||||
|
||||
int a[] = {0, 1, 2, 3};
|
||||
std::cout << '\n' << flat_get<1>(a) << std::endl;
|
||||
|
||||
int b[2][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}};
|
||||
std::cout << flat_get<4>(b) << std::endl;
|
||||
|
||||
int i = 777;
|
||||
std::cout << flat_get<0>(i) << std::endl;
|
||||
}
|
||||
|
||||
void test_runtime(const foo& f) {
|
||||
assert( flat_get<0>(f) == f.v0);
|
||||
assert( flat_get<1>(f) == f.v1);
|
||||
assert( flat_get<2>(f) == f.v2);
|
||||
assert( flat_get<3>(f) == f.v3);
|
||||
assert( flat_get<4>(f) == f.v4and5[0]);
|
||||
assert( flat_get<5>(f) == f.v4and5[1]);
|
||||
assert( flat_get<6>(f) == f.v6);
|
||||
assert( flat_get<7>(f) == f.v7);
|
||||
assert( flat_get<8>(f) == f.v8);
|
||||
assert( flat_get<9>(f) == f.v9);
|
||||
assert( flat_get<10>(f) == f.v10);
|
||||
assert( flat_get<11>(f) < f.v11 + 0.001); assert( flat_get<11>(f) > f.v11 - 0.001);
|
||||
assert( flat_get<12>(f) == f.v12and13.a0);
|
||||
assert( flat_get<13>(f) == f.v12and13.a1);
|
||||
assert( flat_get<14>(f) == f.v14and15andv16and17.b0);
|
||||
assert( flat_get<15>(f) == f.v14and15andv16and17.b1);
|
||||
assert( flat_get<16>(f) == f.v14and15andv16and17.cr.a0);
|
||||
assert( flat_get<17>(f) == f.v14and15andv16and17.cr.a1);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void test_compiletime() {
|
||||
constexpr T f{};
|
||||
static_assert(flat_tuple_size_v<foo> == 18, "failed tuple size check");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), decltype((f.v0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<1>(f)), decltype((f.v1))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<2>(f)), decltype((f.v2))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<3>(f)), decltype((f.v3))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<4>(f)), decltype((f.v4and5[0]))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<5>(f)), decltype((f.v4and5[1]))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<6>(f)), decltype((f.v6))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<7>(f)), decltype((f.v7))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<8>(f)), decltype((f.v8))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<9>(f)), decltype((f.v9))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<10>(f)), decltype((f.v10))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<11>(f)), decltype((f.v11))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<12>(f)), decltype((f.v12and13.a0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<13>(f)), decltype((f.v12and13.a1))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<14>(f)), decltype((f.v14and15andv16and17.b0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<15>(f)), decltype((f.v14and15andv16and17.b1))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<16>(f)), decltype((f.v14and15andv16and17.cr.a0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<17>(f)), decltype((f.v14and15andv16and17.cr.a1))>::value, "types missmatch");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr void test_compiletime_array() {
|
||||
{
|
||||
constexpr T f[20] = {0};
|
||||
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
|
||||
}
|
||||
{
|
||||
constexpr T f[2][10] = {0};
|
||||
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
|
||||
}
|
||||
{
|
||||
constexpr T f[2][5][2] = {0};
|
||||
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
|
||||
}
|
||||
}
|
||||
|
||||
//#define TEST_REF
|
||||
#ifdef TEST_REF
|
||||
|
||||
struct with_ref {
|
||||
int i;
|
||||
int& ref;
|
||||
};
|
||||
void test() {
|
||||
int ref_me = 1234567890;
|
||||
with_ref f { 987654321, ref_me };
|
||||
print<0>(f); print<1>(f);
|
||||
}
|
||||
#endif
|
||||
|
||||
void test_with_enums() {
|
||||
enum class my_enum: unsigned {
|
||||
VALUE1 = 17, VALUE2, VALUE3
|
||||
};
|
||||
struct my_struct { my_enum e; int i; short s; };
|
||||
my_struct s {my_enum::VALUE1, 10, 11};
|
||||
std::tuple<unsigned, int, short> t = flat_make_tuple(s);
|
||||
assert(std::get<0>(t) == 17);
|
||||
assert(std::get<1>(t) == 10);
|
||||
assert(std::get<2>(t) == 11);
|
||||
|
||||
flat_get<1>(s) = 101;
|
||||
assert(flat_get<1>(s) == 101);
|
||||
flat_get<2>(s) = 111;
|
||||
assert(flat_get<2>(s) == 111);
|
||||
|
||||
assert(flat_tie(s) == flat_tie(s));
|
||||
assert(flat_tie(s) == flat_make_tuple(s));
|
||||
assert(flat_tie(s) != t);
|
||||
flat_tie(s) = t;
|
||||
assert(flat_get<0>(s) == 17);
|
||||
assert(flat_get<1>(s) == 10);
|
||||
assert(flat_get<2>(s) == 11);
|
||||
|
||||
static_assert(std::is_same<
|
||||
int, flat_tuple_element_t<1, my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(std::is_same<
|
||||
short, flat_tuple_element_t<2, my_struct>
|
||||
>::value, "");
|
||||
|
||||
|
||||
static_assert(std::is_same<
|
||||
const int, flat_tuple_element_t<1, const my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(std::is_same<
|
||||
volatile short, flat_tuple_element_t<2, volatile my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(std::is_same<
|
||||
const volatile short, flat_tuple_element_t<2, const volatile my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(
|
||||
3 == flat_tuple_size_v<const volatile my_struct>,
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
void test_comparable_struct() {
|
||||
struct comparable_struct {
|
||||
int i; short s; char data[50]; bool bl; int a,b,c,d,e,f;
|
||||
};
|
||||
using namespace pod_ops;
|
||||
|
||||
comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
|
||||
comparable_struct s2 = s1;
|
||||
comparable_struct s3 {0, 1, "Hello", false, 6,7,8,9,10,11111};
|
||||
assert(s1 == s2);
|
||||
assert(s1 <= s2);
|
||||
assert(s1 >= s2);
|
||||
assert(!(s1 != s2));
|
||||
assert(!(s1 == s3));
|
||||
assert(s1 != s3);
|
||||
assert(s1 < s3);
|
||||
assert(s3 > s2);
|
||||
assert(s1 <= s3);
|
||||
assert(s3 >= s2);
|
||||
|
||||
std::cout << s1 << std::endl;
|
||||
|
||||
comparable_struct s4;
|
||||
std::stringstream ss;
|
||||
ss.exceptions ( std::ios::failbit);
|
||||
ss << s1;
|
||||
ss >> s4;
|
||||
std::cout << s4 << std::endl;
|
||||
assert(s1 == s4);
|
||||
int i = 1, j = 2;
|
||||
assert(i != j);
|
||||
}
|
||||
|
||||
void test_empty_struct() {
|
||||
struct empty {};
|
||||
using namespace pod_ops;
|
||||
|
||||
std::cout << empty{} << std::endl;
|
||||
|
||||
assert(empty{} == empty{});
|
||||
}
|
||||
|
||||
|
||||
void test_pods_with_int_operators() {
|
||||
using namespace pod_ops;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::is_pod<int>{};
|
||||
int i = 0;
|
||||
ss >> i;
|
||||
assert(i == 1);
|
||||
std::cout << i << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void test_struct_with_single_field() {
|
||||
struct f1 { int i; };
|
||||
using namespace pod_ops;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << f1{ 777 };
|
||||
f1 var{};
|
||||
ss >> var;
|
||||
assert(var.i == 777);
|
||||
assert(var == f1{ 777 });
|
||||
assert(var != f1{ 778 });
|
||||
|
||||
assert(var <= f1{ 777 });
|
||||
assert(var <= f1{ 778 });
|
||||
assert(var < f1{ 778 });
|
||||
|
||||
assert(var >= f1{ 777 });
|
||||
assert(var >= f1{ 776 });
|
||||
assert(var > f1{ 776 });
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
void test_with_contatiners() {
|
||||
struct testing { bool b1, b2; int i; };
|
||||
struct testing2 { bool b1, b2; int i; };
|
||||
std::set<testing, Comparator > t{
|
||||
{true, true, 100},
|
||||
{false, true, 100},
|
||||
{true, false, 100},
|
||||
{true, true, 101}
|
||||
};
|
||||
|
||||
assert(t.find({true, true, 100}) != t.end());
|
||||
assert(t.count({true, true, 100}) == 1);
|
||||
assert(t.find(testing2{true, true, 100}) != t.end());
|
||||
|
||||
std::set<testing2, Comparator > t2{
|
||||
{true, true, 101},
|
||||
{true, true, 100},
|
||||
{true, false, 100},
|
||||
{false, true, 100}
|
||||
};
|
||||
|
||||
assert(std::equal(t.begin(), t.end(), t2.begin(), t2.end(), flat_equal_to<>{}));
|
||||
assert(!std::equal(t.begin(), t.end(), t2.begin(), t2.end(), flat_not_equal<>{}));
|
||||
|
||||
std::vector<testing> res;
|
||||
std::set_intersection(t.begin(), t.end(), t2.begin(), t2.end(),
|
||||
std::back_inserter(res), Comparator{});
|
||||
|
||||
assert(res.size() == 4);
|
||||
}
|
||||
|
||||
void test_with_user_defined_constructor() {
|
||||
struct pr {
|
||||
int i;
|
||||
short s;
|
||||
|
||||
pr() = default;
|
||||
pr(const pr&) = default;
|
||||
pr(pr&&) = default;
|
||||
pr(int ii, short is) noexcept
|
||||
: i(ii), s(is)
|
||||
{}
|
||||
};
|
||||
|
||||
pr p{1, 2};
|
||||
|
||||
//assert(flat_get<1>(p) == 2); // Compilation error
|
||||
}
|
||||
|
||||
template <class T1, std::size_t CountInT, std::size_t CountHelpers>
|
||||
void test_counts_on_multiple_chars_impl_1() {
|
||||
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]; };
|
||||
static_assert(flat_tuple_size_v<t1_i> == CountInT + CountHelpers, "");
|
||||
|
||||
struct t1_p { T1 v1; void* p[CountHelpers]; };
|
||||
static_assert(flat_tuple_size_v<t1_p> == CountInT + CountHelpers, "");
|
||||
|
||||
struct t1_ll { T1 v1; long long ll[CountHelpers]; };
|
||||
static_assert(flat_tuple_size_v<t1_ll> == CountInT + CountHelpers, "");
|
||||
|
||||
|
||||
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; };
|
||||
static_assert(flat_tuple_size_v<rt1_s> == CountInT + CountHelpers, "");
|
||||
|
||||
struct rt1_i { int i[CountHelpers]; T1 v1; };
|
||||
static_assert(flat_tuple_size_v<rt1_i> == CountInT + CountHelpers, "");
|
||||
|
||||
struct rt1_p { void* p[CountHelpers]; T1 v1; };
|
||||
static_assert(flat_tuple_size_v<rt1_p> == CountInT + CountHelpers, "");
|
||||
|
||||
struct rt1_ll { long long ll[CountHelpers]; T1 v1; };
|
||||
static_assert(flat_tuple_size_v<rt1_ll> == CountInT + CountHelpers, "");
|
||||
}
|
||||
|
||||
template <class T1, std::size_t CountInT>
|
||||
void test_counts_on_multiple_chars_impl() {
|
||||
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(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>();
|
||||
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>();
|
||||
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>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 11>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 12>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 13>();/*
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 14>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 15>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 16>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 17>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 18>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 19>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 20>();*/
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void test_counts_on_multiple_chars() {
|
||||
test_counts_on_multiple_chars_impl<T, 1>();
|
||||
|
||||
struct t2 { T v1; T v2; };
|
||||
test_counts_on_multiple_chars_impl<t2, 2>();
|
||||
test_counts_on_multiple_chars_impl<T[2], 2>();
|
||||
|
||||
test_counts_on_multiple_chars_impl<T[3], 3>();
|
||||
test_counts_on_multiple_chars_impl<T[4], 4>();
|
||||
|
||||
struct t8 { T v1; T v2; T v3; T v4; T v5; T v6; T v7; T v8; };
|
||||
test_counts_on_multiple_chars_impl<t8, 8>();
|
||||
}
|
||||
|
||||
void test_hash() {
|
||||
struct almost_pair { int i; short s; };
|
||||
std::unordered_set<almost_pair, flat_hash<almost_pair>, flat_equal_to<> > s;
|
||||
s.insert({0, 1});
|
||||
s.insert({1, 0});
|
||||
s.insert({1, 1});
|
||||
|
||||
assert(s.size() == 3);
|
||||
flat_hash<almost_pair> hs;
|
||||
assert(hs({0, 1}) != hs({1, 0}));
|
||||
assert(hs({0, 1}) == hs({0, 1}));
|
||||
assert(hs({1, 1}) == hs({1, 1}));
|
||||
assert(hs({0, 0}) != hs({1, 1}));
|
||||
|
||||
struct single_field { int i; };
|
||||
assert(flat_hash<single_field>()({1}) != std::hash<int>()(1));
|
||||
assert(flat_hash<single_field>()({199}) != std::hash<int>()(199));
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_compiletime<foo>();
|
||||
test_compiletime_array<int>();
|
||||
test_compiletime_array<void*>();
|
||||
test_compiletime_array<const void*>();
|
||||
test_compiletime_array<char>();
|
||||
test_compiletime_array<char const volatile*>();
|
||||
{
|
||||
foo f {
|
||||
'A', 11, 12, 13, {'B', 'C'}, 16, 17, 0, 0, 0, 30.1
|
||||
, {18, 19}
|
||||
, {20, 21, {22, 23}}
|
||||
};
|
||||
test_runtime(f);
|
||||
}
|
||||
{
|
||||
foo f {
|
||||
'\0', 12437, 1212, 13, {'1', '7'}, 163, 1723, 0, 0, 0, 3000.1
|
||||
, {-18, -19}
|
||||
, {656565, 65535, {-22, -23}}
|
||||
};
|
||||
test_runtime(f);
|
||||
}
|
||||
|
||||
test_with_enums();
|
||||
test_comparable_struct();
|
||||
test_empty_struct();
|
||||
test_pods_with_int_operators();
|
||||
test_struct_with_single_field();
|
||||
|
||||
test_with_contatiners<flat_less<>>();
|
||||
test_with_contatiners<flat_greater<>>();
|
||||
|
||||
test_print();
|
||||
|
||||
test_with_user_defined_constructor();
|
||||
|
||||
test_counts_on_multiple_chars<char>();
|
||||
test_counts_on_multiple_chars<short>();
|
||||
test_counts_on_multiple_chars<int>();
|
||||
test_counts_on_multiple_chars<void*>();
|
||||
test_counts_on_multiple_chars<long long>();
|
||||
test_hash();
|
||||
}
|
||||
|
||||
|
||||
109
misc/generate_cpp17.py
Normal file
109
misc/generate_cpp17.py
Normal file
@@ -0,0 +1,109 @@
|
||||
#!/usr/bin/python
|
||||
|
||||
# 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)
|
||||
|
||||
############################################################################################################################
|
||||
|
||||
import sys
|
||||
import string
|
||||
|
||||
# Skipping some letters that mey produce keywords or are hard to read
|
||||
ascii_letters = string.ascii_letters.replace("o", "").replace("O", "").replace("i", "").replace("I", "")
|
||||
|
||||
PROLOGUE = """// 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)
|
||||
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
//////////////// This is an auto generated header. Modify pfr/misc/generate_cpp17.py instead. ////////////////////////////
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
#ifndef BOOST_PFR_CORE17_GENERATED_HPP
|
||||
#define BOOST_PFR_CORE17_GENERATED_HPP
|
||||
|
||||
#pragma once
|
||||
|
||||
#if __cplusplus < 201606L /* Oulu meeting, not the exact value */
|
||||
# error C++17 is required for this header.
|
||||
#endif
|
||||
|
||||
#include <boost/pfr/core.hpp>
|
||||
|
||||
namespace boost { namespace pfr { namespace detail {
|
||||
|
||||
template <class... Args>
|
||||
constexpr auto make_tuple_of_references(Args&&... args) noexcept {
|
||||
return sequence_tuple::tuple<Args&...>{ std::forward<Args>(args)... };
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr auto as_tuple_impl(T&& /*val*/, size_t_<0>) noexcept {
|
||||
return sequence_tuple::tuple<>{};
|
||||
}
|
||||
|
||||
"""
|
||||
|
||||
############################################################################################################################
|
||||
EPILOGUE = """
|
||||
////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
template <class T>
|
||||
constexpr auto as_tuple(const T& val) noexcept {
|
||||
typedef size_t_<fields_count<T>()> fields_count_tag;
|
||||
return detail::as_tuple_impl(val, fields_count_tag{});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr auto as_tuple(T& val) noexcept {
|
||||
typedef size_t_<fields_count<T>()> fields_count_tag;
|
||||
return detail::as_tuple_impl(val, fields_count_tag{});
|
||||
}
|
||||
|
||||
template <class T>
|
||||
using as_tuple_t = decltype( ::boost::pfr::detail::as_tuple(std::declval<T&>()) );
|
||||
|
||||
}}} // namespace boost::pfr::detail
|
||||
|
||||
#endif // BOOST_PFR_CORE17_GENERATED_HPP
|
||||
"""
|
||||
|
||||
############################################################################################################################
|
||||
|
||||
indexes = ""
|
||||
print PROLOGUE
|
||||
funcs_count = 100 if len(sys.argv) == 1 else int(sys.argv[1])
|
||||
max_args_on_a_line = len(ascii_letters)
|
||||
for i in xrange(funcs_count):
|
||||
if i == 0:
|
||||
indexes = " "
|
||||
elif i % max_args_on_a_line == 0:
|
||||
indexes += ",\n "
|
||||
else:
|
||||
indexes += ","
|
||||
|
||||
if i >= max_args_on_a_line:
|
||||
indexes += ascii_letters[i / max_args_on_a_line - 1]
|
||||
indexes += ascii_letters[i % max_args_on_a_line]
|
||||
|
||||
print "template <class T>"
|
||||
print "constexpr auto as_tuple_impl(T&& val, size_t_<" + str(i + 1) + ">) noexcept {"
|
||||
if i < max_args_on_a_line:
|
||||
print " auto& [" + indexes.strip() + "] = std::forward<T>(val);"
|
||||
print " return ::boost::pfr::detail::make_tuple_of_references(" + indexes.strip() + ");"
|
||||
else:
|
||||
print " auto& ["
|
||||
print indexes
|
||||
print " ] = std::forward<T>(val);"
|
||||
print ""
|
||||
print " return ::boost::pfr::detail::make_tuple_of_references("
|
||||
print indexes
|
||||
print " );"
|
||||
|
||||
print "}\n"
|
||||
|
||||
print EPILOGUE
|
||||
4
misc/generate_single.sh
Normal file
4
misc/generate_single.sh
Normal file
@@ -0,0 +1,4 @@
|
||||
cat ../include/boost/pfr/core.hpp
|
||||
sed -e '1,/boost\/pfr/d' ../include/boost/pfr/functors.hpp
|
||||
sed -e '1,/boost\/pfr/d' ../include/boost/pfr/flat_functions_for.hpp
|
||||
sed -e '1,/boost\/pfr/d' ../include/boost/pfr/flat_ops.hpp
|
||||
29
test/Jamfile.v2
Normal file
29
test/Jamfile.v2
Normal file
@@ -0,0 +1,29 @@
|
||||
# Copyright (C) 2016, Antony Polukhin.
|
||||
#
|
||||
# Use, modification and distribution is subject to 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)
|
||||
#
|
||||
|
||||
test-suite pfr
|
||||
:
|
||||
[ run core.cpp ]
|
||||
[ run minimal.cpp ]
|
||||
[ run count_fields_on_chars.cpp ]
|
||||
# [ run count_fields_on_ints.cpp ]
|
||||
# [ run count_fields_on_long_longs.cpp ]
|
||||
# [ run count_fields_on_shorts.cpp ]
|
||||
[ run count_fields_on_void_ptrs.cpp ]
|
||||
[ run std_interactions.cpp ]
|
||||
[ run flat_functions_for.cpp ]
|
||||
[ run flat_ops.cpp ]
|
||||
[ run global_flat_ops.cpp ]
|
||||
[ compile-fail non_aggregate1.cpp ]
|
||||
[ compile-fail non_aggregate2.cpp ]
|
||||
[ compile-fail bitfields.cpp ]
|
||||
[ run motivating_example.cpp ]
|
||||
[ run ../example/examples.cpp ]
|
||||
[ run only_fields_count.cpp ]
|
||||
;
|
||||
|
||||
|
||||
23
test/bitfields.cpp
Normal file
23
test/bitfields.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
// 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/core.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
struct bf {
|
||||
unsigned int i1: 1;
|
||||
unsigned int i2: 1;
|
||||
unsigned int i3: 1;
|
||||
unsigned int i4: 1;
|
||||
unsigned int i5: 1;
|
||||
unsigned int i6: 1;
|
||||
};
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::flat_tuple_size<bf>::value; // Must be a compile time error
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
709
test/core.cpp
Normal file
709
test/core.cpp
Normal file
@@ -0,0 +1,709 @@
|
||||
// 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)
|
||||
|
||||
//#define BOOST_PFR_RELAX_POD_REQUIREMENT
|
||||
#include <boost/pfr.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
//#include <boost/type_index.hpp> // for debugging
|
||||
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#include <tuple>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <unordered_set>
|
||||
#include <cstring>
|
||||
|
||||
using namespace boost::pfr;
|
||||
|
||||
template <std::size_t I, class T>
|
||||
void print(T& f) {
|
||||
std::cout << flat_get<I>(f) << "\t\t"
|
||||
<< typeid(flat_tuple_element_t<I, T>).name()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
|
||||
struct make_my_life_harder { int a0; short a1; };
|
||||
struct make_my_life_even_more_harder { unsigned int b0; unsigned short b1; make_my_life_harder cr;};
|
||||
struct foo {
|
||||
unsigned char v0;
|
||||
unsigned int v1;
|
||||
unsigned short v2;
|
||||
unsigned long long v3;
|
||||
unsigned char v4and5[2];
|
||||
int v6;
|
||||
std::size_t v7;
|
||||
int* v8;
|
||||
const void* v9;
|
||||
int const**const volatile**volatile** v10;
|
||||
const double v11;
|
||||
make_my_life_harder v12and13;
|
||||
make_my_life_even_more_harder v14and15andv16and17;
|
||||
};
|
||||
|
||||
void test_print() {
|
||||
foo f {
|
||||
'A', 11, 12, 13, {'B', 'C'}, 16, 17, 0, 0, 0, 30.1
|
||||
, {18, 19}
|
||||
, {20, 21, {22, 23}}
|
||||
};
|
||||
print<0>(f); print<1>(f); print<2>(f);
|
||||
print<3>(f); print<4>(f); print<5>(f);
|
||||
print<6>(f); print<7>(f); print<8>(f);
|
||||
print<9>(f); print<10>(f); print<11>(f);
|
||||
print<12>(f); print<13>(f); print<14>(f);
|
||||
print<15>(f); print<16>(f); print<17>(f);
|
||||
static_assert(flat_tuple_size_v<foo> == 18, "failed tuple size check");
|
||||
|
||||
int a[] = {0, 1, 2, 3};
|
||||
std::cout << '\n' << flat_get<1>(a) << std::endl;
|
||||
|
||||
int b[2][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}};
|
||||
std::cout << flat_get<4>(b) << std::endl;
|
||||
|
||||
int i = 777;
|
||||
std::cout << flat_get<0>(i) << std::endl;
|
||||
}
|
||||
|
||||
void test_runtime(const foo& f) {
|
||||
BOOST_TEST_EQ( flat_get<0>(f), f.v0);
|
||||
BOOST_TEST_EQ( flat_get<1>(f), f.v1);
|
||||
BOOST_TEST_EQ( flat_get<2>(f), f.v2);
|
||||
BOOST_TEST_EQ( flat_get<3>(f), f.v3);
|
||||
BOOST_TEST_EQ( flat_get<4>(f), f.v4and5[0]);
|
||||
BOOST_TEST_EQ( flat_get<5>(f), f.v4and5[1]);
|
||||
BOOST_TEST_EQ( flat_get<6>(f), f.v6);
|
||||
BOOST_TEST_EQ( flat_get<7>(f), f.v7);
|
||||
BOOST_TEST_EQ( flat_get<8>(f), f.v8);
|
||||
BOOST_TEST_EQ( flat_get<9>(f), f.v9);
|
||||
BOOST_TEST_EQ( flat_get<10>(f), f.v10);
|
||||
BOOST_TEST( flat_get<11>(f) < f.v11 + 0.001); BOOST_TEST( flat_get<11>(f) > f.v11 - 0.001);
|
||||
BOOST_TEST_EQ( flat_get<12>(f), f.v12and13.a0);
|
||||
BOOST_TEST_EQ( flat_get<13>(f), f.v12and13.a1);
|
||||
BOOST_TEST_EQ( flat_get<14>(f), f.v14and15andv16and17.b0);
|
||||
BOOST_TEST_EQ( flat_get<15>(f), f.v14and15andv16and17.b1);
|
||||
BOOST_TEST_EQ( flat_get<16>(f), f.v14and15andv16and17.cr.a0);
|
||||
BOOST_TEST_EQ( flat_get<17>(f), f.v14and15andv16and17.cr.a1);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void test_compiletime() {
|
||||
constexpr T f{};
|
||||
static_assert(flat_tuple_size_v<foo> == 18, "failed tuple size check");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), decltype((f.v0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<1>(f)), decltype((f.v1))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<2>(f)), decltype((f.v2))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<3>(f)), decltype((f.v3))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<4>(f)), decltype((f.v4and5[0]))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<5>(f)), decltype((f.v4and5[1]))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<6>(f)), decltype((f.v6))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<7>(f)), decltype((f.v7))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<8>(f)), decltype((f.v8))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<9>(f)), decltype((f.v9))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<10>(f)), decltype((f.v10))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<11>(f)), decltype((f.v11))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<12>(f)), decltype((f.v12and13.a0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<13>(f)), decltype((f.v12and13.a1))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<14>(f)), decltype((f.v14and15andv16and17.b0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<15>(f)), decltype((f.v14and15andv16and17.b1))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<16>(f)), decltype((f.v14and15andv16and17.cr.a0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<17>(f)), decltype((f.v14and15andv16and17.cr.a1))>::value, "types missmatch");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr void test_compiletime_array() {
|
||||
{
|
||||
constexpr T f[20] = {0};
|
||||
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
|
||||
}
|
||||
{
|
||||
constexpr T f[2][10] = {{0}};
|
||||
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
|
||||
}
|
||||
{
|
||||
constexpr T f[2][5][2] = {{{0}}};
|
||||
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
|
||||
}
|
||||
}
|
||||
|
||||
void test_with_enums() {
|
||||
enum class my_enum: unsigned {
|
||||
VALUE1 = 17, VALUE2, VALUE3
|
||||
};
|
||||
struct my_struct { my_enum e; int i; short s; };
|
||||
my_struct s {my_enum::VALUE1, 10, 11};
|
||||
std::tuple<unsigned, int, short> t = flat_structure_to_tuple(s);
|
||||
BOOST_TEST_EQ(std::get<0>(t), 17u);
|
||||
BOOST_TEST_EQ(std::get<1>(t), 10);
|
||||
BOOST_TEST_EQ(std::get<2>(t), 11);
|
||||
|
||||
flat_get<1>(s) = 101;
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 101);
|
||||
flat_get<2>(s) = 111;
|
||||
BOOST_TEST_EQ(flat_get<2>(s), 111);
|
||||
|
||||
BOOST_TEST(flat_structure_tie(s) == flat_structure_tie(s));
|
||||
BOOST_TEST(flat_structure_tie(s) == flat_structure_to_tuple(s));
|
||||
BOOST_TEST(flat_structure_tie(s) != t);
|
||||
flat_structure_tie(s) = t;
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 17u);
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 10);
|
||||
BOOST_TEST_EQ(flat_get<2>(s), 11);
|
||||
|
||||
static_assert(std::is_same<
|
||||
int, flat_tuple_element_t<1, my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(std::is_same<
|
||||
short, flat_tuple_element_t<2, my_struct>
|
||||
>::value, "");
|
||||
|
||||
|
||||
static_assert(std::is_same<
|
||||
const int, flat_tuple_element_t<1, const my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(std::is_same<
|
||||
volatile short, flat_tuple_element_t<2, volatile my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(std::is_same<
|
||||
const volatile short, flat_tuple_element_t<2, const volatile my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(
|
||||
3 == flat_tuple_size_v<const volatile my_struct>,
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
void test_comparable_struct() {
|
||||
struct comparable_struct {
|
||||
int i; short s; char data[50]; bool bl; int a,b,c,d,e,f;
|
||||
};
|
||||
using namespace flat_ops;
|
||||
|
||||
comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
|
||||
comparable_struct s2 = s1;
|
||||
comparable_struct s3 {0, 1, "Hello", false, 6,7,8,9,10,11111};
|
||||
BOOST_TEST(s1 == s2);
|
||||
BOOST_TEST(s1 <= s2);
|
||||
BOOST_TEST(s1 >= s2);
|
||||
BOOST_TEST(!(s1 != s2));
|
||||
BOOST_TEST(!(s1 == s3));
|
||||
BOOST_TEST(s1 != s3);
|
||||
BOOST_TEST(s1 < s3);
|
||||
BOOST_TEST(s3 > s2);
|
||||
BOOST_TEST(s1 <= s3);
|
||||
BOOST_TEST(s3 >= s2);
|
||||
|
||||
std::cout << s1 << std::endl;
|
||||
|
||||
comparable_struct s4;
|
||||
std::stringstream ss;
|
||||
ss.exceptions ( std::ios::failbit);
|
||||
ss << s1;
|
||||
ss >> s4;
|
||||
std::cout << s4 << std::endl;
|
||||
BOOST_TEST(s1 == s4);
|
||||
int i = 1, j = 2;
|
||||
BOOST_TEST_NE(i, j);
|
||||
}
|
||||
|
||||
void test_empty_struct() {
|
||||
struct empty {};
|
||||
using namespace flat_ops;
|
||||
|
||||
std::cout << empty{} << std::endl;
|
||||
|
||||
BOOST_TEST(empty{} == empty{});
|
||||
}
|
||||
|
||||
|
||||
void test_pods_with_int_operators() {
|
||||
using namespace flat_ops;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::is_pod<int>{};
|
||||
int i = 0;
|
||||
ss >> i;
|
||||
BOOST_TEST_EQ(i, 1);
|
||||
std::cout << i << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void test_struct_with_single_field() {
|
||||
struct f1 { int i; };
|
||||
using namespace flat_ops;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << f1{ 777 };
|
||||
f1 var{};
|
||||
ss >> var;
|
||||
BOOST_TEST_EQ(var.i, 777);
|
||||
BOOST_TEST(var == f1{ 777 });
|
||||
BOOST_TEST(var != f1{ 778 });
|
||||
|
||||
BOOST_TEST(var <= f1{ 777 });
|
||||
BOOST_TEST(var <= f1{ 778 });
|
||||
BOOST_TEST(var < f1{ 778 });
|
||||
|
||||
BOOST_TEST(var >= f1{ 777 });
|
||||
BOOST_TEST(var >= f1{ 776 });
|
||||
BOOST_TEST(var > f1{ 776 });
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
void test_with_contatiners() {
|
||||
struct testing { bool b1, b2; int i; };
|
||||
struct testing2 { bool b1, b2; int i; };
|
||||
std::set<testing, Comparator > t{
|
||||
{true, true, 100},
|
||||
{false, true, 100},
|
||||
{true, false, 100},
|
||||
{true, true, 101}
|
||||
};
|
||||
|
||||
BOOST_TEST(t.find({true, true, 100}) != t.end());
|
||||
BOOST_TEST_EQ(t.count({true, true, 100}), 1u);
|
||||
BOOST_TEST(t.find(testing2{true, true, 100}) != t.end());
|
||||
|
||||
std::set<testing2, Comparator > t2{
|
||||
{true, true, 101},
|
||||
{true, true, 100},
|
||||
{true, false, 100},
|
||||
{false, true, 100}
|
||||
};
|
||||
|
||||
BOOST_TEST(std::equal(t.begin(), t.end(), t2.begin(), t2.end(), flat_equal_to<>{}));
|
||||
BOOST_TEST(!std::equal(t.begin(), t.end(), t2.begin(), t2.end(), flat_not_equal<>{}));
|
||||
|
||||
std::vector<testing> res;
|
||||
std::set_intersection(t.begin(), t.end(), t2.begin(), t2.end(),
|
||||
std::back_inserter(res), Comparator{});
|
||||
|
||||
BOOST_TEST_EQ(res.size(), 4u);
|
||||
}
|
||||
|
||||
void test_with_user_defined_constructor() {
|
||||
struct pr {
|
||||
int i;
|
||||
short s;
|
||||
|
||||
pr() = default;
|
||||
pr(const pr&) = default;
|
||||
pr(pr&&) = default;
|
||||
pr(int ii, short is) noexcept
|
||||
: i(ii), s(is)
|
||||
{}
|
||||
};
|
||||
|
||||
pr p{1, 2};
|
||||
|
||||
//assert(flat_get<1>(p) == 2); // Compilation error
|
||||
}
|
||||
|
||||
void test_hash() {
|
||||
struct almost_pair { int i; short s; };
|
||||
std::unordered_set<almost_pair, flat_hash<almost_pair>, flat_equal_to<> > s;
|
||||
s.insert({0, 1});
|
||||
s.insert({1, 0});
|
||||
s.insert({1, 1});
|
||||
|
||||
BOOST_TEST_EQ(s.size(), 3u);
|
||||
flat_hash<almost_pair> hs;
|
||||
BOOST_TEST_NE(hs({0, 1}), hs({1, 0}));
|
||||
BOOST_TEST_EQ(hs({0, 1}), hs({0, 1}));
|
||||
BOOST_TEST_EQ(hs({1, 1}), hs({1, 1}));
|
||||
BOOST_TEST_NE(hs({0, 0}), hs({1, 1}));
|
||||
|
||||
struct single_field { int i; };
|
||||
BOOST_TEST_NE(flat_hash<single_field>()({1}), std::hash<int>()(1));
|
||||
BOOST_TEST_NE(flat_hash<single_field>()({199}), std::hash<int>()(199));
|
||||
}
|
||||
|
||||
// Test case by Lisa Lippincott
|
||||
void test_alignment_with_nested_structure() {
|
||||
struct A0 {
|
||||
short s;
|
||||
char c;
|
||||
};
|
||||
|
||||
struct B0 {
|
||||
A0 a;
|
||||
char c1;
|
||||
char c2;
|
||||
};
|
||||
|
||||
B0 test_struct;
|
||||
std::memset(&test_struct, 0, sizeof(test_struct));
|
||||
test_struct.a.s = 0;
|
||||
test_struct.a.c = '1';
|
||||
test_struct.c1 = '2';
|
||||
test_struct.c2 = '3';
|
||||
BOOST_TEST_EQ(flat_get<0>(test_struct), 0);
|
||||
BOOST_TEST_EQ(flat_get<1>(test_struct), '1');
|
||||
BOOST_TEST_EQ(flat_get<2>(test_struct), '2');
|
||||
BOOST_TEST_EQ(flat_get<3>(test_struct), '3');
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <std::size_t... I>
|
||||
void test_and_debug_internals(std::index_sequence<I...>) {
|
||||
struct A0 {
|
||||
short s;
|
||||
char c;
|
||||
};
|
||||
|
||||
A0 a0 { 3, '4' };
|
||||
BOOST_TEST_EQ(boost::pfr::flat_get<0>(a0), 3);
|
||||
BOOST_TEST_EQ(boost::pfr::flat_get<1>(a0), '4');
|
||||
|
||||
struct A1 {
|
||||
int i;
|
||||
};
|
||||
|
||||
struct B1 {
|
||||
A1 a;
|
||||
int j;
|
||||
};
|
||||
|
||||
B1 b1 { {5}, 6 };
|
||||
BOOST_TEST_EQ(boost::pfr::flat_get<0>(b1), 5);
|
||||
BOOST_TEST_EQ(boost::pfr::flat_get<1>(b1), 6);
|
||||
/*
|
||||
struct B0 {
|
||||
A0 a;
|
||||
char c1;
|
||||
char c2;
|
||||
};
|
||||
|
||||
typedef B0 type;
|
||||
typedef B0 T;
|
||||
|
||||
using namespace boost::pfr::detail;
|
||||
constexpr auto a = flat_array_of_type_ids<T>();
|
||||
(void)a; // `a` is unused if T is an empty type
|
||||
|
||||
constexpr size_array<a.size()> skips_in_subtuples {{
|
||||
a.count_from_opening_till_matching_parenthis_seq(I, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag)...
|
||||
}};
|
||||
|
||||
constexpr size_array<sizeof...(I) + 1> indexes_in_subtuples_uncleanuped {{ 1, 1 + I...}};
|
||||
constexpr auto indexes_plus_1_and_zeros_as_skips = remove_skips(indexes_in_subtuples_uncleanuped, skips_in_subtuples);
|
||||
constexpr auto new_size = size_t_<indexes_plus_1_and_zeros_as_skips.count_nonzeros()>{};
|
||||
constexpr auto indexes = resize_dropping_zeros_and_decrementing(new_size, indexes_plus_1_and_zeros_as_skips);
|
||||
static_assert(indexes.data[0] == 0, "");
|
||||
static_assert(indexes.data[1] == 4, "");
|
||||
static_assert(indexes.data[2] == 5, "");
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
decltype(boost::pfr::detail::as_flat_tuple_impl<type>(
|
||||
std::make_index_sequence< decltype(boost::pfr::detail::flat_array_of_type_ids<type>())::size() >()
|
||||
)),
|
||||
boost::pfr::detail::sequence_tuple::tuple<boost::pfr::detail::sequence_tuple::tuple<short, char>, char, char>
|
||||
>::value,
|
||||
""
|
||||
);
|
||||
|
||||
constexpr auto res = as_flat_tuple_impl<foo>(
|
||||
std::make_index_sequence< decltype(flat_array_of_type_ids<foo>())::size() >()
|
||||
);
|
||||
auto afoo = flat_array_of_type_ids<foo>();
|
||||
std::cerr << "\n\n";
|
||||
for (std::size_t i = 0; i < afoo.size(); ++i) {
|
||||
std::cerr << afoo.data[i] << ' ';
|
||||
}
|
||||
|
||||
std::cerr << boost::typeindex::type_id<decltype(res)>() << "\n\n";*/
|
||||
}
|
||||
|
||||
|
||||
// test by Alexey Moiseytsev
|
||||
void another_test_with_unusual_alignment() {
|
||||
struct nested {
|
||||
char c0;
|
||||
char c1;
|
||||
int i0;
|
||||
short s0;
|
||||
char c2;
|
||||
};
|
||||
|
||||
struct pair {
|
||||
nested n0;
|
||||
nested n1;
|
||||
};
|
||||
|
||||
// layout:
|
||||
// offset struct tuple
|
||||
// 0 n0.c0 n0.c0
|
||||
// 1 n0.c1 n0.c1
|
||||
// 2 padding padding
|
||||
// 3 padding padding
|
||||
// 4 n0.i0 n0.i0
|
||||
// 5 n0.i0 n0.i0
|
||||
// 6 n0.i0 n0.i0
|
||||
// 7 n0.i0 n0.i0
|
||||
// 8 n0.s0 n0.s0
|
||||
// 9 n0.s0 n0.s0
|
||||
// 10 n0.c2 n0.c2
|
||||
// 11 padding n1.c0 !!!
|
||||
// 12 n1.c0 n1.c1 !!!
|
||||
// 13 n1.c1 padding !!!
|
||||
// 14 padding padding
|
||||
// 15 padding padding
|
||||
// 16 n1.i0 n1.i0
|
||||
// 17 n1.i0 n1.i0
|
||||
// 18 n1.i0 n1.i0
|
||||
// 19 n1.i0 n1.i0
|
||||
// 20 n1.s0 n1.s0
|
||||
// 21 n1.s0 n1.s0
|
||||
// 22 n1.c2 n1.c2
|
||||
// 23 padding padding
|
||||
|
||||
pair s{{'q', 'w', 12, 32, 'e'}, {'a', 's', 24, 64, 'd'}};
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 'q');
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 'w');
|
||||
BOOST_TEST_EQ(flat_get<2>(s), 12);
|
||||
BOOST_TEST_EQ(flat_get<3>(s), 32);
|
||||
BOOST_TEST_EQ(flat_get<4>(s), 'e');
|
||||
|
||||
BOOST_TEST_EQ(flat_get<5>(s), 'a');
|
||||
BOOST_TEST_EQ(flat_get<6>(s), 's');
|
||||
BOOST_TEST_EQ(flat_get<7>(s), 24);
|
||||
BOOST_TEST_EQ(flat_get<8>(s), 64);
|
||||
BOOST_TEST_EQ(flat_get<9>(s), 'd');
|
||||
}
|
||||
|
||||
#ifdef BOOST_PFR_RELAX_POD_REQUIREMENT
|
||||
// Test inspired by Anton Bikineev
|
||||
void test_structure_with_default_values() {
|
||||
struct test_me {
|
||||
int i = 2;
|
||||
short s = 14;
|
||||
};
|
||||
|
||||
test_me s;
|
||||
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 2);
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 14);
|
||||
}
|
||||
|
||||
// Test inspired by Anton Bikineev
|
||||
void test_st_layout_structure_with_non_constexpr_type() {
|
||||
/* TODO: fixme
|
||||
struct non_literal_structure {
|
||||
int i1 = 3;
|
||||
short s1 = 15;
|
||||
|
||||
non_literal_structure() = delete;
|
||||
non_literal_structure(const non_literal_structure&) = delete;
|
||||
non_literal_structure(non_literal_structure&&) = default;
|
||||
non_literal_structure& operator=(const non_literal_structure&) = delete;
|
||||
non_literal_structure& operator=(non_literal_structure&&) = delete;
|
||||
};
|
||||
struct test_me {
|
||||
int i = 2;
|
||||
short s = 14;
|
||||
non_literal_structure nonlit{};
|
||||
};
|
||||
|
||||
BOOST_TEST_EQ(tuple_size_v<test_me>, 3);
|
||||
|
||||
test_me s{};
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 2);
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 14);
|
||||
BOOST_TEST_EQ(flat_get<2>(s), 3);
|
||||
BOOST_TEST_EQ(flat_get<3>(s), 15);*/
|
||||
}
|
||||
|
||||
// Test inspired by Anton Bikineev
|
||||
void test_structure_with_user_provided_default_constructor() {
|
||||
struct test_me {
|
||||
short s = 2;
|
||||
constexpr test_me(short){}
|
||||
};
|
||||
|
||||
test_me s{0};
|
||||
(void)s;
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 2); // TODO: fix compile time error message
|
||||
}
|
||||
#endif
|
||||
/*
|
||||
void test_copy_only_pod() {
|
||||
struct copy_only_pod {
|
||||
int i1;
|
||||
short s1;
|
||||
|
||||
copy_only_pod() = delete;
|
||||
copy_only_pod(copy_only_pod&&) = delete;
|
||||
|
||||
copy_only_pod(const copy_only_pod&) = default;
|
||||
copy_only_pod& operator=(const copy_only_pod&) = delete;
|
||||
copy_only_pod& operator=(copy_only_pod&&) = delete;
|
||||
};
|
||||
|
||||
copy_only_pod s{2, 14};
|
||||
BOOST_TEST_EQ(tuple_size_v<copy_only_pod>, 2u);
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 2);
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 14);
|
||||
|
||||
|
||||
struct with_reference {
|
||||
int& i;
|
||||
int* p;
|
||||
};
|
||||
BOOST_TEST_EQ(tuple_size_v<with_reference>, 2u);
|
||||
|
||||
|
||||
struct with_nested_copy_only_pod {
|
||||
int i;
|
||||
copy_only_pod p;
|
||||
};
|
||||
BOOST_TEST_EQ(tuple_size_v<with_nested_copy_only_pod>, 2u);
|
||||
|
||||
with_nested_copy_only_pod np{2, {3, 4}};
|
||||
BOOST_TEST_EQ(flat_get<0>(np), 2);
|
||||
BOOST_TEST_EQ(flat_get<1>(np), 3);
|
||||
BOOST_TEST_EQ(flat_get<2>(np), 4);
|
||||
} // */
|
||||
/* // TODO: think of something with it!
|
||||
void test_move_only_pod() {
|
||||
struct move_only_pod {
|
||||
int i1;
|
||||
short s1;
|
||||
|
||||
move_only_pod() = delete;
|
||||
//move_only_pod(move_only_pod&&) = delete;
|
||||
|
||||
move_only_pod(const move_only_pod&) = delete;
|
||||
move_only_pod(move_only_pod&&) = default;
|
||||
move_only_pod& operator=(const move_only_pod&) = delete;
|
||||
move_only_pod& operator=(move_only_pod&&) = delete;
|
||||
};
|
||||
|
||||
move_only_pod s{2, 14};
|
||||
BOOST_TEST_EQ(tuple_size_v<move_only_pod>, 2u);
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 2);
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 14);
|
||||
|
||||
|
||||
struct with_reference {
|
||||
int& i;
|
||||
int* p;
|
||||
};
|
||||
BOOST_TEST_EQ(tuple_size_v<with_reference>, 2u);
|
||||
|
||||
|
||||
struct with_nested_move_only_pod {
|
||||
int i;
|
||||
short s;
|
||||
move_only_pod p;
|
||||
char c;
|
||||
};
|
||||
BOOST_TEST_EQ(tuple_size_v<with_nested_move_only_pod>, 4u);
|
||||
|
||||
// with_nested_move_only_pod np{2, {3, 4}};
|
||||
// BOOST_TEST_EQ(flat_get<0>(np), 2);
|
||||
// BOOST_TEST_EQ(flat_get<1>(np), 3);
|
||||
// BOOST_TEST_EQ(flat_get<2>(np), 4);
|
||||
} // */
|
||||
|
||||
int main() {
|
||||
test_compiletime<foo>();
|
||||
test_compiletime_array<int>();
|
||||
test_compiletime_array<void*>();
|
||||
test_compiletime_array<const void*>();
|
||||
test_compiletime_array<char>();
|
||||
test_compiletime_array<char const volatile*>();
|
||||
{
|
||||
foo f {
|
||||
'A', 11, 12, 13, {'B', 'C'}, 16, 17, 0, 0, 0, 30.1
|
||||
, {18, 19}
|
||||
, {20, 21, {22, 23}}
|
||||
};
|
||||
test_runtime(f);
|
||||
}
|
||||
{
|
||||
foo f {
|
||||
'\0', 12437, 1212, 13, {'1', '7'}, 163, 1723, 0, 0, 0, 3000.1
|
||||
, {-18, -19}
|
||||
, {656565, 65535, {-22, -23}}
|
||||
};
|
||||
test_runtime(f);
|
||||
}
|
||||
|
||||
test_with_enums();
|
||||
test_comparable_struct();
|
||||
test_empty_struct();
|
||||
test_pods_with_int_operators();
|
||||
test_struct_with_single_field();
|
||||
|
||||
test_with_contatiners<flat_less<>>();
|
||||
test_with_contatiners<flat_greater<>>();
|
||||
|
||||
test_print();
|
||||
|
||||
test_with_user_defined_constructor();
|
||||
test_hash();
|
||||
|
||||
struct non_pod1 {
|
||||
std::string s;
|
||||
std::vector<int> v;
|
||||
int i;
|
||||
|
||||
struct foo {
|
||||
std::string s2;
|
||||
} f;
|
||||
};
|
||||
static_assert(tuple_size<non_pod1>::value == 4, "Must not be a compile error");
|
||||
|
||||
|
||||
struct non_pod2 {
|
||||
unsigned ui1: 1;
|
||||
unsigned ui2: 2;
|
||||
|
||||
std::string s;
|
||||
std::vector<int> v;
|
||||
int i;
|
||||
|
||||
struct foo {
|
||||
std::string s2;
|
||||
} f;
|
||||
};
|
||||
static_assert(tuple_size<non_pod2>::value == 6, "Must not be a compile error even with bitfields");
|
||||
|
||||
int i_2dimens[2][2] = {{10, 11}, {12, 13} };
|
||||
static_assert(tuple_size<decltype(i_2dimens)>::value == 4, "");
|
||||
static_assert(flat_tuple_size<decltype(i_2dimens)>::value == 4, "");
|
||||
|
||||
test_and_debug_internals(std::make_index_sequence<6>{});
|
||||
test_alignment_with_nested_structure();
|
||||
another_test_with_unusual_alignment();
|
||||
|
||||
#ifdef BOOST_PFR_RELAX_POD_REQUIREMENT
|
||||
test_structure_with_default_values();
|
||||
test_st_layout_structure_with_non_constexpr_type();
|
||||
test_structure_with_user_provided_default_constructor();
|
||||
#endif
|
||||
|
||||
//test_copy_only_pod();
|
||||
//test_move_only_pod();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
659
test/core.cpp.autosave
Normal file
659
test/core.cpp.autosave
Normal file
@@ -0,0 +1,659 @@
|
||||
// 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)
|
||||
|
||||
//#define BOOST_PFR_RELAX_POD_REQUIREMENT
|
||||
#include <boost/pfr.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
//#include <boost/type_index.hpp> // for debugging
|
||||
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#include <tuple>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <vector>
|
||||
#include <algorithm>
|
||||
#include <unordered_set>
|
||||
#include <cstring>
|
||||
|
||||
using namespace boost::pfr;
|
||||
|
||||
template <std::size_t I, class T>
|
||||
void print(T& f) {
|
||||
std::cout << flat_get<I>(f) << "\t\t"
|
||||
<< typeid(flat_tuple_element_t<I, T>).name()
|
||||
<< std::endl;
|
||||
}
|
||||
|
||||
|
||||
struct make_my_life_harder { int a0; short a1; };
|
||||
struct make_my_life_even_more_harder { unsigned int b0; unsigned short b1; make_my_life_harder cr;};
|
||||
struct foo {
|
||||
unsigned char v0;
|
||||
unsigned int v1;
|
||||
unsigned short v2;
|
||||
unsigned long long v3;
|
||||
unsigned char v4and5[2];
|
||||
int v6;
|
||||
std::size_t v7;
|
||||
int* v8;
|
||||
const void* v9;
|
||||
int const**const volatile**volatile** v10;
|
||||
const double v11;
|
||||
make_my_life_harder v12and13;
|
||||
make_my_life_even_more_harder v14and15andv16and17;
|
||||
};
|
||||
|
||||
void test_print() {
|
||||
foo f {
|
||||
'A', 11, 12, 13, {'B', 'C'}, 16, 17, 0, 0, 0, 30.1
|
||||
, {18, 19}
|
||||
, {20, 21, {22, 23}}
|
||||
};
|
||||
print<0>(f); print<1>(f); print<2>(f);
|
||||
print<3>(f); print<4>(f); print<5>(f);
|
||||
print<6>(f); print<7>(f); print<8>(f);
|
||||
print<9>(f); print<10>(f); print<11>(f);
|
||||
print<12>(f); print<13>(f); print<14>(f);
|
||||
print<15>(f); print<16>(f); print<17>(f);
|
||||
static_assert(flat_tuple_size_v<foo> == 18, "failed tuple size check");
|
||||
|
||||
int a[] = {0, 1, 2, 3};
|
||||
std::cout << '\n' << flat_get<1>(a) << std::endl;
|
||||
|
||||
int b[2][4] = {{0, 1, 2, 3}, {4, 5, 6, 7}};
|
||||
std::cout << flat_get<4>(b) << std::endl;
|
||||
|
||||
int i = 777;
|
||||
std::cout << flat_get<0>(i) << std::endl;
|
||||
}
|
||||
|
||||
void test_runtime(const foo& f) {
|
||||
BOOST_TEST_EQ( flat_get<0>(f), f.v0);
|
||||
BOOST_TEST_EQ( flat_get<1>(f), f.v1);
|
||||
BOOST_TEST_EQ( flat_get<2>(f), f.v2);
|
||||
BOOST_TEST_EQ( flat_get<3>(f), f.v3);
|
||||
BOOST_TEST_EQ( flat_get<4>(f), f.v4and5[0]);
|
||||
BOOST_TEST_EQ( flat_get<5>(f), f.v4and5[1]);
|
||||
BOOST_TEST_EQ( flat_get<6>(f), f.v6);
|
||||
BOOST_TEST_EQ( flat_get<7>(f), f.v7);
|
||||
BOOST_TEST_EQ( flat_get<8>(f), f.v8);
|
||||
BOOST_TEST_EQ( flat_get<9>(f), f.v9);
|
||||
BOOST_TEST_EQ( flat_get<10>(f), f.v10);
|
||||
BOOST_TEST( flat_get<11>(f) < f.v11 + 0.001); BOOST_TEST( flat_get<11>(f) > f.v11 - 0.001);
|
||||
BOOST_TEST_EQ( flat_get<12>(f), f.v12and13.a0);
|
||||
BOOST_TEST_EQ( flat_get<13>(f), f.v12and13.a1);
|
||||
BOOST_TEST_EQ( flat_get<14>(f), f.v14and15andv16and17.b0);
|
||||
BOOST_TEST_EQ( flat_get<15>(f), f.v14and15andv16and17.b1);
|
||||
BOOST_TEST_EQ( flat_get<16>(f), f.v14and15andv16and17.cr.a0);
|
||||
BOOST_TEST_EQ( flat_get<17>(f), f.v14and15andv16and17.cr.a1);
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void test_compiletime() {
|
||||
constexpr T f{};
|
||||
static_assert(flat_tuple_size_v<foo> == 18, "failed tuple size check");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), decltype((f.v0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<1>(f)), decltype((f.v1))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<2>(f)), decltype((f.v2))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<3>(f)), decltype((f.v3))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<4>(f)), decltype((f.v4and5[0]))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<5>(f)), decltype((f.v4and5[1]))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<6>(f)), decltype((f.v6))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<7>(f)), decltype((f.v7))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<8>(f)), decltype((f.v8))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<9>(f)), decltype((f.v9))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<10>(f)), decltype((f.v10))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<11>(f)), decltype((f.v11))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<12>(f)), decltype((f.v12and13.a0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<13>(f)), decltype((f.v12and13.a1))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<14>(f)), decltype((f.v14and15andv16and17.b0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<15>(f)), decltype((f.v14and15andv16and17.b1))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<16>(f)), decltype((f.v14and15andv16and17.cr.a0))>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<17>(f)), decltype((f.v14and15andv16and17.cr.a1))>::value, "types missmatch");
|
||||
}
|
||||
|
||||
template <class T>
|
||||
constexpr void test_compiletime_array() {
|
||||
{
|
||||
constexpr T f[20] = {0};
|
||||
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
|
||||
}
|
||||
{
|
||||
constexpr T f[2][10] = {{0}};
|
||||
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
|
||||
}
|
||||
{
|
||||
constexpr T f[2][5][2] = {{{0}}};
|
||||
static_assert(flat_tuple_size_v<decltype(f)> == 20, "failed tuple size check for array");
|
||||
static_assert( std::is_same< decltype(flat_get<0>(f)), T const&>::value, "types missmatch");
|
||||
static_assert( std::is_same< decltype(flat_get<19>(f)), T const&>::value, "types missmatch");
|
||||
}
|
||||
}
|
||||
|
||||
void test_with_enums() {
|
||||
enum class my_enum: unsigned {
|
||||
VALUE1 = 17, VALUE2, VALUE3
|
||||
};
|
||||
struct my_struct { my_enum e; int i; short s; };
|
||||
my_struct s {my_enum::VALUE1, 10, 11};
|
||||
std::tuple<unsigned, int, short> t = flat_structure_to_tuple(s);
|
||||
BOOST_TEST_EQ(std::get<0>(t), 17u);
|
||||
BOOST_TEST_EQ(std::get<1>(t), 10);
|
||||
BOOST_TEST_EQ(std::get<2>(t), 11);
|
||||
|
||||
flat_get<1>(s) = 101;
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 101);
|
||||
flat_get<2>(s) = 111;
|
||||
BOOST_TEST_EQ(flat_get<2>(s), 111);
|
||||
|
||||
BOOST_TEST(flat_structure_tie(s) == flat_structure_tie(s));
|
||||
BOOST_TEST(flat_structure_tie(s) == flat_structure_to_tuple(s));
|
||||
BOOST_TEST(flat_structure_tie(s) != t);
|
||||
flat_structure_tie(s) = t;
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 17u);
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 10);
|
||||
BOOST_TEST_EQ(flat_get<2>(s), 11);
|
||||
|
||||
static_assert(std::is_same<
|
||||
int, flat_tuple_element_t<1, my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(std::is_same<
|
||||
short, flat_tuple_element_t<2, my_struct>
|
||||
>::value, "");
|
||||
|
||||
|
||||
static_assert(std::is_same<
|
||||
const int, flat_tuple_element_t<1, const my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(std::is_same<
|
||||
volatile short, flat_tuple_element_t<2, volatile my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(std::is_same<
|
||||
const volatile short, flat_tuple_element_t<2, const volatile my_struct>
|
||||
>::value, "");
|
||||
|
||||
static_assert(
|
||||
3 == flat_tuple_size_v<const volatile my_struct>,
|
||||
""
|
||||
);
|
||||
}
|
||||
|
||||
void test_comparable_struct() {
|
||||
struct comparable_struct {
|
||||
int i; short s; char data[50]; bool bl; int a,b,c,d,e,f;
|
||||
};
|
||||
using namespace flat_ops;
|
||||
|
||||
comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
|
||||
comparable_struct s2 = s1;
|
||||
comparable_struct s3 {0, 1, "Hello", false, 6,7,8,9,10,11111};
|
||||
BOOST_TEST(s1 == s2);
|
||||
BOOST_TEST(s1 <= s2);
|
||||
BOOST_TEST(s1 >= s2);
|
||||
BOOST_TEST(!(s1 != s2));
|
||||
BOOST_TEST(!(s1 == s3));
|
||||
BOOST_TEST(s1 != s3);
|
||||
BOOST_TEST(s1 < s3);
|
||||
BOOST_TEST(s3 > s2);
|
||||
BOOST_TEST(s1 <= s3);
|
||||
BOOST_TEST(s3 >= s2);
|
||||
|
||||
std::cout << s1 << std::endl;
|
||||
|
||||
comparable_struct s4;
|
||||
std::stringstream ss;
|
||||
ss.exceptions ( std::ios::failbit);
|
||||
ss << s1;
|
||||
ss >> s4;
|
||||
std::cout << s4 << std::endl;
|
||||
BOOST_TEST(s1 == s4);
|
||||
int i = 1, j = 2;
|
||||
BOOST_TEST_NE(i, j);
|
||||
}
|
||||
|
||||
void test_empty_struct() {
|
||||
struct empty {};
|
||||
using namespace flat_ops;
|
||||
|
||||
std::cout << empty{} << std::endl;
|
||||
|
||||
BOOST_TEST(empty{} == empty{});
|
||||
}
|
||||
|
||||
|
||||
void test_pods_with_int_operators() {
|
||||
using namespace flat_ops;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << std::is_pod<int>{};
|
||||
int i = 0;
|
||||
ss >> i;
|
||||
BOOST_TEST_EQ(i, 1);
|
||||
std::cout << i << std::endl;
|
||||
}
|
||||
|
||||
|
||||
void test_struct_with_single_field() {
|
||||
struct f1 { int i; };
|
||||
using namespace flat_ops;
|
||||
|
||||
std::stringstream ss;
|
||||
ss << f1{ 777 };
|
||||
f1 var{};
|
||||
ss >> var;
|
||||
BOOST_TEST_EQ(var.i, 777);
|
||||
BOOST_TEST(var == f1{ 777 });
|
||||
BOOST_TEST(var != f1{ 778 });
|
||||
|
||||
BOOST_TEST(var <= f1{ 777 });
|
||||
BOOST_TEST(var <= f1{ 778 });
|
||||
BOOST_TEST(var < f1{ 778 });
|
||||
|
||||
BOOST_TEST(var >= f1{ 777 });
|
||||
BOOST_TEST(var >= f1{ 776 });
|
||||
BOOST_TEST(var > f1{ 776 });
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
void test_with_contatiners() {
|
||||
struct testing { bool b1, b2; int i; };
|
||||
struct testing2 { bool b1, b2; int i; };
|
||||
std::set<testing, Comparator > t{
|
||||
{true, true, 100},
|
||||
{false, true, 100},
|
||||
{true, false, 100},
|
||||
{true, true, 101}
|
||||
};
|
||||
|
||||
BOOST_TEST(t.find({true, true, 100}) != t.end());
|
||||
BOOST_TEST_EQ(t.count({true, true, 100}), 1u);
|
||||
BOOST_TEST(t.find(testing2{true, true, 100}) != t.end());
|
||||
|
||||
std::set<testing2, Comparator > t2{
|
||||
{true, true, 101},
|
||||
{true, true, 100},
|
||||
{true, false, 100},
|
||||
{false, true, 100}
|
||||
};
|
||||
|
||||
BOOST_TEST(std::equal(t.begin(), t.end(), t2.begin(), t2.end(), flat_equal_to<>{}));
|
||||
BOOST_TEST(!std::equal(t.begin(), t.end(), t2.begin(), t2.end(), flat_not_equal<>{}));
|
||||
|
||||
std::vector<testing> res;
|
||||
std::set_intersection(t.begin(), t.end(), t2.begin(), t2.end(),
|
||||
std::back_inserter(res), Comparator{});
|
||||
|
||||
BOOST_TEST_EQ(res.size(), 4u);
|
||||
}
|
||||
|
||||
void test_with_user_defined_constructor() {
|
||||
struct pr {
|
||||
int i;
|
||||
short s;
|
||||
|
||||
pr() = default;
|
||||
pr(const pr&) = default;
|
||||
pr(pr&&) = default;
|
||||
pr(int ii, short is) noexcept
|
||||
: i(ii), s(is)
|
||||
{}
|
||||
};
|
||||
|
||||
pr p{1, 2};
|
||||
|
||||
//assert(flat_get<1>(p) == 2); // Compilation error
|
||||
}
|
||||
|
||||
void test_hash() {
|
||||
struct almost_pair { int i; short s; };
|
||||
std::unordered_set<almost_pair, flat_hash<almost_pair>, flat_equal_to<> > s;
|
||||
s.insert({0, 1});
|
||||
s.insert({1, 0});
|
||||
s.insert({1, 1});
|
||||
|
||||
BOOST_TEST_EQ(s.size(), 3u);
|
||||
flat_hash<almost_pair> hs;
|
||||
BOOST_TEST_NE(hs({0, 1}), hs({1, 0}));
|
||||
BOOST_TEST_EQ(hs({0, 1}), hs({0, 1}));
|
||||
BOOST_TEST_EQ(hs({1, 1}), hs({1, 1}));
|
||||
BOOST_TEST_NE(hs({0, 0}), hs({1, 1}));
|
||||
|
||||
struct single_field { int i; };
|
||||
BOOST_TEST_NE(flat_hash<single_field>()({1}), std::hash<int>()(1));
|
||||
BOOST_TEST_NE(flat_hash<single_field>()({199}), std::hash<int>()(199));
|
||||
}
|
||||
|
||||
// Test case by Lisa Lippincott
|
||||
void test_alignment_with_neted_structure() {
|
||||
struct A0 {
|
||||
short s;
|
||||
char c;
|
||||
};
|
||||
|
||||
struct B0 {
|
||||
A0 a;
|
||||
char c1;
|
||||
char c2;
|
||||
};
|
||||
|
||||
B0 test_struct;
|
||||
std::memset(&test_struct, 0, sizeof(test_struct));
|
||||
test_struct.a.s = 0;
|
||||
test_struct.a.c = '1';
|
||||
test_struct.c1 = '2';
|
||||
test_struct.c2 = '3';
|
||||
BOOST_TEST_EQ(flat_get<0>(test_struct), 0);
|
||||
BOOST_TEST_EQ(flat_get<1>(test_struct), '1');
|
||||
BOOST_TEST_EQ(flat_get<2>(test_struct), '2');
|
||||
BOOST_TEST_EQ(flat_get<3>(test_struct), '3');
|
||||
|
||||
}
|
||||
|
||||
|
||||
template <std::size_t... I>
|
||||
void test_and_debug_internals(std::index_sequence<I...>) {
|
||||
struct A0 {
|
||||
short s;
|
||||
char c;
|
||||
};
|
||||
|
||||
A0 a0 { 3, '4' };
|
||||
BOOST_TEST_EQ(boost::pfr::flat_get<0>(a0), 3);
|
||||
BOOST_TEST_EQ(boost::pfr::flat_get<1>(a0), '4');
|
||||
|
||||
struct A1 {
|
||||
int i;
|
||||
};
|
||||
|
||||
struct B1 {
|
||||
A1 a;
|
||||
int j;
|
||||
};
|
||||
|
||||
B1 b1 { {5}, 6 };
|
||||
BOOST_TEST_EQ(boost::pfr::flat_get<0>(b1), 5);
|
||||
BOOST_TEST_EQ(boost::pfr::flat_get<1>(b1), 6);
|
||||
/*
|
||||
struct B0 {
|
||||
A0 a;
|
||||
char c1;
|
||||
char c2;
|
||||
};
|
||||
|
||||
typedef B0 type;
|
||||
typedef B0 T;
|
||||
|
||||
using namespace boost::pfr::detail;
|
||||
constexpr auto a = flat_array_of_type_ids<T>();
|
||||
(void)a; // `a` is unused if T is an empty type
|
||||
|
||||
constexpr size_array<a.size()> skips_in_subtuples {{
|
||||
a.count_from_opening_till_matching_parenthis_seq(I, typeid_conversions::tuple_begin_tag, typeid_conversions::tuple_end_tag)...
|
||||
}};
|
||||
|
||||
constexpr size_array<sizeof...(I) + 1> indexes_in_subtuples_uncleanuped {{ 1, 1 + I...}};
|
||||
constexpr auto indexes_plus_1_and_zeros_as_skips = remove_skips(indexes_in_subtuples_uncleanuped, skips_in_subtuples);
|
||||
constexpr auto new_size = size_t_<indexes_plus_1_and_zeros_as_skips.count_nonzeros()>{};
|
||||
constexpr auto indexes = resize_dropping_zeros_and_decrementing(new_size, indexes_plus_1_and_zeros_as_skips);
|
||||
static_assert(indexes.data[0] == 0, "");
|
||||
static_assert(indexes.data[1] == 4, "");
|
||||
static_assert(indexes.data[2] == 5, "");
|
||||
|
||||
static_assert(
|
||||
std::is_same<
|
||||
decltype(boost::pfr::detail::as_flat_tuple_impl<type>(
|
||||
std::make_index_sequence< decltype(boost::pfr::detail::flat_array_of_type_ids<type>())::size() >()
|
||||
)),
|
||||
boost::pfr::detail::sequence_tuple::tuple<boost::pfr::detail::sequence_tuple::tuple<short, char>, char, char>
|
||||
>::value,
|
||||
""
|
||||
);
|
||||
|
||||
constexpr auto res = as_flat_tuple_impl<foo>(
|
||||
std::make_index_sequence< decltype(flat_array_of_type_ids<foo>())::size() >()
|
||||
);
|
||||
auto afoo = flat_array_of_type_ids<foo>();
|
||||
std::cerr << "\n\n";
|
||||
for (std::size_t i = 0; i < afoo.size(); ++i) {
|
||||
std::cerr << afoo.data[i] << ' ';
|
||||
}
|
||||
|
||||
std::cerr << boost::typeindex::type_id<decltype(res)>() << "\n\n";*/
|
||||
}
|
||||
|
||||
|
||||
// test by Alexey Moiseytsev
|
||||
void another_test_with_unusual_alignment() {
|
||||
struct nested {
|
||||
char c0;
|
||||
char c1;
|
||||
int i0;
|
||||
short s0;
|
||||
char c2;
|
||||
};
|
||||
|
||||
struct pair {
|
||||
nested n0;
|
||||
nested n1;
|
||||
};
|
||||
|
||||
// layout:
|
||||
// offset struct tuple
|
||||
// 0 n0.c0 n0.c0
|
||||
// 1 n0.c1 n0.c1
|
||||
// 2 padding padding
|
||||
// 3 padding padding
|
||||
// 4 n0.i0 n0.i0
|
||||
// 5 n0.i0 n0.i0
|
||||
// 6 n0.i0 n0.i0
|
||||
// 7 n0.i0 n0.i0
|
||||
// 8 n0.s0 n0.s0
|
||||
// 9 n0.s0 n0.s0
|
||||
// 10 n0.c2 n0.c2
|
||||
// 11 padding n1.c0 !!!
|
||||
// 12 n1.c0 n1.c1 !!!
|
||||
// 13 n1.c1 padding !!!
|
||||
// 14 padding padding
|
||||
// 15 padding padding
|
||||
// 16 n1.i0 n1.i0
|
||||
// 17 n1.i0 n1.i0
|
||||
// 18 n1.i0 n1.i0
|
||||
// 19 n1.i0 n1.i0
|
||||
// 20 n1.s0 n1.s0
|
||||
// 21 n1.s0 n1.s0
|
||||
// 22 n1.c2 n1.c2
|
||||
// 23 padding padding
|
||||
|
||||
pair s{{'q', 'w', 12, 32, 'e'}, {'a', 's', 24, 64, 'd'}};
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 'q');
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 'w');
|
||||
BOOST_TEST_EQ(flat_get<2>(s), 12);
|
||||
BOOST_TEST_EQ(flat_get<3>(s), 32);
|
||||
BOOST_TEST_EQ(flat_get<4>(s), 'e');
|
||||
|
||||
BOOST_TEST_EQ(flat_get<5>(s), 'a');
|
||||
BOOST_TEST_EQ(flat_get<6>(s), 's');
|
||||
BOOST_TEST_EQ(flat_get<7>(s), 24);
|
||||
BOOST_TEST_EQ(flat_get<8>(s), 64);
|
||||
BOOST_TEST_EQ(flat_get<9>(s), 'd');
|
||||
}
|
||||
|
||||
#ifdef BOOST_PFR_RELAX_POD_REQUIREMENT
|
||||
// Test inspired by Anton Bikineev
|
||||
void test_structure_with_default_values() {
|
||||
struct test_me {
|
||||
int i = 2;
|
||||
short s = 14;
|
||||
};
|
||||
|
||||
test_me s;
|
||||
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 2);
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 14);
|
||||
}
|
||||
|
||||
// Test inspired by Anton Bikineev
|
||||
void test_st_layout_structure_with_non_constexpr_type() {
|
||||
struct non_literal_structure {
|
||||
int i1 = 3;
|
||||
short s1 = 15;
|
||||
|
||||
non_literal_structure() = delete;
|
||||
non_literal_structure(const non_literal_structure&) = delete;
|
||||
non_literal_structure(non_literal_structure&&) = default;
|
||||
non_literal_structure& operator=(const non_literal_structure&) = delete;
|
||||
non_literal_structure& operator=(non_literal_structure&&) = delete;
|
||||
};
|
||||
struct test_me {
|
||||
int i = 2;
|
||||
short s = 14;
|
||||
non_literal_structure nonlit{};
|
||||
};
|
||||
|
||||
BOOST_TEST_EQ(tuple_size_v<test_me>, 3);
|
||||
|
||||
test_me s{};
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 2);
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 14);
|
||||
BOOST_TEST_EQ(flat_get<2>(s), 3);
|
||||
BOOST_TEST_EQ(flat_get<3>(s), 15);
|
||||
}
|
||||
|
||||
// Test inspired by Anton Bikineev
|
||||
void test_structure_with_user_provided_default_constructor() {
|
||||
struct test_me {
|
||||
short s = 2;
|
||||
constexpr test_me(short){}
|
||||
};
|
||||
|
||||
test_me s{0};
|
||||
(void)s;
|
||||
//BOOST_TEST_EQ(flat_get<0>(s), 2); // TODO: fix compile time error message2
|
||||
}
|
||||
#endif
|
||||
|
||||
void test_move_only_pod() {
|
||||
struct move_only_pod {
|
||||
int i1;
|
||||
short s1;
|
||||
|
||||
move_only_pod() = delete;
|
||||
//move_only_pod(move_only_pod&&) = delete;
|
||||
|
||||
move_only_pod(const move_only_pod&) = delete;
|
||||
move_only_pod(move_only_pod&&) = default;
|
||||
move_only_pod& operator=(const move_only_pod&) = delete;
|
||||
move_only_pod& operator=(move_only_pod&&) = delete;
|
||||
};
|
||||
|
||||
move_only_pod s{2, 14};
|
||||
BOOST_TEST_EQ(tuple_size_v<move_only_pod>, 2u);
|
||||
BOOST_TEST_EQ(flat_get<0>(s), 2);
|
||||
BOOST_TEST_EQ(flat_get<1>(s), 14);
|
||||
/* // TODO: fix me!
|
||||
struct with_nested_move_only_pod {
|
||||
int i;
|
||||
move_only_pod p;
|
||||
};
|
||||
BOOST_TEST_EQ(tuple_size_v<with_nested_move_only_pod>, 2u); */
|
||||
/* // TODO: fix me!
|
||||
with_nested_move_only_pod np{2, {3, 4}};
|
||||
BOOST_TEST_EQ(flat_get<0>(np), 2);
|
||||
BOOST_TEST_EQ(flat_get<1>(np), 3);
|
||||
BOOST_TEST_EQ(flat_get<2>(np), 4);*/
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_compiletime<foo>();
|
||||
test_compiletime_array<int>();
|
||||
test_compiletime_array<void*>();
|
||||
test_compiletime_array<const void*>();
|
||||
test_compiletime_array<char>();
|
||||
test_compiletime_array<char const volatile*>();
|
||||
{
|
||||
foo f {
|
||||
'A', 11, 12, 13, {'B', 'C'}, 16, 17, 0, 0, 0, 30.1
|
||||
, {18, 19}
|
||||
, {20, 21, {22, 23}}
|
||||
};
|
||||
test_runtime(f);
|
||||
}
|
||||
{
|
||||
foo f {
|
||||
'\0', 12437, 1212, 13, {'1', '7'}, 163, 1723, 0, 0, 0, 3000.1
|
||||
, {-18, -19}
|
||||
, {656565, 65535, {-22, -23}}
|
||||
};
|
||||
test_runtime(f);
|
||||
}
|
||||
|
||||
test_with_enums();
|
||||
test_comparable_struct();
|
||||
test_empty_struct();
|
||||
test_pods_with_int_operators();
|
||||
test_struct_with_single_field();
|
||||
|
||||
test_with_contatiners<flat_less<>>();
|
||||
test_with_contatiners<flat_greater<>>();
|
||||
|
||||
test_print();
|
||||
|
||||
test_with_user_defined_constructor();
|
||||
test_hash();
|
||||
|
||||
struct non_pod1 {
|
||||
std::string s;
|
||||
std::vector<int> v;
|
||||
int i;
|
||||
|
||||
struct foo {
|
||||
std::string s2;
|
||||
} f;
|
||||
};
|
||||
static_assert(tuple_size<non_pod1>::value == 4, "Must not be a compile error");
|
||||
|
||||
|
||||
struct non_pod2 {
|
||||
unsigned ui1: 1;
|
||||
unsigned ui2: 2;
|
||||
|
||||
std::string s;
|
||||
std::vector<int> v;
|
||||
int i;
|
||||
|
||||
struct foo {
|
||||
std::string s2;
|
||||
} f;
|
||||
};
|
||||
static_assert(tuple_size<non_pod2>::value == 6, "Must not be a compile error even with bitfields");
|
||||
|
||||
int i_2dimens[2][2] = {{10, 11}, {12, 13} };
|
||||
static_assert(tuple_size<decltype(i_2dimens)>::value == 4, "");
|
||||
static_assert(flat_tuple_size<decltype(i_2dimens)>::value == 4, "");
|
||||
|
||||
test_and_debug_internals(std::make_index_sequence<6>{});
|
||||
test_alignment_with_neted_structure();
|
||||
another_test_with_unusual_alignment();
|
||||
|
||||
#ifdef BOOST_PFR_RELAX_POD_REQUIREMENT
|
||||
test_structure_with_default_values();
|
||||
test_st_layout_structure_with_non_constexpr_type();
|
||||
test_structure_with_user_provided_default_constructor();
|
||||
#endif
|
||||
|
||||
test_move_only_pod();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
15
test/count_fields_on_chars.cpp
Normal file
15
test/count_fields_on_chars.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
15
test/count_fields_on_ints.cpp
Normal file
15
test/count_fields_on_ints.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
15
test/count_fields_on_long_longs.cpp
Normal file
15
test/count_fields_on_long_longs.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
15
test/count_fields_on_shorts.cpp
Normal file
15
test/count_fields_on_shorts.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
15
test/count_fields_on_void_ptrs.cpp
Normal file
15
test/count_fields_on_void_ptrs.cpp
Normal file
@@ -0,0 +1,15 @@
|
||||
// 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;
|
||||
}
|
||||
|
||||
|
||||
108
test/flat_functions_for.cpp
Normal file
108
test/flat_functions_for.cpp
Normal file
@@ -0,0 +1,108 @@
|
||||
// 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/flat_functions_for.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#include <tuple>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <unordered_set>
|
||||
|
||||
struct adl_hash {
|
||||
template <class T>
|
||||
std::size_t operator()(const T& val) const {
|
||||
using namespace boost;
|
||||
return hash_value(val);
|
||||
}
|
||||
};
|
||||
|
||||
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)
|
||||
|
||||
void test_comparable_struct() {
|
||||
comparable_struct s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
|
||||
comparable_struct s2 = s1;
|
||||
comparable_struct s3 {0, 1, "Hello", false, 6,7,8,9,10,11111};
|
||||
BOOST_TEST_EQ(s1, s2);
|
||||
BOOST_TEST(s1 <= s2);
|
||||
BOOST_TEST(s1 >= s2);
|
||||
BOOST_TEST(!(s1 != s2));
|
||||
BOOST_TEST(!(s1 == s3));
|
||||
BOOST_TEST(s1 != s3);
|
||||
BOOST_TEST(s1 < s3);
|
||||
BOOST_TEST(s3 > s2);
|
||||
BOOST_TEST(s1 <= s3);
|
||||
BOOST_TEST(s3 >= s2);
|
||||
|
||||
std::cout << s1 << std::endl;
|
||||
|
||||
comparable_struct s4;
|
||||
std::stringstream ss;
|
||||
ss.exceptions ( std::ios::failbit);
|
||||
ss << s1;
|
||||
ss >> s4;
|
||||
std::cout << s4 << std::endl;
|
||||
BOOST_TEST_EQ(s1, s4);
|
||||
int i = 1, j = 2;
|
||||
BOOST_TEST_NE(i, j);
|
||||
}
|
||||
|
||||
struct empty { operator std::string() { return "empty{}"; } };
|
||||
BOOST_PFR_FLAT_FUNCTIONS_FOR(empty)
|
||||
|
||||
void test_empty_struct() {
|
||||
BOOST_TEST_EQ(empty{}, empty{});
|
||||
}
|
||||
|
||||
namespace foo {
|
||||
struct testing { bool b1, b2; int i; };
|
||||
BOOST_PFR_FLAT_FUNCTIONS_FOR(testing);
|
||||
}
|
||||
|
||||
template <class Comparator>
|
||||
void test_with_contatiners() {
|
||||
std::set<foo::testing, Comparator > t{
|
||||
{true, true, 100},
|
||||
{false, true, 100},
|
||||
{true, false, 100},
|
||||
{true, true, 101}
|
||||
};
|
||||
|
||||
BOOST_TEST(t.find({true, true, 100}) != t.end());
|
||||
BOOST_TEST_EQ(t.count({true, true, 100}), 1u);
|
||||
|
||||
std::unordered_set<foo::testing, adl_hash> us(t.begin(), t.end());
|
||||
BOOST_TEST_EQ(us.size(), t.size());
|
||||
}
|
||||
|
||||
void test_implicit_conversions() {
|
||||
std::stringstream ss;
|
||||
ss << std::true_type{};
|
||||
BOOST_TEST_EQ(ss.str(), "1"); // Does not breaks implicit conversion
|
||||
|
||||
ss.str("");
|
||||
ss << empty{};
|
||||
BOOST_TEST_EQ(ss.str(), "{}"); // Breaks implicit conversion for types marked with BOOST_PFR_FLAT_FUNCTIONS_FOR
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_comparable_struct();
|
||||
test_empty_struct();
|
||||
test_with_contatiners<std::less<>>();
|
||||
test_with_contatiners<std::greater<>>();
|
||||
test_implicit_conversions();
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
82
test/flat_ops.cpp
Normal file
82
test/flat_ops.cpp
Normal file
@@ -0,0 +1,82 @@
|
||||
// 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/flat_ops.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#include <tuple>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
template <class T>
|
||||
void test_comparable_struct() {
|
||||
using namespace boost::pfr::flat_ops;
|
||||
|
||||
T s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
|
||||
T s2 = s1;
|
||||
T s3 {0, 1, "Hello", false, 6,7,8,9,10,11111};
|
||||
BOOST_TEST(s1 == s2);
|
||||
BOOST_TEST(s1 <= s2);
|
||||
BOOST_TEST(s1 >= s2);
|
||||
BOOST_TEST(!(s1 != s2));
|
||||
BOOST_TEST(!(s1 == s3));
|
||||
BOOST_TEST(s1 != s3);
|
||||
BOOST_TEST(s1 < s3);
|
||||
BOOST_TEST(s3 > s2);
|
||||
BOOST_TEST(s1 <= s3);
|
||||
BOOST_TEST(s3 >= s2);
|
||||
|
||||
std::cout << s1 << std::endl;
|
||||
|
||||
T s4;
|
||||
std::stringstream ss;
|
||||
ss.exceptions ( std::ios::failbit);
|
||||
ss << s1;
|
||||
ss >> s4;
|
||||
std::cout << s4 << std::endl;
|
||||
BOOST_TEST(s1 == s4);
|
||||
int i = 1, j = 2;
|
||||
BOOST_TEST_NE(i, j);
|
||||
}
|
||||
|
||||
void test_empty_struct() {
|
||||
struct empty {};
|
||||
using namespace boost::pfr::flat_ops;
|
||||
|
||||
std::cout << empty{};
|
||||
BOOST_TEST(empty{} == empty{});
|
||||
}
|
||||
|
||||
void test_implicit_conversions() {
|
||||
std::stringstream ss;
|
||||
ss << std::true_type{};
|
||||
BOOST_TEST_EQ(ss.str(), "1"); // Does not breaks implicit conversion
|
||||
}
|
||||
|
||||
|
||||
namespace foo {
|
||||
struct comparable_struct {
|
||||
int i; short s; char data[50]; bool bl; int a,b,c,d,e,f;
|
||||
};
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_comparable_struct<foo::comparable_struct>();
|
||||
|
||||
struct local_comparable_struct {
|
||||
int i; short s; char data[50]; bool bl; int a,b,c,d,e,f;
|
||||
};
|
||||
|
||||
test_comparable_struct<local_comparable_struct>();
|
||||
test_empty_struct();
|
||||
test_implicit_conversions();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
112
test/global_flat_ops.cpp
Normal file
112
test/global_flat_ops.cpp
Normal file
@@ -0,0 +1,112 @@
|
||||
// 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/global_flat_ops.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#include <iostream>
|
||||
#include <typeinfo>
|
||||
#include <tuple>
|
||||
#include <sstream>
|
||||
#include <set>
|
||||
#include <string>
|
||||
|
||||
#include <boost/functional/hash.hpp>
|
||||
#include <unordered_set>
|
||||
|
||||
template <class T>
|
||||
void test_comparable_struct() {
|
||||
T s1 {0, 1, "Hello", false, 6,7,8,9,10,11};
|
||||
T s2 = s1;
|
||||
T s3 {0, 1, "Hello", false, 6,7,8,9,10,11111};
|
||||
BOOST_TEST(s1 == s2);
|
||||
BOOST_TEST(s1 <= s2);
|
||||
BOOST_TEST(s1 >= s2);
|
||||
BOOST_TEST(!(s1 != s2));
|
||||
BOOST_TEST(!(s1 == s3));
|
||||
BOOST_TEST(s1 != s3);
|
||||
BOOST_TEST(s1 < s3);
|
||||
BOOST_TEST(s3 > s2);
|
||||
BOOST_TEST(s1 <= s3);
|
||||
BOOST_TEST(s3 >= s2);
|
||||
|
||||
std::cout << s1 << std::endl;
|
||||
|
||||
T s4;
|
||||
std::stringstream ss;
|
||||
ss.exceptions ( std::ios::failbit);
|
||||
ss << s1;
|
||||
ss >> s4;
|
||||
std::cout << s4 << std::endl;
|
||||
BOOST_TEST(s1 == s4);
|
||||
int i = 1, j = 2;
|
||||
BOOST_TEST_NE(i, j);
|
||||
}
|
||||
|
||||
void test_empty_struct() {
|
||||
struct empty {};
|
||||
|
||||
std::cout << empty{};
|
||||
BOOST_TEST(empty{} == empty{});
|
||||
}
|
||||
|
||||
struct adl_hash {
|
||||
template <class T>
|
||||
std::size_t operator()(const T& val) const {
|
||||
using namespace boost;
|
||||
return hash_value(val);
|
||||
}
|
||||
};
|
||||
|
||||
template <class Comparator>
|
||||
void test_with_contatiners() {
|
||||
struct testing { bool b1, b2; int i; };
|
||||
|
||||
std::set<testing, Comparator > t{
|
||||
{true, true, 100},
|
||||
{false, true, 100},
|
||||
{true, false, 100},
|
||||
{true, true, 101}
|
||||
};
|
||||
|
||||
BOOST_TEST(t.find({true, true, 100}) != t.end());
|
||||
BOOST_TEST_EQ(t.count({true, true, 100}), 1u);
|
||||
|
||||
std::unordered_set<testing, adl_hash> us(t.begin(), t.end());
|
||||
BOOST_TEST_EQ(us.size(), t.size());
|
||||
}
|
||||
|
||||
|
||||
namespace foo {
|
||||
struct comparable_struct {
|
||||
int i; short s; char data[50]; bool bl; int a,b,c,d,e,f;
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
void test_implicit_conversions() {
|
||||
std::stringstream ss;
|
||||
ss << std::true_type{};
|
||||
BOOST_TEST_EQ(ss.str(), "{}"); // Breaks implicit conversion :(
|
||||
}
|
||||
|
||||
int main() {
|
||||
test_comparable_struct<foo::comparable_struct>();
|
||||
|
||||
struct local_comparable_struct {
|
||||
int i; short s; char data[50]; bool bl; int a,b,c,d,e,f;
|
||||
};
|
||||
|
||||
test_comparable_struct<local_comparable_struct>();
|
||||
|
||||
test_empty_struct();
|
||||
test_with_contatiners<std::less<>>();
|
||||
test_with_contatiners<std::greater<>>();
|
||||
test_implicit_conversions();
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
12
test/minimal.cpp
Normal file
12
test/minimal.cpp
Normal file
@@ -0,0 +1,12 @@
|
||||
// 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/core.hpp>
|
||||
|
||||
int main() {
|
||||
struct foo { int i; char c;};
|
||||
static_assert(boost::pfr::flat_tuple_size_v<foo> == 2, "");
|
||||
}
|
||||
|
||||
16
test/motivating_example.cpp
Normal file
16
test/motivating_example.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
#include <iostream>
|
||||
#include "boost/pfr.hpp"
|
||||
|
||||
struct my_struct { // no ostream operator defined!
|
||||
int i;
|
||||
char c;
|
||||
double d;
|
||||
};
|
||||
|
||||
int main() {
|
||||
using namespace boost::pfr::flat_ops; // ostream operator out-of-the-box for all PODs!
|
||||
|
||||
my_struct s{100, 'H', 3.141593};
|
||||
std::cout << "my_struct has " << boost::pfr::flat_tuple_size<my_struct>::value
|
||||
<< " fields: " << s << "\n";
|
||||
}
|
||||
16
test/non_aggregate1.cpp
Normal file
16
test/non_aggregate1.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
// 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/core.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::tuple_size<std::pair<int, short>>::value; // Must be a compile time error
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
16
test/non_aggregate2.cpp
Normal file
16
test/non_aggregate2.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
// 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/core.hpp>
|
||||
#include <boost/core/lightweight_test.hpp>
|
||||
|
||||
#include <tuple>
|
||||
|
||||
int main() {
|
||||
(void)boost::pfr::flat_tuple_size<std::pair<int, short>>::value; // Must be a compile time error
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
|
||||
16
test/only_fields_count.cpp
Normal file
16
test/only_fields_count.cpp
Normal file
@@ -0,0 +1,16 @@
|
||||
// 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/fields_count.hpp>
|
||||
|
||||
int main() {
|
||||
struct nested { int i; char data[20]; };
|
||||
struct foo { int i; char c; nested n; };
|
||||
static_assert(boost::pfr::tuple_size_v<foo> == 3, "");
|
||||
|
||||
struct with_reference { int& i; char data; };
|
||||
static_assert(boost::pfr::tuple_size_v<with_reference> == 2, "");
|
||||
}
|
||||
|
||||
35
test/std_interactions.cpp
Normal file
35
test/std_interactions.cpp
Normal file
@@ -0,0 +1,35 @@
|
||||
// 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/core.hpp>
|
||||
#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));
|
||||
}
|
||||
}
|
||||
|
||||
int main() {
|
||||
using namespace std;
|
||||
using namespace helper;
|
||||
struct foo { int i; short s;};
|
||||
|
||||
foo f{1, 2};
|
||||
BOOST_TEST_EQ(get<0>(f), 1);
|
||||
|
||||
const foo cf{1, 2};
|
||||
BOOST_TEST_EQ(get<1>(cf), 2);
|
||||
|
||||
std::tuple<int, short> t{10, 20};
|
||||
BOOST_TEST_EQ(get<0>(t), 10);
|
||||
|
||||
const std::tuple<int, short> ct{10, 20};
|
||||
BOOST_TEST_EQ(get<1>(ct), 20);
|
||||
|
||||
return boost::report_errors();
|
||||
}
|
||||
|
||||
99
test/test_counts_on.hpp
Normal file
99
test/test_counts_on.hpp
Normal file
@@ -0,0 +1,99 @@
|
||||
// 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_TEST_TEST_COUNTS_ON_HPP
|
||||
#define BOOST_PFR_TEST_TEST_COUNTS_ON_HPP
|
||||
|
||||
#include <boost/pfr/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;
|
||||
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]; };
|
||||
static_assert(flat_tuple_size_v<t1_i> == CountInT + CountHelpers, "");
|
||||
|
||||
struct t1_p { T1 v1; void* p[CountHelpers]; };
|
||||
static_assert(flat_tuple_size_v<t1_p> == CountInT + CountHelpers, "");
|
||||
|
||||
struct t1_ll { T1 v1; long long ll[CountHelpers]; };
|
||||
static_assert(flat_tuple_size_v<t1_ll> == CountInT + CountHelpers, "");
|
||||
|
||||
|
||||
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; };
|
||||
static_assert(flat_tuple_size_v<rt1_s> == CountInT + CountHelpers, "");
|
||||
|
||||
struct rt1_i { int i[CountHelpers]; T1 v1; };
|
||||
static_assert(flat_tuple_size_v<rt1_i> == CountInT + CountHelpers, "");
|
||||
|
||||
struct rt1_p { void* p[CountHelpers]; T1 v1; };
|
||||
static_assert(flat_tuple_size_v<rt1_p> == CountInT + CountHelpers, "");
|
||||
|
||||
struct rt1_ll { long long ll[CountHelpers]; T1 v1; };
|
||||
static_assert(flat_tuple_size_v<rt1_ll> == CountInT + CountHelpers, "");
|
||||
}
|
||||
|
||||
template <class T1, std::size_t CountInT>
|
||||
void test_counts_on_multiple_chars_impl() {
|
||||
using namespace boost::pfr;
|
||||
|
||||
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(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>();
|
||||
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>();
|
||||
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>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 11>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 12>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 13>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 14>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 15>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 16>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 17>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 18>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 19>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 20>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 23>();
|
||||
test_counts_on_multiple_chars_impl_1<T1, CountInT, 24>();
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void test_counts_on_multiple_chars() {
|
||||
test_counts_on_multiple_chars_impl<T, 1>();
|
||||
|
||||
struct t2 { T v1; T v2; };
|
||||
test_counts_on_multiple_chars_impl<t2, 2>();
|
||||
test_counts_on_multiple_chars_impl<T[2], 2>();
|
||||
|
||||
test_counts_on_multiple_chars_impl<T[3], 3>();
|
||||
test_counts_on_multiple_chars_impl<T[4], 4>();
|
||||
|
||||
struct t8 { T v1; T v2; T v3; T v4; T v5; T v6; T v7; T v8; };
|
||||
test_counts_on_multiple_chars_impl<t8, 8>();
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
Reference in New Issue
Block a user