Multiscale Universal Interface  2.0
A Concurrent Framework for Coupling Heterogeneous Solvers
dynstorage.h
Go to the documentation of this file.
1 /*****************************************************************************
2 * Multiscale Universal Interface Code Coupling Library *
3 * *
4 * Copyright (C) 2019 Y. H. Tang, S. Kudo, X. Bian, Z. Li, G. E. Karniadakis *
5 * *
6 * This software is jointly licensed under the Apache License, Version 2.0 *
7 * and the GNU General Public License version 3, you may use it according *
8 * to either. *
9 * *
10 * ** Apache License, version 2.0 ** *
11 * *
12 * Licensed under the Apache License, Version 2.0 (the "License"); *
13 * you may not use this file except in compliance with the License. *
14 * You may obtain a copy of the License at *
15 * *
16 * http://www.apache.org/licenses/LICENSE-2.0 *
17 * *
18 * Unless required by applicable law or agreed to in writing, software *
19 * distributed under the License is distributed on an "AS IS" BASIS, *
20 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
21 * See the License for the specific language governing permissions and *
22 * limitations under the License. *
23 * *
24 * ** GNU General Public License, version 3 ** *
25 * *
26 * This program is free software: you can redistribute it and/or modify *
27 * it under the terms of the GNU General Public License as published by *
28 * the Free Software Foundation, either version 3 of the License, or *
29 * (at your option) any later version. *
30 * *
31 * This program is distributed in the hope that it will be useful, *
32 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
33 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
34 * GNU General Public License for more details. *
35 * *
36 * You should have received a copy of the GNU General Public License *
37 * along with this program. If not, see <http://www.gnu.org/licenses/>. *
38 *****************************************************************************/
39 
48 #ifndef DYNSTORAGE_H_
49 #define DYNSTORAGE_H_
50 
51 #include <vector>
52 #include <utility>
53 #include <cstdint>
54 #include <typeinfo>
55 #include <type_traits>
56 
57 #include "stream.h"
58 #include "../general/util.h"
59 
60 namespace mui {
61 
62 struct bad_storage_id: std::runtime_error {
63  bad_storage_id( const char* err ): std::runtime_error(err) {}
64 };
65 struct bad_storage_cast: std::bad_cast {
66  virtual const char* what() const noexcept { return "MUI Error [dynstorage.h]: Storage error, bad cast."; }
67 };
68 
69 
70 namespace {
71 // meta helper functions
72 
73 // get_typeid_: this value is based on the order of Variadic template argument.
74 // get_typeid_<int, int, double, float, char, etc...>::value==0,
75 // get_typeid_<double, int, double, float, char, etc...>::value == 1, and so on
76 template<typename T, typename... Args> struct get_typeid_;
77 template<typename T, typename Head, typename... Tail> struct get_typeid_<T,Head,Tail...> {
78  typedef typename std::remove_reference<typename std::remove_cv<T>::type>::type type;
79  static constexpr std::int32_t value =
80  std::conditional<std::is_same<type,Head>::value,
81  std::integral_constant<std::int32_t,0>,
82  std::integral_constant<std::int32_t,1+get_typeid_<T,Tail...>::value> >::type::value;
83 };
84 template<typename T> struct get_typeid_<T> {
85  static constexpr std::int32_t value = 0;
86 };
87 
88 // build i-th element and apply functor
89 template<std::int32_t i, typename R, typename... Args> struct make_value_;
90 template<std::int32_t i, typename R, typename Head, typename... Tail > struct make_value_<i,R,Head,Tail...> {
91  template<typename F>
92  static R apply( std::int32_t which, F f ) {
93  if( i == which ) {
94  Head head;
95  return f(std::move(head));
96  }
97  else return make_value_<i+1,R,Tail...>::apply(which,f);
98  }
99 };
100 template<std::int32_t i,typename R> struct make_value_<i,R> {
101  template<typename F>
102  static R apply( int, F ) { throw bad_storage_id("MUI Error [dynstorage.h]: Storage error, bad type id."); }
103 };
104 
105 
106 template<typename Head, typename... Tail> struct get_head_ { typedef Head type; };
107 template<typename... Types>
108 using get_head_t_ = typename get_head_<Types...>::type;
109 
110 // type dispatcher.
111 template<id_t i, typename R, typename... Args> struct apply_visitor_impl_;
112 template<id_t i, typename R, typename Head, typename... Tail>
113 struct apply_visitor_impl_<i,R,Head,Tail...> {
114  template<typename F>
115  static R apply( id_t which, void* content, F& f ) { // this applies the content to f
116  if( i == which ) return f(*static_cast<Head*>(content));
117  else return apply_visitor_impl_<i+1,R,Tail...>::apply(which,content,f);
118  }
119  template<typename F>
120  static R apply( id_t which, const void* content, F& f ) {
121  if( i == which ) return f(*static_cast<const Head*>(content));
122  else return apply_visitor_impl_<i+1,R,Tail...>::apply(which,content,f);
123  }
124  template<typename F>
125  static R applym( id_t which, void* content, F& f ) { // move the content to f
126  if( i == which ) return f(std::move(*static_cast<Head*>(content)));
127  else return apply_visitor_impl_<i+1,R,Tail...>::applym(which,content,f);
128  }
129 };
130 template<id_t i, typename R> struct apply_visitor_impl_<i,R> {
131  template<typename F>
132  static R apply( id_t, const void*, F& ) { throw bad_storage_id("MUI Error [dynstorage.h]: Storage error, bad id."); }
133  template<typename F>
134  static R applym( id_t, void*, F& ) { throw bad_storage_id("MUI Error [dynstorage.h]: Storage error, bad id."); }
135 };
136 template<typename R,typename... Types> using applyer_ = apply_visitor_impl_<0,R,Types...>;
137 }
138 
139 // storage can hold any type of Types... and it has value semantics.
140 // feature of storage
141 // copy&construct as a value
142 // member functions: swap, clear, empty
143 // apply_visitor: user can get the actual type of storage by visiting it.
144 // ref: boost::any, boost::type_erasure, boost::variant
145 template<typename... Types>
146 struct storage {
147 private: // functors
148  struct deleter_ { template<typename T> void operator()( T& t ){ delete std::addressof(t); } };
149  struct cloner_ { template<typename T> void* operator()( const T& t ){ return static_cast<void*>(new T(t)); } };
150 
151 private: // internal typedefs
152  using Head_ = get_head_t_<Types...>;
153 
154 public:
155  using id_t = std::int32_t;
156  storage() noexcept : which_(bad_id), content_(0) {}
157  storage( const storage& rhs ) : which_(rhs.which_), content_(rhs.content_? rhs.clone_() : 0) {}
158  storage( storage&& rhs ) noexcept : which_(rhs.which_), content_(rhs.content_) {
159  rhs.which_ = bad_id;
160  rhs.content_ = 0;
161  }
163  if(!empty()) this->apply_visitor(deleter_());
164  which_ = bad_id;
165  content_ = 0;
166  }
168  rhs.swap(*this);
169  return *this;
170  }
171 
172  template<typename ValueType>
173  explicit storage( const ValueType& value)
174  : which_(get_typeid_<ValueType,Types...>::value),
175  content_(new ValueType(value)) {
176  static_assert(get_typeid_<ValueType,Types...>::value != bad_id,
177  "MUI Error [dynstorage.h]: Storage error, unsupported type. Please add type to type_list.");
178  }
179  template<typename ValueType>
180  explicit storage(ValueType&& value,
181  typename std::enable_if<!std::is_same<storage&,ValueType>::value>::type* = 0,
182  typename std::enable_if<!std::is_const<ValueType>::value>::type* = 0 )
183  : which_(get_typeid_<ValueType,Types...>::value),
184  content_(new typename std::decay<ValueType>::type(std::move(value))) {
185  static_assert(get_typeid_<ValueType,Types...>::value != bad_id,
186  "MUI Error [dynstorage.h]: Storage error, unsupported type. Please add type to type_list.");
187  }
188 
189  template<typename ValueType>
190  storage& operator=(ValueType&& rhs) {
191  storage(std::forward<ValueType>(rhs)).swap(*this);
192  return *this;
193  }
194 
195  void swap( storage& rhs ) noexcept {
196  std::swap(which_,rhs.which_);
197  std::swap(content_,rhs.content_);
198  }
199 
200 private:
201  void* clone_() const { return apply_visitor(cloner_()); }
202 public:
203  void clear() noexcept { storage().swap(*this); }
204  bool empty() const noexcept { return content_ == 0; }
205  explicit operator bool() const noexcept { return !empty(); }
206 
207  static const id_t bad_id = sizeof...(Types);
208  id_t which() const { return which_; }
209 
210  template<typename F, typename R_=typename std::result_of<F(const Head_&)>::type>
211  R_ apply_visitor( F f ) const& {
212  return applyer_<R_,Types...>::apply(which_, content_, f);
213  }
214  template<typename F, typename R_=typename std::result_of<F(Head_&)>::type>
215  R_ apply_visitor( F f ) & {
216  return applyer_<R_,Types...>::apply(which_, content_, f);
217  }
218  template<typename F, typename R_=typename std::result_of<F(Head_&&)>::type>
219  R_ apply_visitorm( F f ) && {
220  return applyer_<R_,Types...>::applym(which_, content_, f);
221  }
222 
223 
224 private:
225  id_t which_ = bad_id;
226  void* content_ = 0;
227 
228  template<typename ValueType, typename... Types2>
229  friend ValueType* storage_cast(storage<Types2...>*);
230 };
231 
232 
233 template<typename... Args>
234 inline void swap(storage<Args...>& lhs, storage<Args...>& rhs )
235 {
236  lhs.swap(rhs);
237 }
238 
239 template<typename ValueType, typename... Args>
241 {
242  return obj && obj->which() == get_typeid_<ValueType,Args...>::value ?
243  static_cast<ValueType*>(obj->content_) : 0;
244 }
245 
246 template<typename ValueType, typename... Args>
247 const ValueType* storage_cast(const storage<Args...>* obj )
248 {
249  return storage_cast<ValueType>(const_cast<storage<Args...>*>(obj));
250 }
251 
252 template<typename ValueType, typename... Args>
253 ValueType storage_cast( storage<Args...>& obj ){
254  typedef typename std::remove_reference<ValueType>::type nonref;
255  nonref* result = storage_cast<nonref>(&obj);
256  if(!result) throw bad_storage_cast();
257 
258  typedef typename std::add_lvalue_reference<ValueType>::type ref_type;
259  return static_cast<ref_type>(*result);
260 }
261 template<typename ValueType, typename... Args>
262 ValueType storage_cast( const storage<Args...>& obj ){
263  typedef typename std::remove_reference<ValueType>::type nonref;
264  return storage_cast<const nonref&>(const_cast<storage<Args...>&>(obj));
265 }
266 
267 template<typename ValueType, typename... Args>
268 inline ValueType&& storage_cast(storage<Args...>&& obj)
269 {
270  static_assert(std::is_rvalue_reference<ValueType&&>::value
271  || std::is_const<typename std::remove_reference<ValueType>::type>::type,
272  "MUI Error [dynstorage.h]: This type of cast is not supported.");
273  return storage_cast<ValueType&&>(obj);
274 }
275 
276 
277 // (de)serialization
278 namespace {
279 struct serializer {
280  template<typename T> void operator()( const T& t ){ ost << t; }
281  ostream& ost;
282 };
283 }
284 template<typename... Args>
286 {
287  stream << st.which();
288  if( !st.empty() ) st.apply_visitor(serializer{stream});
289  return stream;
290 }
291 
292 namespace {
293 template<typename Storage>
294 struct deserializer {
295  template<typename T> Storage operator()( T&& t ){
296  ist >> t;
297  return Storage(std::move(t));
298  }
299  istream& ist;
300 };
301 }
302 template<typename... Args>
304 {
305  using type=storage<Args...>;
306  typename type::id_t which;
307  stream >> which;
308  st = (which == type::bad_id) ? type() :
309  make_value_<0,type,Args...>::apply(which,deserializer<type>{stream});
310  return stream;
311 }
312 
313 }
314 #endif
Definition: stream.h:61
Definition: stream.h:67
istream & ist
Definition: dynstorage.h:299
ostream & ost
Definition: dynstorage.h:281
u u F
Definition: dim.h:351
T
Definition: dim.h:363
Definition: comm.h:54
istream & operator>>(istream &stream, smalluint &sml)
Definition: comm_tcp.h:103
ostream & operator<<(ostream &stream, const smalluint &sml)
Definition: comm_tcp.h:127
ValueType * storage_cast(storage< Args... > *obj)
Definition: dynstorage.h:240
void swap(storage< Args... > &lhs, storage< Args... > &rhs)
Definition: dynstorage.h:234
vexpr_apply1< E, OP, SCALAR, D > apply(vexpr< E, SCALAR, D > const &u, OP const &op)
Definition: point.h:392
Defines base stream class container_stream and associated functors.
Definition: dynstorage.h:65
virtual const char * what() const noexcept
Definition: dynstorage.h:66
Definition: dynstorage.h:62
bad_storage_id(const char *err)
Definition: dynstorage.h:63
Definition: dynstorage.h:146
friend ValueType * storage_cast(storage< Types2... > *)
storage(storage &&rhs) noexcept
Definition: dynstorage.h:158
storage & operator=(ValueType &&rhs)
Definition: dynstorage.h:190
std::int32_t id_t
Definition: dynstorage.h:155
~storage()
Definition: dynstorage.h:162
R_ apply_visitor(F f) &
Definition: dynstorage.h:215
storage(const ValueType &value)
Definition: dynstorage.h:173
static const id_t bad_id
Definition: dynstorage.h:207
storage & operator=(storage rhs)
Definition: dynstorage.h:167
storage(const storage &rhs)
Definition: dynstorage.h:157
void clear() noexcept
Definition: dynstorage.h:203
void swap(storage &rhs) noexcept
Definition: dynstorage.h:195
storage() noexcept
Definition: dynstorage.h:156
id_t which() const
Definition: dynstorage.h:208
storage(ValueType &&value, typename std::enable_if<!std::is_same< storage &, ValueType >::value >::type *=0, typename std::enable_if<!std::is_const< ValueType >::value >::type *=0)
Definition: dynstorage.h:180
R_ apply_visitorm(F f) &&
Definition: dynstorage.h:219
R_ apply_visitor(F f) const &
Definition: dynstorage.h:211
bool empty() const noexcept
Definition: dynstorage.h:204