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.
Files changed (40) hide show
  1. pvxslibs/__init__.py +0 -0
  2. pvxslibs/dbd/pvxsIoc.dbd +8 -0
  3. pvxslibs/include/pvxs/client.h +1094 -0
  4. pvxslibs/include/pvxs/data.h +948 -0
  5. pvxslibs/include/pvxs/iochooks.h +170 -0
  6. pvxslibs/include/pvxs/log.h +148 -0
  7. pvxslibs/include/pvxs/netcommon.h +82 -0
  8. pvxslibs/include/pvxs/nt.h +208 -0
  9. pvxslibs/include/pvxs/server.h +238 -0
  10. pvxslibs/include/pvxs/sharedArray.h +748 -0
  11. pvxslibs/include/pvxs/sharedpv.h +121 -0
  12. pvxslibs/include/pvxs/source.h +290 -0
  13. pvxslibs/include/pvxs/srvcommon.h +148 -0
  14. pvxslibs/include/pvxs/unittest.h +327 -0
  15. pvxslibs/include/pvxs/util.h +354 -0
  16. pvxslibs/include/pvxs/version.h +97 -0
  17. pvxslibs/include/pvxs/versionNum.h +6 -0
  18. pvxslibs/ioc.py +10 -0
  19. pvxslibs/lib/__init__.py +0 -0
  20. pvxslibs/lib/event_core_dsoinfo.py +14 -0
  21. pvxslibs/lib/event_pthread_dsoinfo.py +14 -0
  22. pvxslibs/lib/libevent_core.so +0 -0
  23. pvxslibs/lib/libevent_core.so.2.2.0 +0 -0
  24. pvxslibs/lib/libevent_pthread.so +0 -0
  25. pvxslibs/lib/libevent_pthread.so.2.2.0 +0 -0
  26. pvxslibs/lib/libpvxs.so +0 -0
  27. pvxslibs/lib/libpvxs.so.1.5 +0 -0
  28. pvxslibs/lib/libpvxsIoc.so +0 -0
  29. pvxslibs/lib/libpvxsIoc.so.1.5 +0 -0
  30. pvxslibs/lib/pvxsIoc_dsoinfo.py +14 -0
  31. pvxslibs/lib/pvxs_dsoinfo.py +14 -0
  32. pvxslibs/path.py +12 -0
  33. pvxslibs/test/__init__.py +0 -0
  34. pvxslibs/test/test_load.py +30 -0
  35. pvxslibs/version.py +32 -0
  36. pvxslibs-1.5.0.dist-info/METADATA +44 -0
  37. pvxslibs-1.5.0.dist-info/RECORD +40 -0
  38. pvxslibs-1.5.0.dist-info/WHEEL +5 -0
  39. pvxslibs-1.5.0.dist-info/licenses/LICENSE +26 -0
  40. 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