PVData C++  8.0.5
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 
39 /** A type-safe variant union capable of holding
40  * any of the PVD scalar types (POD or string)
41  *
42  @code
43  AnyScalar A(5);
44  assert(A.type()==pvInt);
45  assert(A.ref<int32>()==5);
46  assert(A.as<int32>()==5);
47  assert(A.as<double>()==5.0);
48  assert(A.ref<double>()==5.0); // throws AnyScalar::bad_cast
49  @endcode
50  */
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:
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:
98  //! Construct empty
99  //! @post empty()==true
101 
102  //! Construct from provided value.
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 
118  //! Construct from un-typed pointer.
119  //! Caller is responsible to ensure that buf actually points to the provided type
120  //! @version Added after 7.0.0
121  AnyScalar(ScalarType type, const void *buf);
122 
123  AnyScalar(const AnyScalar& o);
124 
125 #if __cplusplus>=201103L
126  AnyScalar(AnyScalar&& o);
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) {
144  clear();
145  swap(o);
146  return *this;
147  }
148 #endif
149 
150  //! Reset internal state.
151  //! @version Added after 7.0.0
152  //! @post empty()==true
153  void clear();
154 
155  void swap(AnyScalar& o);
156 
157  //! Type code of contained value. Or (ScalarType)-1 is empty.
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 
176  //! Provide read-only access to underlying buffer.
177  //! For a string this is std::string::c_str().
178  //! @version Added after 7.0.0
179  const void* bufferUnsafe() const;
180 
181  /** Return typed reference to wrapped value. Non-const reference allows value modification
182  *
183  * @throws bad_cast when the requested type does not match the stored type
184  @code
185  AnyScalar v(42);
186  v.ref<uint32>() = 43;
187  assert(v.ref<uint32>() == 43);
188  @endcode
189  */
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 
203  /** Return typed reference to wrapped value. Const reference does not allow modification.
204  *
205  * @throws bad_cast when the requested type does not match the stored type
206  @code
207  const AnyScalar v(42);
208  assert(v.ref<uint32>() == 42);
209  @endcode
210  */
211  template<typename T>
212  inline
213  // T -> strip_const -> map to storage type -> add const reference
214  typename meta::decorate_const<typename detail::any_storage_type<typename meta::strip_const<T>::type>::type>::type&
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 
224  /** copy out wrapped value, with a value conversion.
225  *
226  * @throws bad_cast when empty()==true
227  */
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;
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
Definition: pvData.h:1662
epicsShareFunc bool yajl_parse_helper(std::istream &src, yajl_handle handle)