pvxslibs 1.5.0__cp310-cp310-manylinux2014_x86_64.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pvxslibs/__init__.py +0 -0
- pvxslibs/dbd/pvxsIoc.dbd +8 -0
- pvxslibs/include/pvxs/client.h +1094 -0
- pvxslibs/include/pvxs/data.h +948 -0
- pvxslibs/include/pvxs/iochooks.h +170 -0
- pvxslibs/include/pvxs/log.h +148 -0
- pvxslibs/include/pvxs/netcommon.h +82 -0
- pvxslibs/include/pvxs/nt.h +208 -0
- pvxslibs/include/pvxs/server.h +238 -0
- pvxslibs/include/pvxs/sharedArray.h +748 -0
- pvxslibs/include/pvxs/sharedpv.h +121 -0
- pvxslibs/include/pvxs/source.h +290 -0
- pvxslibs/include/pvxs/srvcommon.h +148 -0
- pvxslibs/include/pvxs/unittest.h +327 -0
- pvxslibs/include/pvxs/util.h +354 -0
- pvxslibs/include/pvxs/version.h +97 -0
- pvxslibs/include/pvxs/versionNum.h +6 -0
- pvxslibs/ioc.py +10 -0
- pvxslibs/lib/__init__.py +0 -0
- pvxslibs/lib/event_core_dsoinfo.py +14 -0
- pvxslibs/lib/event_pthread_dsoinfo.py +14 -0
- pvxslibs/lib/libevent_core.so +0 -0
- pvxslibs/lib/libevent_core.so.2.2.0 +0 -0
- pvxslibs/lib/libevent_pthread.so +0 -0
- pvxslibs/lib/libevent_pthread.so.2.2.0 +0 -0
- pvxslibs/lib/libpvxs.so +0 -0
- pvxslibs/lib/libpvxs.so.1.5 +0 -0
- pvxslibs/lib/libpvxsIoc.so +0 -0
- pvxslibs/lib/libpvxsIoc.so.1.5 +0 -0
- pvxslibs/lib/pvxsIoc_dsoinfo.py +14 -0
- pvxslibs/lib/pvxs_dsoinfo.py +14 -0
- pvxslibs/path.py +12 -0
- pvxslibs/test/__init__.py +0 -0
- pvxslibs/test/test_load.py +30 -0
- pvxslibs/version.py +32 -0
- pvxslibs-1.5.0.dist-info/METADATA +44 -0
- pvxslibs-1.5.0.dist-info/RECORD +40 -0
- pvxslibs-1.5.0.dist-info/WHEEL +5 -0
- pvxslibs-1.5.0.dist-info/licenses/LICENSE +26 -0
- pvxslibs-1.5.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,948 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Copyright - See the COPYRIGHT that is included with this distribution.
|
|
3
|
+
* pvxs is distributed subject to a Software License Agreement found
|
|
4
|
+
* in file LICENSE that is included with this distribution.
|
|
5
|
+
*/
|
|
6
|
+
#ifndef PVXS_DATA_H
|
|
7
|
+
#define PVXS_DATA_H
|
|
8
|
+
|
|
9
|
+
#include <initializer_list>
|
|
10
|
+
#include <stdexcept>
|
|
11
|
+
#include <vector>
|
|
12
|
+
#include <iosfwd>
|
|
13
|
+
#include <string>
|
|
14
|
+
#include <memory>
|
|
15
|
+
#include <typeinfo>
|
|
16
|
+
#include <tuple>
|
|
17
|
+
|
|
18
|
+
#include <pvxs/version.h>
|
|
19
|
+
#include <pvxs/sharedArray.h>
|
|
20
|
+
|
|
21
|
+
namespace pvxs {
|
|
22
|
+
class Value;
|
|
23
|
+
class TypeDef;
|
|
24
|
+
namespace client {
|
|
25
|
+
namespace detail {
|
|
26
|
+
class CommonBase;
|
|
27
|
+
}} // namespace client::detail
|
|
28
|
+
|
|
29
|
+
//! selector for union FieldStorage::store
|
|
30
|
+
enum struct StoreType : uint8_t {
|
|
31
|
+
Null, //!< no associate storage
|
|
32
|
+
Bool, //!< bool
|
|
33
|
+
UInteger, //!< uint64_t
|
|
34
|
+
Integer, //!< int64_t
|
|
35
|
+
Real, //!< double
|
|
36
|
+
String, //!< std::string
|
|
37
|
+
Compound, //!< Value
|
|
38
|
+
Array, //!< shared_array<const void>
|
|
39
|
+
};
|
|
40
|
+
|
|
41
|
+
PVXS_API
|
|
42
|
+
std::ostream& operator<<(std::ostream& strm, StoreType c);
|
|
43
|
+
|
|
44
|
+
constexpr struct unselect_t {} unselect;
|
|
45
|
+
|
|
46
|
+
namespace impl {
|
|
47
|
+
struct FieldStorage;
|
|
48
|
+
struct FieldDesc;
|
|
49
|
+
|
|
50
|
+
//! maps T to one of the types which can be stored in the FieldStorage::store union
|
|
51
|
+
//! typename StorageMap<T>::store_t is, if existent, one such type.
|
|
52
|
+
//! store_t shall be convertible to/from T through StoreTransform<T>::in() and out().
|
|
53
|
+
//! StorageMap<T>::code is the associated StoreType.
|
|
54
|
+
template<typename T, typename Enable=void>
|
|
55
|
+
struct StorageMap {
|
|
56
|
+
typedef void not_storable;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
// map signed integers to int64_t
|
|
60
|
+
template<typename T>
|
|
61
|
+
struct StorageMap<T, typename std::enable_if<std::is_integral<T>::value && std::is_signed<T>::value>::type>
|
|
62
|
+
{ typedef int64_t store_t; static constexpr StoreType code{StoreType::Integer}; };
|
|
63
|
+
|
|
64
|
+
// map unsigned integers to uint64_t
|
|
65
|
+
template<typename T>
|
|
66
|
+
struct StorageMap<T, typename std::enable_if<std::is_integral<T>::value && !std::is_signed<T>::value && !std::is_same<T,bool>::value>::type>
|
|
67
|
+
{ typedef uint64_t store_t; static constexpr StoreType code{StoreType::UInteger}; };
|
|
68
|
+
|
|
69
|
+
// map floating point to double. (truncates long double, but then PVA doesn't have >8 byte primitives support anyway)
|
|
70
|
+
template<typename T>
|
|
71
|
+
struct StorageMap<T, typename std::enable_if<std::is_floating_point<T>::value>::type>
|
|
72
|
+
{ typedef double store_t; static constexpr StoreType code{StoreType::Real}; };
|
|
73
|
+
|
|
74
|
+
template<>
|
|
75
|
+
struct StorageMap<bool>
|
|
76
|
+
{ typedef bool store_t; static constexpr StoreType code{StoreType::Bool}; };
|
|
77
|
+
|
|
78
|
+
template<>
|
|
79
|
+
struct StorageMap<std::string>
|
|
80
|
+
{ typedef std::string store_t; static constexpr StoreType code{StoreType::String}; };
|
|
81
|
+
|
|
82
|
+
template<>
|
|
83
|
+
struct StorageMap<char*>
|
|
84
|
+
{ typedef std::string store_t; static constexpr StoreType code{StoreType::String}; };
|
|
85
|
+
|
|
86
|
+
template<>
|
|
87
|
+
struct StorageMap<const char*>
|
|
88
|
+
{ typedef std::string store_t; static constexpr StoreType code{StoreType::String}; };
|
|
89
|
+
|
|
90
|
+
template<typename E>
|
|
91
|
+
struct StorageMap<shared_array<const E>>
|
|
92
|
+
{ typedef shared_array<const void> store_t; static constexpr StoreType code{StoreType::Array}; };
|
|
93
|
+
|
|
94
|
+
template<>
|
|
95
|
+
struct StorageMap<Value>
|
|
96
|
+
{ typedef Value store_t; static constexpr StoreType code{StoreType::Compound}; };
|
|
97
|
+
|
|
98
|
+
template<>
|
|
99
|
+
struct StorageMap<unselect_t>
|
|
100
|
+
{ typedef unselect_t store_t; static constexpr StoreType code{StoreType::Null}; };
|
|
101
|
+
|
|
102
|
+
// drill through enum{} to handle as underlying integer type
|
|
103
|
+
template<typename T>
|
|
104
|
+
struct StorageMap<T, typename std::enable_if<std::is_enum<T>::value>::type>
|
|
105
|
+
:StorageMap<typename std::underlying_type<T>::type>
|
|
106
|
+
{};
|
|
107
|
+
|
|
108
|
+
template<typename T>
|
|
109
|
+
using StoreAs = StorageMap<typename std::decay<T>::type>;
|
|
110
|
+
|
|
111
|
+
template<typename T, typename Enable=void>
|
|
112
|
+
struct StoreTransform {
|
|
113
|
+
// pass through by default
|
|
114
|
+
static inline const T& in (const T& v) { return v; }
|
|
115
|
+
static inline const T& out(const T& v) { return v; }
|
|
116
|
+
};
|
|
117
|
+
template<typename E>
|
|
118
|
+
struct StoreTransform<shared_array<const E>> {
|
|
119
|
+
// cast shared_array to void
|
|
120
|
+
static inline
|
|
121
|
+
shared_array<const void> in(const shared_array<const E>& v) {
|
|
122
|
+
return v.template castTo<const void>();
|
|
123
|
+
}
|
|
124
|
+
static inline
|
|
125
|
+
shared_array<const E> out(const shared_array<const void>& v) {
|
|
126
|
+
return v.template convertTo<const E>();
|
|
127
|
+
}
|
|
128
|
+
};
|
|
129
|
+
template<typename T>
|
|
130
|
+
struct StoreTransform<T, typename std::enable_if<std::is_enum<T>::value>::type> {
|
|
131
|
+
typedef typename std::underlying_type<T>::type itype_t;
|
|
132
|
+
static inline
|
|
133
|
+
itype_t in(const T& v) { return v; }
|
|
134
|
+
static inline
|
|
135
|
+
T out(const itype_t& v) { return static_cast<T>(v); }
|
|
136
|
+
};
|
|
137
|
+
|
|
138
|
+
} // namespace impl
|
|
139
|
+
|
|
140
|
+
//! Groups of related types
|
|
141
|
+
enum struct Kind : uint8_t {
|
|
142
|
+
Bool = 0x00,
|
|
143
|
+
Integer = 0x20,
|
|
144
|
+
Real = 0x40,
|
|
145
|
+
String = 0x60,
|
|
146
|
+
Compound = 0x80,
|
|
147
|
+
Null = 0xe0,
|
|
148
|
+
};
|
|
149
|
+
|
|
150
|
+
/** Possible Field types.
|
|
151
|
+
*
|
|
152
|
+
* eg. String is scalar string, StringA is array of strings.
|
|
153
|
+
*/
|
|
154
|
+
struct TypeCode {
|
|
155
|
+
//! actual complete (scalar) type code.
|
|
156
|
+
enum code_t : uint8_t {
|
|
157
|
+
Bool = 0x00,
|
|
158
|
+
BoolA = 0x08,
|
|
159
|
+
Int8 = 0x20,
|
|
160
|
+
Int16 = 0x21,
|
|
161
|
+
Int32 = 0x22,
|
|
162
|
+
Int64 = 0x23,
|
|
163
|
+
UInt8 = 0x24,
|
|
164
|
+
UInt16 = 0x25,
|
|
165
|
+
UInt32 = 0x26,
|
|
166
|
+
UInt64 = 0x27,
|
|
167
|
+
Int8A = 0x28,
|
|
168
|
+
Int16A = 0x29,
|
|
169
|
+
Int32A = 0x2a,
|
|
170
|
+
Int64A = 0x2b,
|
|
171
|
+
UInt8A = 0x2c,
|
|
172
|
+
UInt16A = 0x2d,
|
|
173
|
+
UInt32A = 0x2e,
|
|
174
|
+
UInt64A = 0x2f,
|
|
175
|
+
Float32 = 0x42,
|
|
176
|
+
Float64 = 0x43,
|
|
177
|
+
Float32A= 0x4a,
|
|
178
|
+
Float64A= 0x4b,
|
|
179
|
+
String = 0x60,
|
|
180
|
+
StringA = 0x68,
|
|
181
|
+
Struct = 0x80,
|
|
182
|
+
Union = 0x81,
|
|
183
|
+
Any = 0x82,
|
|
184
|
+
StructA = 0x88,
|
|
185
|
+
UnionA = 0x89,
|
|
186
|
+
AnyA = 0x8a,
|
|
187
|
+
// 0xfd - cache update w/ full
|
|
188
|
+
// 0xfe - cache fetch
|
|
189
|
+
Null = 0xff,
|
|
190
|
+
};
|
|
191
|
+
|
|
192
|
+
//! the actual type code. eg. for switch()
|
|
193
|
+
code_t code;
|
|
194
|
+
|
|
195
|
+
bool valid() const;
|
|
196
|
+
|
|
197
|
+
Kind kind() const { return Kind(code&0xe0); }
|
|
198
|
+
//! size()==1<<order()
|
|
199
|
+
uint8_t order() const { return code&3; }
|
|
200
|
+
//! Size in bytes for simple kinds (Bool, Integer, Real)
|
|
201
|
+
uint8_t size() const { return 1u<<order(); }
|
|
202
|
+
//! For Integer kind
|
|
203
|
+
bool isunsigned() const { return code&0x04; }
|
|
204
|
+
//! For all
|
|
205
|
+
bool isarray() const { return code&0x08; }
|
|
206
|
+
|
|
207
|
+
constexpr TypeCode() :code(Null) {}
|
|
208
|
+
constexpr explicit TypeCode(uint8_t c) :code(code_t(c)) {}
|
|
209
|
+
constexpr TypeCode(code_t c) :code(c) {}
|
|
210
|
+
|
|
211
|
+
PVXS_API StoreType storedAs() const;
|
|
212
|
+
PVXS_API ArrayType arrayType() const;
|
|
213
|
+
|
|
214
|
+
//! associated array of type
|
|
215
|
+
constexpr TypeCode arrayOf() const {return TypeCode{uint8_t(code|0x08)};}
|
|
216
|
+
//! associated not array of type
|
|
217
|
+
constexpr TypeCode scalarOf() const {return TypeCode{uint8_t(code&~0x08)};}
|
|
218
|
+
|
|
219
|
+
//! name string. eg. "bool" or "uint8_t"
|
|
220
|
+
PVXS_API const char* name() const;
|
|
221
|
+
};
|
|
222
|
+
|
|
223
|
+
inline bool operator==(TypeCode lhs, TypeCode rhs) {
|
|
224
|
+
return lhs.code==rhs.code;
|
|
225
|
+
}
|
|
226
|
+
inline bool operator!=(TypeCode lhs, TypeCode rhs) {
|
|
227
|
+
return lhs.code!=rhs.code;
|
|
228
|
+
}
|
|
229
|
+
PVXS_API
|
|
230
|
+
std::ostream& operator<<(std::ostream& strm, TypeCode c);
|
|
231
|
+
|
|
232
|
+
namespace impl {
|
|
233
|
+
template<typename T>
|
|
234
|
+
struct ScalarMap;
|
|
235
|
+
|
|
236
|
+
#define CASE(TYPE, STORE, CODE) \
|
|
237
|
+
template<> struct ScalarMap<TYPE> { typedef STORE store_t; static constexpr TypeCode::code_t code{TypeCode::CODE}; }
|
|
238
|
+
|
|
239
|
+
CASE(bool , uint64_t, Bool);
|
|
240
|
+
CASE(uint8_t , uint64_t, UInt8);
|
|
241
|
+
CASE(uint16_t, uint64_t, UInt16);
|
|
242
|
+
CASE(uint32_t, uint64_t, UInt32);
|
|
243
|
+
CASE(uint64_t, uint64_t, UInt64);
|
|
244
|
+
CASE(int8_t , int64_t , Int8);
|
|
245
|
+
CASE(int16_t , int64_t , Int16);
|
|
246
|
+
CASE(int32_t , int64_t , Int32);
|
|
247
|
+
CASE(int64_t , int64_t , Int64);
|
|
248
|
+
CASE(float , double , Float32);
|
|
249
|
+
CASE(double , double , Float64);
|
|
250
|
+
CASE(std::string, std::string, String);
|
|
251
|
+
|
|
252
|
+
#undef CASE
|
|
253
|
+
|
|
254
|
+
} // namespace impl
|
|
255
|
+
|
|
256
|
+
//! Definition of a member of a Struct/Union for use with TypeDef
|
|
257
|
+
struct Member {
|
|
258
|
+
private:
|
|
259
|
+
TypeCode code;
|
|
260
|
+
std::string name;
|
|
261
|
+
std::string id;
|
|
262
|
+
std::vector<Member> children;
|
|
263
|
+
friend class TypeDef;
|
|
264
|
+
friend class client::detail::CommonBase;
|
|
265
|
+
|
|
266
|
+
PVXS_API
|
|
267
|
+
void _validate() const;
|
|
268
|
+
public:
|
|
269
|
+
struct Helper;
|
|
270
|
+
|
|
271
|
+
//! Empty/invalid Member
|
|
272
|
+
inline
|
|
273
|
+
Member() :code(TypeCode::Null) {}
|
|
274
|
+
|
|
275
|
+
//! Member for non-Compound
|
|
276
|
+
//! @pre code.kind()!=Kind::Compound
|
|
277
|
+
inline
|
|
278
|
+
Member(TypeCode code, const std::string& name)
|
|
279
|
+
:Member(code, name, {})
|
|
280
|
+
{}
|
|
281
|
+
//! Compound member with type ID
|
|
282
|
+
Member(TypeCode code, const std::string& name, const std::string& id, std::initializer_list<Member> children)
|
|
283
|
+
:code(code)
|
|
284
|
+
,name(name)
|
|
285
|
+
,id(id)
|
|
286
|
+
,children(children.begin(), children.end())
|
|
287
|
+
{_validate();}
|
|
288
|
+
template<typename Iterable>
|
|
289
|
+
Member(TypeCode code, const std::string& name, const std::string& id, const Iterable& children)
|
|
290
|
+
:code(code)
|
|
291
|
+
,name(name)
|
|
292
|
+
,id(id)
|
|
293
|
+
,children(children.begin(), children.end())
|
|
294
|
+
{_validate();}
|
|
295
|
+
//! Compound member without type ID
|
|
296
|
+
inline
|
|
297
|
+
Member(TypeCode code, const std::string& name, std::initializer_list<Member> children)
|
|
298
|
+
:Member(code, name , std::string(), children)
|
|
299
|
+
{}
|
|
300
|
+
template<typename Iterable>
|
|
301
|
+
inline
|
|
302
|
+
Member(TypeCode code, const std::string& name, const Iterable& children)
|
|
303
|
+
:Member(code, name , std::string(), children)
|
|
304
|
+
{}
|
|
305
|
+
|
|
306
|
+
PVXS_API
|
|
307
|
+
void addChild(const Member& mem);
|
|
308
|
+
};
|
|
309
|
+
|
|
310
|
+
/** Helper functions for building TypeDef.
|
|
311
|
+
*
|
|
312
|
+
* Each of the TypeCode::code_t enums has an associated helper function of the same name
|
|
313
|
+
* which is a shorthand notation for a Member().
|
|
314
|
+
*
|
|
315
|
+
* eg. @code members::UInt32("blah") @endcode is equivalent to @code Member(TypeCode::UInt32, "blah") @endcode
|
|
316
|
+
*/
|
|
317
|
+
namespace members {
|
|
318
|
+
#define CASE(TYPE) \
|
|
319
|
+
inline Member TYPE(const std::string& name) { return Member(TypeCode::TYPE, name); }
|
|
320
|
+
CASE(Bool)
|
|
321
|
+
CASE(UInt8)
|
|
322
|
+
CASE(UInt16)
|
|
323
|
+
CASE(UInt32)
|
|
324
|
+
CASE(UInt64)
|
|
325
|
+
CASE(Int8)
|
|
326
|
+
CASE(Int16)
|
|
327
|
+
CASE(Int32)
|
|
328
|
+
CASE(Int64)
|
|
329
|
+
CASE(Float32)
|
|
330
|
+
CASE(Float64)
|
|
331
|
+
CASE(String)
|
|
332
|
+
CASE(Any)
|
|
333
|
+
CASE(BoolA)
|
|
334
|
+
CASE(UInt8A)
|
|
335
|
+
CASE(UInt16A)
|
|
336
|
+
CASE(UInt32A)
|
|
337
|
+
CASE(UInt64A)
|
|
338
|
+
CASE(Int8A)
|
|
339
|
+
CASE(Int16A)
|
|
340
|
+
CASE(Int32A)
|
|
341
|
+
CASE(Int64A)
|
|
342
|
+
CASE(Float32A)
|
|
343
|
+
CASE(Float64A)
|
|
344
|
+
CASE(StringA)
|
|
345
|
+
CASE(AnyA)
|
|
346
|
+
#undef CASE
|
|
347
|
+
|
|
348
|
+
#define CASE(TYPE) \
|
|
349
|
+
inline Member TYPE(const std::string& name, std::initializer_list<Member> children) { return Member(TypeCode::TYPE, name, children); } \
|
|
350
|
+
template <typename Iterable> \
|
|
351
|
+
inline Member TYPE(const std::string& name, const Iterable& children) { return Member(TypeCode::TYPE, name, children); } \
|
|
352
|
+
inline Member TYPE(const std::string& name, const std::string& id, std::initializer_list<Member> children) { return Member(TypeCode::TYPE, name, id, children); } \
|
|
353
|
+
template <typename Iterable> \
|
|
354
|
+
inline Member TYPE(const std::string& name, const std::string& id, const Iterable& children) { return Member(TypeCode::TYPE, name, id, children); }
|
|
355
|
+
|
|
356
|
+
CASE(Struct)
|
|
357
|
+
CASE(Union)
|
|
358
|
+
CASE(StructA)
|
|
359
|
+
CASE(UnionA)
|
|
360
|
+
#undef CASE
|
|
361
|
+
} // namespace members
|
|
362
|
+
|
|
363
|
+
/** Define a new type, either from scratch, or based on an existing Value
|
|
364
|
+
*
|
|
365
|
+
* @code
|
|
366
|
+
* namespace M = pvxs::members;
|
|
367
|
+
* auto def1 = TypeDef(TypeCode::Int32); // a single scalar field
|
|
368
|
+
* auto def2 = TypeDef(TypeCode::Struct, {
|
|
369
|
+
* M::Int32("value"),
|
|
370
|
+
* M::Struct("alarm", "alarm_t", {
|
|
371
|
+
* M::Int32("severity"),
|
|
372
|
+
* }),
|
|
373
|
+
* def1.as("special"), // compose definitions
|
|
374
|
+
* });
|
|
375
|
+
*
|
|
376
|
+
* auto val = def2.create(); // instantiate a Value
|
|
377
|
+
* });
|
|
378
|
+
* @endcode
|
|
379
|
+
*/
|
|
380
|
+
class PVXS_API TypeDef
|
|
381
|
+
{
|
|
382
|
+
public:
|
|
383
|
+
struct Node;
|
|
384
|
+
private:
|
|
385
|
+
std::shared_ptr<const Member> top;
|
|
386
|
+
std::shared_ptr<const impl::FieldDesc> desc;
|
|
387
|
+
public:
|
|
388
|
+
//! new, empty, definition
|
|
389
|
+
TypeDef() = default;
|
|
390
|
+
// moveable, copyable
|
|
391
|
+
TypeDef(const TypeDef&) = default;
|
|
392
|
+
TypeDef(TypeDef&&) = default;
|
|
393
|
+
TypeDef& operator=(const TypeDef&) = default;
|
|
394
|
+
TypeDef& operator=(TypeDef&&) = default;
|
|
395
|
+
//! pre-populate definition based on provided Value
|
|
396
|
+
explicit TypeDef(const Value&);
|
|
397
|
+
~TypeDef();
|
|
398
|
+
|
|
399
|
+
//! new definition with id and children. code must be TypeCode::Struct or TypeCode::Union
|
|
400
|
+
template<typename Iterable>
|
|
401
|
+
TypeDef(TypeCode code, const std::string& id, const Iterable& children)
|
|
402
|
+
:TypeDef(std::make_shared<Member>(code, "", id, children))
|
|
403
|
+
{}
|
|
404
|
+
TypeDef(TypeCode code, const std::string& id, std::initializer_list<Member> children)
|
|
405
|
+
:TypeDef(std::make_shared<Member>(code, "", id, children))
|
|
406
|
+
{}
|
|
407
|
+
private:
|
|
408
|
+
TypeDef(std::shared_ptr<const Member>&&);
|
|
409
|
+
public:
|
|
410
|
+
//! new definition for a single scalar field. code must __not__ be TypeCode::Struct or TypeCode::Union
|
|
411
|
+
TypeDef(TypeCode code)
|
|
412
|
+
:TypeDef(code, std::string(), {})
|
|
413
|
+
{}
|
|
414
|
+
//! new definition without id. code must be TypeCode::Struct or TypeCode::Union
|
|
415
|
+
TypeDef(TypeCode code, std::initializer_list<Member> children)
|
|
416
|
+
:TypeDef(code, std::string(), children)
|
|
417
|
+
{}
|
|
418
|
+
|
|
419
|
+
//! Use this definition as a member (eg. sub-structure) in another definition.
|
|
420
|
+
Member as(const std::string& name) const;
|
|
421
|
+
|
|
422
|
+
/** Use this definition as a member (eg. sub-structure) in another definition
|
|
423
|
+
* with a (limited) type change.
|
|
424
|
+
*
|
|
425
|
+
* A ``Kind::Compound`` type (eg. ``Struct``) may be changed to another
|
|
426
|
+
* Compound type (eg. ``StructA``). However. changes between Compound
|
|
427
|
+
* and non-Compound are not allowed.
|
|
428
|
+
*
|
|
429
|
+
* @since 1.1.0
|
|
430
|
+
*/
|
|
431
|
+
Member as(TypeCode code, const std::string& name) const;
|
|
432
|
+
|
|
433
|
+
private:
|
|
434
|
+
std::shared_ptr<Member> _append_start();
|
|
435
|
+
static
|
|
436
|
+
void _append(Member& edit, const Member& mem);
|
|
437
|
+
void _append_finish(std::shared_ptr<Member>&& edit);
|
|
438
|
+
public:
|
|
439
|
+
|
|
440
|
+
//! append additional children. Only for TypeCode::Struct or TypeCode::Union
|
|
441
|
+
template<typename Iterable>
|
|
442
|
+
TypeDef& operator+=(const Iterable& children) {
|
|
443
|
+
auto edit = _append_start();
|
|
444
|
+
for(auto& child : children) {
|
|
445
|
+
_append(*edit, child);
|
|
446
|
+
}
|
|
447
|
+
_append_finish(std::move(edit));
|
|
448
|
+
return *this;
|
|
449
|
+
}
|
|
450
|
+
TypeDef& operator+=(std::initializer_list<Member> children) {
|
|
451
|
+
auto edit = _append_start();
|
|
452
|
+
for(auto& child : children) {
|
|
453
|
+
_append(*edit, child);
|
|
454
|
+
}
|
|
455
|
+
_append_finish(std::move(edit));
|
|
456
|
+
return *this;
|
|
457
|
+
}
|
|
458
|
+
|
|
459
|
+
//! Instantiate this definition
|
|
460
|
+
Value create() const;
|
|
461
|
+
|
|
462
|
+
friend
|
|
463
|
+
PVXS_API
|
|
464
|
+
std::ostream& operator<<(std::ostream& strm, const TypeDef&);
|
|
465
|
+
};
|
|
466
|
+
|
|
467
|
+
PVXS_API
|
|
468
|
+
std::ostream& operator<<(std::ostream& strm, const TypeDef&);
|
|
469
|
+
|
|
470
|
+
//! Thrown when accessing a Null Value
|
|
471
|
+
struct PVXS_API NoField : public std::runtime_error
|
|
472
|
+
{
|
|
473
|
+
explicit NoField();
|
|
474
|
+
virtual ~NoField();
|
|
475
|
+
};
|
|
476
|
+
|
|
477
|
+
//! Thrown when a Value can not be converted to the requested type
|
|
478
|
+
struct PVXS_API NoConvert : public std::runtime_error
|
|
479
|
+
{
|
|
480
|
+
NoConvert(const std::string& msg) : std::runtime_error(msg) {}
|
|
481
|
+
virtual ~NoConvert();
|
|
482
|
+
};
|
|
483
|
+
|
|
484
|
+
struct PVXS_API LookupError : public std::runtime_error
|
|
485
|
+
{
|
|
486
|
+
explicit LookupError(const std::string& msg);
|
|
487
|
+
virtual ~LookupError();
|
|
488
|
+
};
|
|
489
|
+
|
|
490
|
+
/** Generic data container
|
|
491
|
+
*
|
|
492
|
+
* References a single data field, which may be free-standing (eg. "int x = 5;")
|
|
493
|
+
* or a member of an enclosing Struct, or an element in an array of Struct.
|
|
494
|
+
*
|
|
495
|
+
* - Use valid() (or operator bool() ) to determine if pointed to a valid field.
|
|
496
|
+
* - Use operator[] to traverse within a Kind::Compound field.
|
|
497
|
+
*
|
|
498
|
+
* @code
|
|
499
|
+
* Value val = nt::NTScalar{TypeCode::Int32}.create();
|
|
500
|
+
* val["value"] = 42;
|
|
501
|
+
* Value alias = val;
|
|
502
|
+
* assert(alias["value"].as<int32_t>()==42); // 'alias' is a second reference to the same Struct
|
|
503
|
+
* @endcode
|
|
504
|
+
*/
|
|
505
|
+
class PVXS_API Value {
|
|
506
|
+
friend class TypeDef;
|
|
507
|
+
// (maybe) storage for this field. alias of StructTop::members[]
|
|
508
|
+
std::shared_ptr<impl::FieldStorage> store;
|
|
509
|
+
// (maybe) owned through StructTop (aliased as FieldStorage)
|
|
510
|
+
const impl::FieldDesc* desc;
|
|
511
|
+
public:
|
|
512
|
+
struct Helper;
|
|
513
|
+
friend struct Helper;
|
|
514
|
+
|
|
515
|
+
//! default empty Value
|
|
516
|
+
constexpr Value() :desc(nullptr) {}
|
|
517
|
+
private:
|
|
518
|
+
// Build new Value with the given type. Used by TypeDef
|
|
519
|
+
explicit Value(const std::shared_ptr<const impl::FieldDesc>& desc);
|
|
520
|
+
Value(const std::shared_ptr<const impl::FieldDesc>& desc, Value& parent);
|
|
521
|
+
public:
|
|
522
|
+
// movable and copyable
|
|
523
|
+
Value(const Value&) = default;
|
|
524
|
+
Value(Value&& o) noexcept
|
|
525
|
+
:desc(o.desc)
|
|
526
|
+
{
|
|
527
|
+
store = std::move(o.store);
|
|
528
|
+
o.desc = nullptr;
|
|
529
|
+
}
|
|
530
|
+
Value& operator=(const Value&) = default;
|
|
531
|
+
Value& operator=(Value&& o) noexcept {
|
|
532
|
+
store = std::move(o.store);
|
|
533
|
+
desc = o.desc;
|
|
534
|
+
o.desc = nullptr;
|
|
535
|
+
return *this;
|
|
536
|
+
}
|
|
537
|
+
~Value();
|
|
538
|
+
|
|
539
|
+
//! allocate new storage, with default values
|
|
540
|
+
Value cloneEmpty() const;
|
|
541
|
+
//! allocate new storage and copy in our values
|
|
542
|
+
Value clone() const;
|
|
543
|
+
//! copy value(s) from other.
|
|
544
|
+
//! Acts like from(o) for kind==Kind::Compound .
|
|
545
|
+
//! Acts like from(o.as<T>()) for kind!=Kind::Compound
|
|
546
|
+
Value& assign(const Value& o);
|
|
547
|
+
|
|
548
|
+
//! Use to allocate members for an array of Struct and array of Union
|
|
549
|
+
Value allocMember();
|
|
550
|
+
|
|
551
|
+
/** Restore to newly allocated state.
|
|
552
|
+
*
|
|
553
|
+
* Free any allocation for array or string values, zero numeric values.
|
|
554
|
+
* unmark() all fields.
|
|
555
|
+
*
|
|
556
|
+
* @since 1.1.0
|
|
557
|
+
*/
|
|
558
|
+
void clear();
|
|
559
|
+
|
|
560
|
+
//! Does this Value actually reference some underlying storage
|
|
561
|
+
inline bool valid() const { return desc; }
|
|
562
|
+
inline explicit operator bool() const { return desc; }
|
|
563
|
+
|
|
564
|
+
//! Test if this field is marked as valid/changed
|
|
565
|
+
bool isMarked(bool parents=true, bool children=false) const;
|
|
566
|
+
//! return *this if isMarked()==true, or a !valid() ref. if false.
|
|
567
|
+
Value ifMarked(bool parents=true, bool children=false) const;
|
|
568
|
+
//! Mark this field as valid/changed
|
|
569
|
+
void mark(bool v=true);
|
|
570
|
+
//! Remove mark from this field, and optionally parent and/or child fields.
|
|
571
|
+
//! \since 1.1.3 Correctly unmark parent fields
|
|
572
|
+
void unmark(bool parents=false, bool children=true);
|
|
573
|
+
|
|
574
|
+
//! Type of the referenced field (or Null)
|
|
575
|
+
TypeCode type() const;
|
|
576
|
+
//! Type of value stored in referenced field
|
|
577
|
+
StoreType storageType() const;
|
|
578
|
+
//! Type ID string (Struct or Union only)
|
|
579
|
+
const std::string& id() const;
|
|
580
|
+
//! Test prefix of Type ID string (Struct or Union only)
|
|
581
|
+
bool idStartsWith(const std::string& prefix) const;
|
|
582
|
+
|
|
583
|
+
private:
|
|
584
|
+
static
|
|
585
|
+
bool _equal(const impl::FieldDesc* A, const impl::FieldDesc* B);
|
|
586
|
+
public:
|
|
587
|
+
//! Test for instance equality. aka. this==this
|
|
588
|
+
inline bool equalInst(const Value& o) const { return store==o.store; }
|
|
589
|
+
//! Test for equality of type only (including field names)
|
|
590
|
+
inline bool equalType(const Value& o) const { return _equal(desc, o.desc); }
|
|
591
|
+
|
|
592
|
+
/** Return our name for a descendant field.
|
|
593
|
+
* @code
|
|
594
|
+
* Value v = ...;
|
|
595
|
+
* assert(v.nameOf(v["some.field"])=="some.field");
|
|
596
|
+
* @endcode
|
|
597
|
+
* @throws NoField unless both this and descendant are valid()
|
|
598
|
+
* @throws std::logic_error if descendant is not actually a descendant
|
|
599
|
+
*/
|
|
600
|
+
const std::string& nameOf(const Value& descendant) const;
|
|
601
|
+
|
|
602
|
+
// access to Value's ... value
|
|
603
|
+
// not for Struct
|
|
604
|
+
|
|
605
|
+
// use with caution
|
|
606
|
+
void copyOut(void *ptr, StoreType type) const;
|
|
607
|
+
bool tryCopyOut(void *ptr, StoreType type) const;
|
|
608
|
+
void copyIn(const void *ptr, StoreType type);
|
|
609
|
+
bool tryCopyIn(const void *ptr, StoreType type);
|
|
610
|
+
|
|
611
|
+
/** Extract from field.
|
|
612
|
+
*
|
|
613
|
+
* Type 'T' may be one of:
|
|
614
|
+
* - bool
|
|
615
|
+
* - uint8_t, uint16_t, uint32_t, uint64_t
|
|
616
|
+
* - int8_t, int16_t, int32_t, int64_t
|
|
617
|
+
* - float, double
|
|
618
|
+
* - std::string
|
|
619
|
+
* - Value
|
|
620
|
+
* - shared_array<const void>
|
|
621
|
+
* - An enum where the underlying type is one of the preceding (since 0.2.0).
|
|
622
|
+
*
|
|
623
|
+
* @throws NoField !this->valid()
|
|
624
|
+
* @throws NoConvert if the field value can not be coerced to type T
|
|
625
|
+
*/
|
|
626
|
+
template<typename T>
|
|
627
|
+
inline T as() const {
|
|
628
|
+
typename impl::StoreAs<T>::store_t ret;
|
|
629
|
+
copyOut(&ret, impl::StoreAs<T>::code);
|
|
630
|
+
return impl::StoreTransform<T>::out(ret);
|
|
631
|
+
}
|
|
632
|
+
|
|
633
|
+
//! Attempt to extract value from field.
|
|
634
|
+
//! @returns false if as<T>() would throw NoField or NoConvert
|
|
635
|
+
template<typename T>
|
|
636
|
+
inline bool as(T& val) const {
|
|
637
|
+
typename impl::StoreAs<T>::store_t temp;
|
|
638
|
+
auto ret = tryCopyOut(&temp, impl::StoreAs<T>::code);
|
|
639
|
+
if(ret) {
|
|
640
|
+
try {
|
|
641
|
+
val = impl::StoreTransform<T>::out(temp);
|
|
642
|
+
}catch(std::exception&){
|
|
643
|
+
ret = false;
|
|
644
|
+
}
|
|
645
|
+
}
|
|
646
|
+
return ret;
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
//! Attempt to extract value from field.
|
|
650
|
+
//! If possible, this value is cast to T and passed as the only argument
|
|
651
|
+
//! of the provided function.
|
|
652
|
+
template<typename T, typename FN>
|
|
653
|
+
typename impl::StorageMap<typename std::decay<FN>::type>::not_storable as(FN&& fn) const {
|
|
654
|
+
typename impl::StoreAs<T>::store_t val;
|
|
655
|
+
if(tryCopyOut(&val, impl::StoreAs<T>::code)) {
|
|
656
|
+
fn(impl::StoreTransform<T>::out(val));
|
|
657
|
+
}
|
|
658
|
+
}
|
|
659
|
+
|
|
660
|
+
//! Attempt to assign to field.
|
|
661
|
+
//! @returns false if from<T>() would throw NoField or NoConvert
|
|
662
|
+
template<typename T>
|
|
663
|
+
inline bool tryFrom(const T& val) {
|
|
664
|
+
const typename impl::StoreAs<T>::store_t& norm(impl::StoreTransform<T>::in(val));
|
|
665
|
+
return tryCopyIn(&norm, impl::StoreAs<T>::code);
|
|
666
|
+
}
|
|
667
|
+
|
|
668
|
+
/** Assign from field.
|
|
669
|
+
*
|
|
670
|
+
* Type 'T' may be one of:
|
|
671
|
+
* - bool
|
|
672
|
+
* - uint8_t, uint16_t, uint32_t, uint64_t
|
|
673
|
+
* - int8_t, int16_t, int32_t, int64_t
|
|
674
|
+
* - float, double
|
|
675
|
+
* - std::string
|
|
676
|
+
* - Value
|
|
677
|
+
* - shared_array<const void>
|
|
678
|
+
* - An enum where the underlying type is one of the preceding (since 0.2.0).
|
|
679
|
+
*/
|
|
680
|
+
template<typename T>
|
|
681
|
+
void from(const T& val) {
|
|
682
|
+
const typename impl::StoreAs<T>::store_t& norm(impl::StoreTransform<T>::in(val));
|
|
683
|
+
copyIn(&norm, impl::StoreAs<T>::code);
|
|
684
|
+
}
|
|
685
|
+
|
|
686
|
+
//! Inline assignment of sub-field.
|
|
687
|
+
//! Shorthand for @code (*this)[key].from(val) @endcode
|
|
688
|
+
template<typename T, typename K>
|
|
689
|
+
Value& update(K key, const T& val) {
|
|
690
|
+
(*this)[key].from(val);
|
|
691
|
+
return *this;
|
|
692
|
+
}
|
|
693
|
+
|
|
694
|
+
//! shorthand for from<T>(const T&) except for T=Value (would be ambiguous with ref. assignment)
|
|
695
|
+
template<typename T>
|
|
696
|
+
#ifdef _DOXYGEN_
|
|
697
|
+
Value&
|
|
698
|
+
#else
|
|
699
|
+
typename std::enable_if<!std::is_same<T,Value>::value, Value&>::type
|
|
700
|
+
#endif
|
|
701
|
+
operator=(const T& val) {
|
|
702
|
+
from<T>(val);
|
|
703
|
+
return *this;
|
|
704
|
+
}
|
|
705
|
+
|
|
706
|
+
// Struct/Union access
|
|
707
|
+
private:
|
|
708
|
+
void traverse(const std::string& expr, bool modify, bool dothrow);
|
|
709
|
+
public:
|
|
710
|
+
|
|
711
|
+
/** Attempt to access a descendant field.
|
|
712
|
+
*
|
|
713
|
+
* Argument may be:
|
|
714
|
+
* * name of a child field. eg. "value"
|
|
715
|
+
* * name of a descendant field. eg "alarm.severity"
|
|
716
|
+
* * element of an array of structures. eg "dimension[0]"
|
|
717
|
+
* * name of a union field. eg. "->booleanValue"
|
|
718
|
+
*
|
|
719
|
+
* These may be composed. eg.
|
|
720
|
+
*
|
|
721
|
+
* * "dimension[0]size"
|
|
722
|
+
* * "value->booleanValue"
|
|
723
|
+
*
|
|
724
|
+
* @returns A valid() Value if the descendant field exists, otherwise an invalid Value.
|
|
725
|
+
*/
|
|
726
|
+
Value operator[](const std::string& name);
|
|
727
|
+
const Value operator[](const std::string& name) const;
|
|
728
|
+
|
|
729
|
+
/** Attempt to access a descendant field, or throw exception.
|
|
730
|
+
*
|
|
731
|
+
* Acts like operator[] on success, but throws a (hopefully descriptive)
|
|
732
|
+
* exception instead of returning an invalid Value.
|
|
733
|
+
*
|
|
734
|
+
* @throws LookupError If the lookup can not be satisfied
|
|
735
|
+
* @throws NoField If this Value is empty
|
|
736
|
+
* @since 1.1.2 An empty Value correctly throws NoField instead of returning an empty Value
|
|
737
|
+
*/
|
|
738
|
+
Value lookup(const std::string& name);
|
|
739
|
+
const Value lookup(const std::string& name) const;
|
|
740
|
+
|
|
741
|
+
//! Number of child fields.
|
|
742
|
+
//! Only Struct, StructA, Union, UnionA return non-zero
|
|
743
|
+
//! \since 1.1.3 correctly return non-zero for StructA and UnionA
|
|
744
|
+
size_t nmembers() const;
|
|
745
|
+
|
|
746
|
+
struct _IAll {};
|
|
747
|
+
struct _IChildren {};
|
|
748
|
+
struct _IMarked {
|
|
749
|
+
size_t nextcheck=0u;
|
|
750
|
+
};
|
|
751
|
+
private:
|
|
752
|
+
template<typename T>
|
|
753
|
+
struct _Iterator;
|
|
754
|
+
template<typename T>
|
|
755
|
+
friend struct _Iterator;
|
|
756
|
+
public:
|
|
757
|
+
template<typename T>
|
|
758
|
+
struct Iterable;
|
|
759
|
+
template<typename T>
|
|
760
|
+
friend struct Iterable;
|
|
761
|
+
|
|
762
|
+
typedef Iterable<_IAll> IAll;
|
|
763
|
+
typedef Iterable<_IChildren> IChildren;
|
|
764
|
+
typedef Iterable<_IMarked> IMarked;
|
|
765
|
+
|
|
766
|
+
/** Depth-first iteration of all descendant fields
|
|
767
|
+
*
|
|
768
|
+
* @code
|
|
769
|
+
* Value top(...);
|
|
770
|
+
* for(auto fld : top.iall()) {
|
|
771
|
+
* std::cout<<top.nameOf(fld)<<" = "<<fld<<"\n";
|
|
772
|
+
* }
|
|
773
|
+
* @endcode
|
|
774
|
+
*/
|
|
775
|
+
inline
|
|
776
|
+
IAll iall() const noexcept;
|
|
777
|
+
//! iteration of all child fields
|
|
778
|
+
inline
|
|
779
|
+
IChildren ichildren() const noexcept;
|
|
780
|
+
//! Depth-first iteration of all marked descendant fields
|
|
781
|
+
inline
|
|
782
|
+
IMarked imarked() const noexcept;
|
|
783
|
+
|
|
784
|
+
//! Provides options to control printing of a Value via std::ostream.
|
|
785
|
+
struct Fmt {
|
|
786
|
+
const Value* top = nullptr;
|
|
787
|
+
size_t _limit=0u;
|
|
788
|
+
enum format_t {
|
|
789
|
+
Tree,
|
|
790
|
+
Delta,
|
|
791
|
+
} _format = Tree;
|
|
792
|
+
bool _showValue = true;
|
|
793
|
+
|
|
794
|
+
Fmt(const Value* top) :top(top) {}
|
|
795
|
+
//! Show Value in tree/struct format
|
|
796
|
+
Fmt& tree() { _format = Tree; return *this; }
|
|
797
|
+
//! Show Value in delta format
|
|
798
|
+
Fmt& delta() { _format = Delta ; return *this; }
|
|
799
|
+
//! Explicitly select format_t
|
|
800
|
+
Fmt& format(format_t f) { _format = f ; return *this; }
|
|
801
|
+
//! Whether to show field values, or only type information
|
|
802
|
+
Fmt& showValue(bool v) { _showValue = v; return *this; }
|
|
803
|
+
//! When non-zero, arrays output will be truncated with "..." after cnt elements.
|
|
804
|
+
Fmt& arrayLimit(size_t cnt) { _limit = cnt; return *this; }
|
|
805
|
+
};
|
|
806
|
+
/** Configurable printing via std::ostream
|
|
807
|
+
*
|
|
808
|
+
* @code
|
|
809
|
+
* Value val;
|
|
810
|
+
* std::cout<<val.format().arrayLimit(10);
|
|
811
|
+
* @endcode
|
|
812
|
+
*/
|
|
813
|
+
inline Fmt format() const { return Fmt(this); }
|
|
814
|
+
};
|
|
815
|
+
|
|
816
|
+
template<typename T>
|
|
817
|
+
struct Value::_Iterator : private T
|
|
818
|
+
{
|
|
819
|
+
private:
|
|
820
|
+
Value val;
|
|
821
|
+
size_t pos = 0u;
|
|
822
|
+
friend class Value;
|
|
823
|
+
friend struct Iterable<T>;
|
|
824
|
+
constexpr _Iterator(const Value& val, size_t pos) : val(val), pos(pos) {}
|
|
825
|
+
public:
|
|
826
|
+
_Iterator() = default;
|
|
827
|
+
Value operator*() const noexcept; // specialized per- _IterKind
|
|
828
|
+
_Iterator& operator++() noexcept; // specialized per- _IterKind
|
|
829
|
+
_Iterator operator++(int) noexcept {
|
|
830
|
+
_Iterator ret(*this);
|
|
831
|
+
++(*this);
|
|
832
|
+
return ret;
|
|
833
|
+
}
|
|
834
|
+
inline bool operator==(const _Iterator& o) const noexcept { return pos==o.pos; }
|
|
835
|
+
inline bool operator!=(const _Iterator& o) const noexcept { return pos!=o.pos; }
|
|
836
|
+
};
|
|
837
|
+
|
|
838
|
+
template<typename T>
|
|
839
|
+
struct Value::Iterable
|
|
840
|
+
{
|
|
841
|
+
private:
|
|
842
|
+
Value val;
|
|
843
|
+
friend class Value;
|
|
844
|
+
public:
|
|
845
|
+
Iterable() = default;
|
|
846
|
+
explicit Iterable(const Value* val) :val(*val) {}
|
|
847
|
+
typedef _Iterator<T> iterator;
|
|
848
|
+
iterator begin() const noexcept; // specialized per- _IterKind
|
|
849
|
+
iterator end() const noexcept; // specialized per- _IterKind
|
|
850
|
+
};
|
|
851
|
+
|
|
852
|
+
template<>
|
|
853
|
+
inline
|
|
854
|
+
Value::Iterable<Value::_IAll>::iterator
|
|
855
|
+
Value::Iterable<Value::_IAll>::begin() const noexcept {
|
|
856
|
+
return iterator(val, 0u); // always start pos==0
|
|
857
|
+
}
|
|
858
|
+
|
|
859
|
+
template<>
|
|
860
|
+
PVXS_API
|
|
861
|
+
Value::Iterable<Value::_IAll>::iterator
|
|
862
|
+
Value::Iterable<Value::_IAll>::end() const noexcept;
|
|
863
|
+
|
|
864
|
+
template<>
|
|
865
|
+
PVXS_API
|
|
866
|
+
Value
|
|
867
|
+
Value::_Iterator<Value::_IAll>::operator*() const noexcept;
|
|
868
|
+
|
|
869
|
+
template<>
|
|
870
|
+
inline
|
|
871
|
+
Value::_Iterator<Value::_IAll>&
|
|
872
|
+
Value::_Iterator<Value::_IAll>::operator++() noexcept {
|
|
873
|
+
pos++;
|
|
874
|
+
return *this;
|
|
875
|
+
}
|
|
876
|
+
|
|
877
|
+
template<>
|
|
878
|
+
inline
|
|
879
|
+
Value::Iterable<Value::_IChildren>::iterator
|
|
880
|
+
Value::Iterable<Value::_IChildren>::begin() const noexcept {
|
|
881
|
+
return iterator(val, 0u); // always start pos==0
|
|
882
|
+
}
|
|
883
|
+
|
|
884
|
+
template<>
|
|
885
|
+
PVXS_API
|
|
886
|
+
Value::Iterable<Value::_IChildren>::iterator
|
|
887
|
+
Value::Iterable<Value::_IChildren>::end() const noexcept;
|
|
888
|
+
|
|
889
|
+
template<>
|
|
890
|
+
PVXS_API
|
|
891
|
+
Value
|
|
892
|
+
Value::_Iterator<Value::_IChildren>::operator*() const noexcept;
|
|
893
|
+
|
|
894
|
+
template<>
|
|
895
|
+
inline
|
|
896
|
+
Value::_Iterator<Value::_IChildren>&
|
|
897
|
+
Value::_Iterator<Value::_IChildren>::operator++() noexcept {
|
|
898
|
+
pos++;
|
|
899
|
+
return *this;
|
|
900
|
+
}
|
|
901
|
+
|
|
902
|
+
template<>
|
|
903
|
+
PVXS_API
|
|
904
|
+
Value::Iterable<Value::_IMarked>::iterator
|
|
905
|
+
Value::Iterable<Value::_IMarked>::begin() const noexcept;
|
|
906
|
+
|
|
907
|
+
template<>
|
|
908
|
+
PVXS_API
|
|
909
|
+
Value::Iterable<Value::_IMarked>::iterator
|
|
910
|
+
Value::Iterable<Value::_IMarked>::end() const noexcept;
|
|
911
|
+
|
|
912
|
+
template<>
|
|
913
|
+
PVXS_API
|
|
914
|
+
Value
|
|
915
|
+
Value::_Iterator<Value::_IMarked>::operator*() const noexcept;
|
|
916
|
+
|
|
917
|
+
template<>
|
|
918
|
+
PVXS_API
|
|
919
|
+
Value::_Iterator<Value::_IMarked>&
|
|
920
|
+
Value::_Iterator<Value::_IMarked>::operator++() noexcept;
|
|
921
|
+
|
|
922
|
+
Value::Iterable<Value::_IAll>
|
|
923
|
+
Value::iall() const noexcept {
|
|
924
|
+
return Iterable<Value::_IAll>{this};
|
|
925
|
+
}
|
|
926
|
+
|
|
927
|
+
Value::Iterable<Value::_IChildren>
|
|
928
|
+
Value::ichildren() const noexcept {
|
|
929
|
+
return Iterable<Value::_IChildren>{this};
|
|
930
|
+
}
|
|
931
|
+
|
|
932
|
+
Value::Iterable<Value::_IMarked>
|
|
933
|
+
Value::imarked() const noexcept {
|
|
934
|
+
return Iterable<Value::_IMarked>{this};
|
|
935
|
+
}
|
|
936
|
+
|
|
937
|
+
PVXS_API
|
|
938
|
+
std::ostream& operator<<(std::ostream& strm, const Value::Fmt& fmt);
|
|
939
|
+
|
|
940
|
+
inline
|
|
941
|
+
std::ostream& operator<<(std::ostream& strm, const Value& val)
|
|
942
|
+
{
|
|
943
|
+
return strm<<val.format();
|
|
944
|
+
}
|
|
945
|
+
|
|
946
|
+
} // namespace pvxs
|
|
947
|
+
|
|
948
|
+
#endif // PVXS_DATA_H
|