Value Container API¶
#include <pvxs/data.h>
namespace pvxs { ... }
pvxs::Value
is the primary data container type used with PVXS.
A pvxs::Value
may be obtained via the remote peer (client or server),
or created locally. See ntapi
or typedefapi
.
pvxs::Value
is a safe pointer-like object which, maybe, references
a node in a tree of sub-structures and leaf fields.
This tree will be referred to as a Structure as it behaves
in many ways like a C ‘struct’.
For example, the following code:
Value top = TypeDef(TypeCode::Struct, {
members::Int32("fldname"),
}).create();
top["fldname"] = 1;
fld = top["fldname"];
fld = 2;
Is analogous to the following pseudo code.
// pseudo-code
struct anon {
int32_t fldname=0u;
};
void* top = new anon;
static_cast<anon*>(top)->fldname = 1;
void* fld = &static_cast<anon*>(top)->fldname;
static_cast<int32_t*>(fld) = 2;
With the chief functional difference being that the analogs of the casts are made safe. Also, the storage of the underlying Structure will be free’d when no more Values reference it.
A Value which does not reference any underlying Structure is not valid, or “empty”.
Value dummy;
assert(!dummy.valid());
assert(!dummy); // operator bool() is an alias for valid()
An invalid Value may be returned on error by some methods. All operations on an invalid Value should be safe and well defined.
Value top(nt::NTScalar{TypeCode::Int32}.create());
int32_t val = top["nonexistent"].as<int32_t>();
In this example, the operator[] lookup of a non-existent field returns an invalid Value.
Attempting to extract an integer from this will then throw a pvxs::NoField
exception.
Value¶
Field Lookup¶
Access to members of structured types is accomplished through pvxs::Value::operator[]()
or pvxs::Value::lookup()
.
These two methods differ in how errors are communicated.
operator[] will return an “invalid” or “empty” Value if the expression does not address a member.
lookup() will throw an exception describing where and how expression evaluation failed.
Iteration¶
pvxs::Value
instances pointing to a non-array structured data field (Struct or Union)
may be iterated. Iteration comes in three variations: pvxs::Value::iall()
, pvxs::Value::ichildren()
,
and pvxs::Value::imarked()
.
For a Struct, iall() is a depth first traversal of all fields.
ichildren() traverses all child fields (excluding eg. grandchildren
and further). imarked() considers all fields, but only visits
those which have beem marked (pvxs::Value::isMarked()
).
For a Union. iall() and ichildren() are identical, and will visit all possible Union members, excluding the implicit NULL member. Traversal does not effect member selection. imarked() for a Union will visit at most one member (if one is selected)>
Iteration of Union may return Value instances allocated with temporary storage. Changes to these instances will not effect the underlying structure.
Iteration of other field types, including StructA and UnionA is not implemented at this time, and will always appear as empty.
-
class Value¶
Generic data container
References a single data field, which may be free-standing (eg. “int x = 5;”) or a member of an enclosing Struct, or an element in an array of Struct.
Use valid() (or operator bool() ) to determine if pointed to a valid field.
Use operator[] to traverse within a Kind::Compound field.
Value val = nt::NTScalar{TypeCode::Int32}.create(); val["value"] = 42; Value alias = val; assert(alias["value"].as<int32_t>()==42); // 'alias' is a second reference to the same Struct
Public Functions
-
Value &assign(const Value &o)¶
copy value(s) from other. Acts like from(o) for kind==Kind::Compound . Acts like from(o.as<T>()) for kind!=Kind::Compound
-
void clear()¶
Restore to newly allocated state.
Free any allocation for array or string values, zero numeric values. unmark() all fields.
- Since
1.1.0
-
bool isMarked(bool parents = true, bool children = false) const¶
Test if this field is marked as valid/changed.
-
Value ifMarked(bool parents = true, bool children = false) const¶
return *this if isMarked()==true, or a !valid() ref. if false.
-
void mark(bool v = true)¶
Mark this field as valid/changed.
-
void unmark(bool parents = false, bool children = true)¶
Remove mark from this field, and optionally parent and/or child fields.
- Since
1.1.3 Correctly unmark parent fields
-
StoreType storageType() const¶
Type of value stored in referenced field.
-
const std::string &id() const¶
Type ID string (Struct or Union only)
-
bool idStartsWith(const std::string &prefix) const¶
Test prefix of Type ID string (Struct or Union only)
-
const std::string &nameOf(const Value &descendant) const¶
Return our name for a descendant field.
Value v = ...; assert(v.nameOf(v["some.field"])=="some.field");
-
template<typename T>
inline T as() const¶ Extract from field.
Type ‘T’ may be one of:
bool
uint8_t, uint16_t, uint32_t, uint64_t
int8_t, int16_t, int32_t, int64_t
float, double
std::string
shared_array<const void>
An enum where the underlying type is one of the preceding (since 0.2.0).
-
template<typename T, typename FN>
inline impl::StorageMap<typenamestd::decay<FN>::type>::not_storable as(FN &&fn) const¶ Attempt to extract value from field. If possible, this value is cast to T and passed as the only argument of the provided function.
-
template<typename T>
inline void from(const T &val)¶ Assign from field.
Type ‘T’ may be one of:
bool
uint8_t, uint16_t, uint32_t, uint64_t
int8_t, int16_t, int32_t, int64_t
float, double
std::string
shared_array<const void>
An enum where the underlying type is one of the preceding (since 0.2.0).
-
template<typename T, typename K>
inline Value &update(K key, const T &val)¶ Inline assignment of sub-field. Shorthand for
(*this)[key].from(val)
-
template<typename T>
inline Value &operator=(const T &val)¶ shorthand for from<T>(const T&) except for T=Value (would be ambiguous with ref. assignment)
-
Value operator[](const std::string &name)¶
Attempt to access a descendant field.
Argument may be:
name of a child field. eg. “value”
name of a descendant field. eg “alarm.severity”
element of an array of structures. eg “dimension[0]”
name of a union field. eg. “->booleanValue”
These may be composed. eg.
“dimension[0]size”
”value->booleanValue”
-
Value lookup(const std::string &name)¶
Attempt to access a descendant field, or throw exception.
Acts like operator[] on success, but throws a (hopefully descriptive) exception instead of returning an invalid Value.
- Throws:
LookupError – If the lookup can not be satisfied
-
size_t nmembers() const¶
Number of child fields. only Struct, StructA, Union, UnionA return non-zero
- Since
1.1.3 correctly return non-zero for StructA and UnionA
-
inline IAll iall() const noexcept¶
Depth-first iteration of all descendant fields
Value top(...); for(auto fld : top.iall()) { std::cout<<top.nameOf(fld)<<" = "<<fld<<"\n"; }
-
inline IChildren ichildren() const noexcept¶
iteration of all child fields
-
inline IMarked imarked() const noexcept¶
Depth-first iteration of all marked descendant fields.
-
struct _IAll¶
-
struct _IChildren¶
-
struct _IMarked¶
-
template<typename T>
struct Iterable¶
-
struct NoConvert : public std::runtime_error¶
Thrown when a Value can not be converted to the requested type.
-
struct LookupError : public std::runtime_error¶
Array fields¶
Array fields are represented with the pvxs::shared_array
container
using void vs. non-void, and const vs. non-const element types.
Arrays are initially created as non-const and non-void.
After being populated, an array must be transformed using
pvxs::shared_array::freeze()
to become const before
being stored in a pvxs::Value
.
shared_array<double> arr({1.0, 2.0});
Value top = nt::NTScalar{TypeCode::Float64A}.create();
top["value"] = arr.freeze();
# freeze() acts like std::move(). arr is now empty
# only the read-only reference remains!
The pvxs::shared_array::freeze()
method is special in that it
acts like std::move() in that it moves the array reference into the returned object.
freeze() requires exclusive ownership of the reference being frozen.
An exception will be thrown unless pvxs::shared_array::unique()
would return true.
Array values may be extracted from pvxs::Value
as either const void or const non-void.
The const non-void option is a convenience which may allocate and do an element by element conversion.
# extract reference, or converted copy
arr = top["value"].as<shared_array<const double>>();
When it is desirable to avoid an implicit allocate and convert,
an array can be extracted as “const void”.
This does require calling pvxs::shared_array::original_type()
to find the pvxs::ArrayType
of the underlying array prior to using pvxs::shared_array::castTo()
.
# extract untyped reference. Never copies
shared_array<const void> varr = top["value"].as<shared_array<const void>>();
if(varr.original_type()==ArrayType::Float64) {
# castTo() throws std::logic_error if the underlying type is not 'double'.
shared_array<const double> temp = varr.castTo<const double>();
}
std::vector-like contiguous array of items passed by reference.
shared_array comes in const and non-const, as well as void and non-void variants.
A non-const array is allocated and filled, then last non-const reference is exchanged for new const reference. This const reference can then be safely shared between various threads.
shared_array<uint32_t> arr({1, 2, 3}); assert(arr.size()==3); shared_ptr<const uint32_t> constarr(arr.freeze()); assert(arr.size()==0); assert(constarr.size()==3);
The void / non-void variants allow arrays to be moved without explicit typing. However, the void variant preserves the original ArrayType.
shared_array<uint32_t> arr({1, 2, 3}); assert(arr.size()==3); shared_array<void> voidarr(arr.castTo<void>()); assert(arr.size()==0); assert(voidarr.size()==3); // void size() in elements
Public Functions
allocate new array and populate from initializer list
Construct a copy of another a sequence. Requires random access iterators.
Allocate (with new[]) a new vector of size c.
Allocate (with new[]) a new vector of size c and fill with value e.
use existing alloc with delete[]
use existing alloc w/ custom deletor
build around existing shared_ptr
alias existing shared_array
Number of elements.
size()==0
True if this instance is the only (strong) reference.
Reset size()==0.
Exchange contents with other.
Access to raw pointer. May be nullptr if size()==0
Extend size. Implies make_unique().
- Post:
unique()==true
Ensure exclusive ownership of array data by making a copy if necessary.
- Post:
unique()==true
begin iteration
end iteration
Cast to const, consuming this
Return non-const (maybe) copy. consuming this
If
unique(), transforms this reference into the returned const reference. If not unique(), returns a copy and clears this reference. In either case, the returned reference will be unique().- Since
1.1.2
- Post:
empty()==true
Cast to/from void, preserving const-ness.
A “safe” version of static_cast<>()
Allowed casts depend upon two aspects of type parameter E.
Whether the base type is void or non-void. And whether or not the const qualifier is present.
Type E may always be cast to itself.
Casts must preserve const-ness. Either both of E and TO, or neither, must be const qualified.
At most one of E or TO may have different non-void base type.
- Throws:
std::logic_error – on void -> non-void cast when requested type and the original_type() do not match.
Cast with fallback to copy. Preserves const-ness
Return either a reference or a copy of this array. A copy will be made if the requested type and the original_type() do not match. Otherwise functions like castTo().
Provide options when rendering with std::ostream.
shared_array<int32_t> arr({1,2,3,4}); // print entire array // {4}[1,2,3,4] std::cout<<arr; // print at most 3 elements // {4}[1,2,3,...] std::cout<<arr.format().limit(3);
return type of underlying array. (void only)
-
size_t pvxs::elementSize(ArrayType type)¶
Return storage size (aka. sizeof() ) for array element type
- Throws:
std::logic_error – for invalid types.
-
class Limiter¶
Provide options when rendering with std::ostream.
-
enum class pvxs::ArrayType : uint8_t¶
Identify real array type in void specializations of shared_array.
See also
Values:
-
enumerator Null¶
Untyped.
-
enumerator Bool¶
bool
-
enumerator Int8¶
int8_t
-
enumerator Int16¶
int16_t
-
enumerator Int32¶
int32_t
-
enumerator Int64¶
int64_t
-
enumerator UInt8¶
uint8_t
-
enumerator UInt16¶
uint16_t
-
enumerator UInt32¶
uint32_t
-
enumerator UInt64¶
uint64_t
-
enumerator Float32¶
float
-
enumerator Float64¶
double
-
enumerator String¶
std::string
-
enumerator Null¶