PVData C++  8.0.6
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Groups Pages
anyscalar.h
1 #ifndef PV_ANYSCALAR_H
2 #define PV_ANYSCALAR_H
3 
4 #if __cplusplus>=201103L
5 # include <type_traits>
6 #endif
7 
8 #include <ostream>
9 #include <exception>
10 #include <map>
11 
12 #include <epicsAssert.h>
13 
14 #include <pv/templateMeta.h>
15 #include <pv/typeCast.h>
16 #include <pv/pvIntrospect.h> /* for ScalarType enum */
17 
18 namespace epics{namespace pvData{
19 namespace detail {
20 
21 // special mangling for AnyScalar ctor to map from argument type to storage type.
22 // allow construction from constants.
23 template <typename T>
24 struct any_storage_type { typedef T type; };
25 template<> struct any_storage_type<int> { typedef int32 type; };
26 template<> struct any_storage_type<unsigned> { typedef uint32 type; };
27 template<> struct any_storage_type<char*> { typedef std::string type; };
28 template<> struct any_storage_type<const char*> { typedef std::string type; };
29 
30 #if __cplusplus>=201103L
31 // std::max() isn't constexpr until c++14 :(
32 constexpr size_t cmax(size_t A, size_t B) {
33  return A>B ? A : B;
34 }
35 #endif
36 
37 }// namespace detail
38 
51 class epicsShareClass AnyScalar {
52 public:
53  struct bad_cast : public std::exception {
54 #if __cplusplus>=201103L
55  bad_cast() noexcept {}
56  virtual ~bad_cast() noexcept {}
57  virtual const char* what() const noexcept
58 #else
59  bad_cast() throw() {}
60  virtual ~bad_cast() throw() {}
61  virtual const char* what() const throw()
62 #endif
63  { return "bad_cast() type mis-match"; }
64  };
65 
66 private:
67  ScalarType _stype;
68 
69  // always reserve enough storage for std::string or double (assumed worst case)
70 #if __cplusplus>=201103L
71 
72  struct wrap_t {
73  typename std::aligned_storage<detail::cmax(sizeof(std::string), sizeof(double)),
74  detail::cmax(alignof(std::string), alignof(double))
75  >::type blob[1];
76  } _wrap;
77 #else
78  struct wrap_t {
79  union blob_t {
80  char data[sizeof(std::string)];
81  double align_f; // assume std::string alignment <= 8
82  } blob[1];
83  } _wrap;
84 #endif
85 
86  // assumed largest non-string type
87  typedef double _largest_blob;
88 
89  template<typename T>
90  inline T& _as() {
91  return *reinterpret_cast<T*>(_wrap.blob);
92  }
93  template<typename T>
94  inline const T& _as() const {
95  return *reinterpret_cast<const T*>(_wrap.blob);
96  }
97 public:
100  AnyScalar() : _stype((ScalarType)-1) {}
101 
103  template<typename T>
104  explicit AnyScalar(T v)
105  {
106  typedef typename meta::strip_const<T>::type T2;
107  typedef typename detail::any_storage_type<T2>::type TT;
108 
109  STATIC_ASSERT(sizeof(TT)<=sizeof(_wrap.blob));
110 
111  new (_wrap.blob) TT(v);
112 
113  // this line fails to compile when type T can't be mapped to one of
114  // the PVD scalar types.
116  }
117 
121  AnyScalar(ScalarType type, const void *buf);
122 
123  AnyScalar(const AnyScalar& o);
124 
125 #if __cplusplus>=201103L
126  AnyScalar(AnyScalar&& o) noexcept;
127 #endif
128 
129  inline ~AnyScalar() {clear();}
130 
131  inline AnyScalar& operator=(const AnyScalar& o) {
132  AnyScalar(o).swap(*this);
133  return *this;
134  }
135 
136  template<typename T>
137  inline AnyScalar& operator=(T v) {
138  AnyScalar(v).swap(*this);
139  return *this;
140  }
141 
142 #if __cplusplus>=201103L
143  inline AnyScalar& operator=(AnyScalar&& o) noexcept {
144  clear();
145  swap(o);
146  return *this;
147  }
148 #endif
149 
153  void clear();
154 
155  void swap(AnyScalar& o);
156 
158  inline ScalarType type() const {
159  return _stype;
160  }
161 
162  inline void* unsafe() { return _wrap.blob; }
163  inline const void* unsafe() const { return _wrap.blob; }
164 
165  inline bool empty() const { return _stype==(ScalarType)-1; }
166 
167 #if __cplusplus>=201103L
168  explicit operator bool() const { return !empty(); }
169 #else
170 private:
171  typedef void (AnyScalar::*bool_type)(AnyScalar&);
172 public:
173  operator bool_type() const { return !empty() ? &AnyScalar::swap : 0; }
174 #endif
175 
179  const void* bufferUnsafe() const;
180 
190  template<typename T>
191  inline
192  // T -> strip_const -> map to storage type -> add reference
193  typename detail::any_storage_type<typename meta::strip_const<T>::type>::type&
194  ref() {
195  typedef typename meta::strip_const<T>::type T2;
196  typedef typename detail::any_storage_type<T2>::type TT;
197 
199  throw bad_cast();
200  return reinterpret_cast<TT&>(_wrap.blob);
201  }
202 
211  template<typename T>
212  inline
213  // T -> strip_const -> map to storage type -> add const reference
215  ref() const {
216  typedef typename meta::strip_const<T>::type T2;
217  typedef typename detail::any_storage_type<T2>::type TT;
218 
220  throw bad_cast();
221  return reinterpret_cast<typename meta::decorate_const<TT>::type&>(_wrap.blob);
222  }
223 
228  template<typename T>
229  inline
230  T as() const {
231  typedef typename meta::strip_const<T>::type T2;
232  typedef typename detail::any_storage_type<T2>::type TT;
233 
234  if(_stype==(ScalarType)-1)
235  throw bad_cast();
236  TT ret;
237  castUnsafeV(1, (ScalarType)ScalarTypeID<T2>::value, &ret,
238  _stype, _wrap.blob);
239  return ret;
240  }
241 
242 private:
243  friend epicsShareFunc std::ostream& operator<<(std::ostream& strm, const AnyScalar& v);
244 };
245 
246 epicsShareExtern
247 std::ostream& operator<<(std::ostream& strm, const AnyScalar& v);
248 
249 }} // namespace epics::pvData
250 
251 #endif // PV_ANYSCALAR_H
basic_ostream< _CharT, _Traits > & operator<<(basic_ostream< _CharT, _Traits > &__os, const basic_string< _CharT, _Traits, _Alloc > &__str)
ScalarType type() const
Type code of contained value. Or (ScalarType)-1 is empty.
Definition: anyscalar.h:158
constexpr auto empty(const _Container &__cont) noexcept(noexcept(__cont.empty())) -> decltype(__cont.empty())
uint32_t uint32
Definition: pvType.h:99
AnyScalar(T v)
Construct from provided value.
Definition: anyscalar.h:104
T swap(T val)
Definition: byteBuffer.h:212
constexpr complex< _Tp > & operator=(const _Tp &)
detail::any_storage_type< typename meta::strip_const< T >::type >::type & ref()
Definition: anyscalar.h:194
basic_string< char > string
meta::decorate_const< typename detail::any_storage_type< typename meta::strip_const< T >::type >::type >::type & ref() const
Definition: anyscalar.h:215
int32_t int32
Definition: pvType.h:83
constexpr auto data(_Container &__cont) noexcept(noexcept(__cont.data())) -> decltype(__cont.data())