TPIE

2362a60
reflect.h
1 // -*- mode: c++; tab-width: 4; indent-tabs-mode: t; eval: (progn (c-set-style "stroustrup") (c-set-offset 'innamespace 0)); -*-
2 // vi:set ts=4 sts=4 sw=4 noet :
3 // Copyright 2013, 2016, The TPIE development team
4 //
5 // This file is part of TPIE.
6 //
7 // TPIE is free software: you can redistribute it and/or modify it under
8 // the terms of the GNU Lesser General Public License as published by the
9 // Free Software Foundation, either version 3 of the License, or (at your
10 // option) any later version.
11 //
12 // TPIE is distributed in the hope that it will be useful, but WITHOUT ANY
13 // WARRANTY; without even the implied warranty of MERCHANTABILITY or
14 // FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
15 // License for more details.
16 //
17 // You should have received a copy of the GNU Lesser General Public License
18 // along with TPIE. If not, see <http://www.gnu.org/licenses/>
19 
20 #ifndef __TPIE_REFLECT_H__
21 #define __TPIE_REFLECT_H__
22 
23 #include <type_traits>
24 #include <iterator>
25 #include <array>
26 
27 namespace tpie {
28 
29 #define REFLECT_XSTR(s) REFLECT_STR(s)
30 #define REFLECT_STR(s) #s
31 
32 #define REFLECT_BEGIN(name) \
33  template <typename R, typename ... T> \
34  bool reflect_impl(name *, R & r, T && ... v) { \
35  r.begin(REFLECT_XSTR(name));
36 
37 #define REFLECT_VISIT(naXme) \
38  r.name(REFLECT_XSTR(naXme)); \
39  if (!r.apply(v . naXme ...)) return false;
40 
41 #define REFLECT_VISIT_SUPER(naXme) \
42  r.name(REFLECT_XSTR(naXme)); \
43  if (!r.apply(static_cast<std::conditional_t<R::write, naXme &, const naXme &>>(v) ...)) return false;
44 
45 #define REFLECT_END() \
46  r.end(); \
47  return true; \
48 }
49 
50 template <typename R, typename T, typename ... TT>
51 bool reflect(R & r, T && v, TT && ... vs);
52 
53 // SFINAE magic to detect if a type is trivialy serializable
54 template <typename T>
56 private:
57  template <typename TT>
58  static char magic(TT *, typename std::enable_if<TT::is_trivially_serializable>::type *_=0);
59 
60  template <typename TT>
61  static long magic(...);
62 public:
63  static bool constexpr value=
64  (std::is_pod<T>::value || sizeof(magic<T>((T*)nullptr))==sizeof(char)) && !std::is_pointer<T>::value;
65 };
66 
67 // SFINAE magic to detect member functions and such
68 template <typename T>
70 private:
71  template <typename TT>
72  static char size_and_lookup_magic(TT *,
73  decltype(std::declval<TT>().size()) * a = 0,
74  std::decay_t<decltype(std::declval<TT>()[0])> * b = 0);
75  template <typename TT>
76  static long size_and_lookup_magic(...);
77 
78  template <typename TT>
79  static char resize_magic(TT *,
80  decltype(std::declval<TT>().resize(0)) * a = 0);
81  template <typename TT>
82  static long resize_magic(...);
83 
84  template <typename TT>
85  static char push_back_magic(TT *,
86  decltype(std::declval<TT &>().push_back(std::declval<std::decay_t<decltype(std::declval<TT>()[0])>>())) * a = 0);
87  template <typename TT>
88  static long push_back_magic(...);
89 
90  template <typename TT>
91  static char data_magic(TT *,
92  decltype(std::declval<TT>().data()) * a = 0);
93  template <typename TT>
94  static long data_magic(...);
95 
96  template <typename TT>
97  static char c_str_magic(TT *,
98  decltype(std::declval<TT>().c_str()) * a = 0);
99  template <typename TT>
100  static long c_str_magic(...);
101 
102  template <typename TT>
103  static std::enable_if_t<is_trivially_serializable2<std::decay_t<decltype(std::declval<TT>()[0])>>::value, char> tsv_magic(TT *) {};
104 
105  template <typename TT>
106  static long tsv_magic(...);
107 public:
108  static constexpr bool size_and_lookup = sizeof(size_and_lookup_magic<T>((T*)nullptr)) == sizeof(char);
109  static constexpr bool resize = sizeof(resize_magic<T>((T*)nullptr)) == sizeof(char);
110  static constexpr bool push_back = sizeof(push_back_magic<T>((T*)nullptr)) == sizeof(char);
111  static constexpr bool data = sizeof(data_magic<T>((T*)nullptr)) == sizeof(char);
112  static constexpr bool c_str = sizeof(c_str_magic<T>((T*)nullptr)) == sizeof(char);
113  static constexpr bool trivially_serializable_value = sizeof(tsv_magic<T>((T*)nullptr)) == sizeof(char);
114 };
115 
116 // Use tag dispatch to reflection of known types
124 
125 template <typename D, typename R, typename ... T>
126 bool reflect_dispatch(reflect_tag_impl, R & r, T && ... v) {
127  return reflect_impl((D*)nullptr, r, v...);
128 }
129 
130 template <typename D, typename R, typename ... T>
131 bool reflect_dispatch(reflect_tag_direct, R & r, T && ... v) {
132  return r(v...);
133 }
134 
135 template <typename D, typename R, typename T, typename ... TT>
136 bool reflect_dispatch(reflect_tag_array_read, R & r, T && v, TT && ... vs) {
137  const auto d = v.size();
138  r.beginArray(d, vs.size()...);
139  for (size_t i=0; i < d; ++i) {
140  if (!reflect(r, v[i], vs[i]...)) return false;
141  }
142  r.endArray();
143  return true;
144 }
145 
146 template <typename D, typename R, typename T>
147 bool reflect_dispatch(reflect_tag_trivial_array_read, R & r, T && v) {
148  const auto d = v.size();
149  r.beginArray(d);
150  if (!r(v.data(), v.size())) return false;
151  r.endArray();
152  return true;
153 }
154 
155 template <typename D, typename R, typename T>
156 bool reflect_dispatch(reflect_tag_array_write, R & r, T && v) {
157  size_t d = r.beginArray();
158  v.resize(d);
159  for (size_t i=0; i < d; ++i) {
160  if (!r.apply(v[i])) return false;
161  }
162  r.endArray();
163  return true;
164 }
165 
166 template <typename D, typename R, typename T>
167 bool reflect_dispatch(reflect_tag_trivial_array_write, R & r, T && v) {
168  size_t d = r.beginArray();
169  v.resize(d);
170  if (!r(&v[0], d)) return false;
171  r.endArray();
172  return true;
173 }
174 
175 template <typename D, typename R, typename T>
176 bool reflect_dispatch(reflect_tag_push_back_array_write, R & r, T && v) {
177  //static_assert(false, "Not implemented");
178  return true;
179 }
180 
181 template <size_t C, typename R, typename T>
182 bool reflect_static_array_dispatch(std::true_type, R & r, T && v) {
183  r.beginStaticArray(C);
184  if (!r(&v[0], C)) return false;
185  r.endStaticArray();
186  return true;
187 }
188 
189 template <size_t C, typename R, typename T, typename ... TT>
190 bool reflect_static_array_dispatch(std::false_type, R & r, T && v, TT && ... vv) {
191  r.beginStaticArray(C);
192  for (size_t i=0; i < C; ++i)
193  if (!r.applyt(v[i], vv[i]...)) return false;
194  r.endStaticArray();
195  return true;
196 }
197 
198 template <bool direct, bool trivial_array_read, bool array_read, bool trivial_array_write, bool push_back_array_write, bool array_write>
200  typedef reflect_tag_impl type;
201 };
202 
203 template <bool trivial_array_read, bool array_read, bool trivial_array_write, bool push_back_array_write, bool array_write>
204 struct reflect_tag_compute<true, trivial_array_read, array_read, trivial_array_write, push_back_array_write, array_write> {
205  typedef reflect_tag_direct type;
206 };
207 
208 template <bool array_read>
209 struct reflect_tag_compute<false, true, array_read, false, false, false> {
211 };
212 
213 template <>
214 struct reflect_tag_compute<false, false, true, false, false, false> {
216 };
217 
218 template <bool push_back_array_write, bool array_write>
219 struct reflect_tag_compute<false, false, false, true, push_back_array_write, array_write> {
221 };
222 
223 template <bool array_write>
224 struct reflect_tag_compute<false, false, false, false, true, array_write> {
226 };
227 
228 template <>
229 struct reflect_tag_compute<false, false, false, false, false, true> {
231 };
232 
233 // Reflect entry point
234 // Reflect a bunch of T s using R
235 template <typename R, typename T, typename ... TT>
236 bool reflect(R & r, T && v, TT && ... vs) {
237  typedef std::decay_t<T> D;
238  typedef reflect_sfinae<D> S;
239  constexpr bool dc = std::is_default_constructible<D>::value;
240  constexpr bool write = R::write;
241  typedef std::decay_t<T> D;
242  typedef typename reflect_tag_compute<
243  // direct
244  (R::string && S::size_and_lookup && S::c_str && S::data) ||
245  (R::trivialSerializable && is_trivially_serializable2<D>::value) ||
246  (R::arithmetic && std::is_arithmetic<D>::value),
247  // trivial array read
248  R::trivialSerializable && S::size_and_lookup && S::data && !write && S::trivially_serializable_value,
249  // array read
250  S::size_and_lookup && !write,
251  // trivial array write
252  R::trivialSerializable && S::size_and_lookup && S::resize && S::data && write && S::trivially_serializable_value && dc,
253  // push_back array write
254  false, //S::size_and_lookup && S::push_back && S::resize && write,
255  // array_write
256  S::size_and_lookup && dc && S::resize && write
257  >::type tag;
258  return reflect_dispatch<D>(tag(), r, v, vs...);
259 }
260 
261 // reflect special case for static arrays
262 template <typename R, typename T, std::size_t C, typename ... TT>
263 bool reflect(R & r, T(& v)[C], TT && ... vs) {
264  typedef std::conditional_t<is_trivially_serializable2<T>::value, std::true_type, std::false_type> tag;
265  return reflect_static_array_dispatch<C>(tag(), r, v, vs...);
266 }
267 
268 // reflect special case for std::array
269 template <typename R, typename T, std::size_t C, typename ... TT>
270 bool reflect(R & r, const std::array<T, C> & v, TT && ... vs) {
271  typedef std::conditional_t<is_trivially_serializable2<T>::value, std::true_type, std::false_type> tag;
272  return reflect_static_array_dispatch<C>(tag(), r, v, vs...);
273 }
274 
275 // reflect special case for std::array
276 template <typename R, typename T, std::size_t C, typename ... TT>
277 bool reflect(R & r, std::array<T, C> & v, TT && ... vs) {
278  typedef std::conditional_t<is_trivially_serializable<T>::value, std::true_type, std::false_type> tag;
279  return reflect_static_array_dispatch<C>(tag(), r, v, vs...);
280 }
281 } //namespace tpie
282 
283 #endif //_TPIE_REFLECT_H__