PVData C++
8.0.5
misc
pv
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
:
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
:
98
//! Construct empty
99
//! @post empty()==true
100
AnyScalar
() :
_stype
((
ScalarType
)-1) {}
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.
115
_stype
= (
ScalarType
)
ScalarTypeID
<
TT
>::
value
;
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
198
if
(
_stype
!=(
ScalarType
)
ScalarTypeID
<
TT
>::
value
)
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
219
if
(
_stype
!=(
ScalarType
)
ScalarTypeID
<
TT
>::
value
)
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
;
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
std
Definition:
pvData.h:1662
epics::pvData::AnyScalar
Definition:
anyscalar.h:51
epics::pvData::yajl_parse_helper
epicsShareFunc bool yajl_parse_helper(std::istream &src, yajl_handle handle)
epics::pvData::detail::any_storage_type
Definition:
anyscalar.h:24
Generated on Wed Sep 7 2022 15:52:54 for PVData C++ by
1.8.13