TPIE

2362a60
container.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 2015, 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_PIPELINING_PIPE_CONTAINER_H__
21 #define __TPIE_PIPELINING_PIPE_CONTAINER_H__
22 
23 #include <type_traits>
24 #include <memory>
25 #include <typeinfo>
26 
27 namespace tpie {
28 namespace pipelining {
29 
30 template <typename T>
31 T & move_if_movable(typename std::remove_reference<T>::type & t,
32  typename std::enable_if<!std::is_move_constructible<T>::value>::type* = 0) {
33  return t;
34 }
35 
36 template <typename T>
37 T && move_if_movable(typename std::remove_reference<T>::type & t,
38  typename std::enable_if<std::is_move_constructible<T>::value>::type* = 0) {
39  return static_cast<T&&>(t);
40 }
41 
42 template <typename T>
43 T & move_if_movable_rvalue(typename std::remove_reference<T>::type & t,
44  typename std::enable_if<
45  !std::is_move_constructible<T>::value ||
46  !std::is_rvalue_reference<T>::value
47  >::type* = 0) {
48  return t;
49 }
50 
51 template <typename T>
52 T && move_if_movable_rvalue(typename std::remove_reference<T>::type & t,
53  typename std::enable_if<
54  std::is_move_constructible<T>::value &&
55  std::is_rvalue_reference<T>::value
56  >::type* = 0) {
57  return static_cast<T&&>(t);
58 }
59 
60 
61 template <typename ... TT>
62 class container {};
63 
64 template <typename T, typename ... TT>
65 struct container<T, TT...> : public container<TT...> {
66  container(const container &) = delete;
67  container() = delete;
68 
69  template <typename T2, typename ... TT2>
70  container(T2 && t, TT2 && ... tt)
71  : container<TT...>(std::forward<TT2>(tt)...)
72  , v(move_if_movable_rvalue<T2&&>(t)) {}
73 
74  container(container && o)
75  : container<TT...>(std::forward<container<TT...> >(o))
76  , v(move_if_movable<T>(o.v)) {}
77 
78  T v;
79 };
80 
81 namespace bits {
82 template <int i, typename T, typename ...TT>
83 struct get_impl {
84  typedef typename get_impl<i-1, TT...>::type type;
85  static type & get(container<T, TT...> & cc) {return get_impl<i-1, TT...>::get(cc);}
86  static const type & get(const container<T, TT...> & cc) {return get_impl<i-1, TT...>::get(cc);}
87 };
88 
89 template <typename T, typename ...TT>
90 struct get_impl<0, T, TT...> {
91  typedef T type;
92  static type & get(container<T, TT...> & cc) {return cc.v;}
93  static const type & get(const container<T, TT...> & cc) {return cc.v;}
94 };
95 } //namespace bits
96 
97 
98 template <int i, typename ...T>
99 typename bits::get_impl<i, T...>::type & get(container<T...> & c) {
101 }
102 
103 template <int i, typename ...T>
104 const typename bits::get_impl<i, T...>::type & get(const container<T...> & c) {
105  return bits::get_impl<i, T...>::get(c);
106 }
107 
108 namespace bits {
109 template<int ... S>
110 struct dispatch {
111  template <typename F, typename ... T1, typename ... T2>
112  static F run_move(container<T1...> & t, T2 &&... o) {
113  return F(std::move(o)..., move_if_movable<T1>(get<S>(t))...);
114  }
115 
116  template <typename F, typename ... T1, typename ... T2>
117  static F run_copy(container<T1...> & t, T2 &&... o) {
118  return F(std::move(o)..., get<S>(t)...);
119  }
120 };
121 
122 template<int N, int ...S>
123 struct dispatch_gen : dispatch_gen<N-1, N-1, S...> { };
124 
125 template<int ...S>
126 struct dispatch_gen<0, S...> {
127  typedef dispatch<S...> type;
128 };
129 
130 } //namespace bits
131 
132 
133 template <typename F, typename ... T1, typename ... T2>
134 F container_construct(container<T1...> & cont, T2 && ... a) {
135  return bits::dispatch_gen<sizeof...(T1)>::type::template run_move<F>(cont, std::move(a)...);
136 }
137 
138 template <typename F, typename ... T1, typename ... T2>
139 F container_construct_copy(container<T1...> & cont, T2 && ... a) {
140  return bits::dispatch_gen<sizeof...(T1)>::type::template run_copy<F>(cont, std::move(a)...);
141 }
142 
143 class bad_any_noncopyable_copy: public std::exception {
144 public:
145  const char * what() const noexcept override {return "bad any_noncopyable copy";}
146 };
147 
148 
149 namespace bits {
150 
152 public:
153  virtual ~any_noncopyable_cont_base() {};
154  virtual const std::type_info & type() const {
155  return typeid(void);
156  }
157  virtual any_noncopyable_cont_base * copy() const = 0;
158 };
159 
160 template <typename T, bool can_copy = std::is_copy_constructible<T>::value>
162 public:
163  any_noncopyable_cont(T value): value(move_if_movable<T>(value)) {}
164  T value;
165  const std::type_info & type() const override {
166  return typeid(value);
167  }
168 
169  any_noncopyable_cont_base * copy() const override {
170  throw bad_any_noncopyable_copy();
171  }
172 };
173 
174 template <typename T>
176 public:
177  any_noncopyable_cont(T value): value(move_if_movable<T>(value)) {}
178  T value;
179  const std::type_info & type() const override {
180  return typeid(value);
181  }
182 
183  any_noncopyable_cont_base * copy() const override {
184  return new any_noncopyable_cont<T, true>(value);
185  }
186 };
187 
188 
189 } //namespace bits
190 
191 class bad_any_noncopyable_cast: public std::bad_cast {
192 public:
193  const char * what() const noexcept override {return "bad any_noncopyable cast";}
194 };
195 
197 public:
198  template <typename T>
199  explicit any_noncopyable(T t) {
200  cont = std::unique_ptr<bits::any_noncopyable_cont_base>(
201  new bits::any_noncopyable_cont<T>(move_if_movable<T>(t)));
202  }
203 
204  any_noncopyable() = default;
205  any_noncopyable(const any_noncopyable &) = delete;
206  any_noncopyable(any_noncopyable &&) = default;
207  any_noncopyable & operator=(const any_noncopyable & o) = delete;
208  any_noncopyable & operator=(any_noncopyable && o) = default;
209 
210  template <typename T>
211  any_noncopyable & operator=(T t) {
212  cont = std::unique_ptr<bits::any_noncopyable_cont_base>(
213  new bits::any_noncopyable_cont<T>(move_if_movable<T>(t)));
214  return *this;
215  }
216 
217  explicit operator bool() {return (bool)cont;}
218 
219  void reset() {cont.reset();}
220 
221  any_noncopyable copy() const {
222  return any_noncopyable(cont->copy());
223  }
224 
225  template <typename T>
226  friend const T & any_cast(const any_noncopyable & a);
227 
228  template <typename T>
229  friend T & any_cast(any_noncopyable & a);
230 
231  friend void swap(any_noncopyable & l, any_noncopyable & r);
232 
233  const std::type_info & type() const {
234  if (!cont) return typeid(void);
235  auto val = cont.get();
236  return val->type();
237  }
238 private:
240  : cont(elm) {}
241 
242  std::unique_ptr<bits::any_noncopyable_cont_base> cont;
243 };
244 
245 template <typename T>
246 const T & any_cast(const any_noncopyable & a) {
247  if (!a.cont) throw bad_any_noncopyable_cast();
248  auto val = a.cont.get();
249  if (typeid(*val) != typeid(bits::any_noncopyable_cont<T>)) throw bad_any_noncopyable_cast();
250  return static_cast<const bits::any_noncopyable_cont<T>*>(val)->value;
251 }
252 
253 template <typename T>
254 T & any_cast(any_noncopyable & a) {
255  if (!a.cont) throw bad_any_noncopyable_cast();
256  auto val = a.cont.get();
257  if (typeid(*val) != typeid(bits::any_noncopyable_cont<T>)) throw bad_any_noncopyable_cast();
258  return static_cast<bits::any_noncopyable_cont<T>*>(val)->value;
259 }
260 
261 inline void swap(any_noncopyable & l, any_noncopyable & r) {std::swap(l.cont, r.cont);}
262 
263 } //namespace pipelining
264 } //namespace tpie
265 #endif //__TPIE_PIPELINING_PIPE_CONTAINER_H__