/** * Copyright - See the COPYRIGHT that is included with this distribution. * pvxs is distributed subject to a Software License Agreement found * in file LICENSE that is included with this distribution. */ #ifndef DATAIMPL_H #define DATAIMPL_H #include #include #include #include #include "bitmask.h" #include "utilpvt.h" namespace pvxs { struct Value::Helper { // internal access to private operations static inline Value build(const std::shared_ptr& desc) { return Value(desc); } static inline Value build(const std::shared_ptr& desc, Value& parent) { return Value(desc, parent); } static inline Value build(const std::shared_ptr& desc, const std::shared_ptr& pstore, const impl::FieldDesc* pdesc); static Value build(const void* ptr, StoreType type); static inline std::shared_ptr& store( Value& v) { return v.store; } static inline std::shared_ptr store(const Value& v) { return v.store; } static constexpr const FieldDesc* desc(const Value& v) { return v.desc; } static inline void set_desc(Value& v, const FieldDesc* desc) { v.desc = desc; } static inline impl::FieldStorage* store_ptr( Value& v) { return v.store.get(); } static inline const impl::FieldStorage* store_ptr(const Value& v) { return v.store.get(); } static std::shared_ptr type(const Value& v); }; namespace impl { struct Buffer; /** Describes a single field, leaf or otherwise, in a nested structure. * * FieldDesc are always stored depth first as a contiguous array, * with offset to descendant fields given as positive integers relative * to the current field. (not possible to jump _back_) * * We deal with indices in this FieldDesc array. found in FieldDesc::mlookup * and FieldDesc::miter Relative to current position in FieldDesc array. (aka this+n) */ struct FieldDesc { // type ID string (Struct/Union) std::string id; // Lookup of all descendant fields of this Structure or Union. // "fld.sub.leaf" -> rel index // For Struct, relative to this (always >=1) // For Union, offset in members array (one entry will always be zero) std::map mlookup; // child iteration. child# -> ("sub", rel index in enclosing vector) std::vector> miter; // number of FieldDesc nodes between this node and it's a parent Struct (or 0 if no parent). // This value also appears in the parent's miter and mlookup mappings. // Only usable when a StructTop is accessible and this!=StructTop::desc size_t parent_index=0; // For Union, UnionA, StructA // For Union, the choices concatenated together (members.size() != #choices) // For UnionA/StructA containing a single Union/Struct std::vector members; const TypeCode code{TypeCode::Null}; explicit FieldDesc(TypeCode code) :code{code} {} // number of FieldDesc nodes which describe this node. Inclusive. always size()>=1 inline size_t size() const { return 1u + (members.empty() ? mlookup.size() : 0u); } }; PVXS_API void to_wire(Buffer& buf, const FieldDesc* cur); typedef std::map> TypeStore; PVXS_API void from_wire(Buffer& buf, std::vector& descs, TypeStore& cache, unsigned depth=0); struct StructTop; struct FieldStorage { /* Storage for field value. depends on StoreType. * * All array types stored as shared_array which includes full type info * Integers promoted to either int64_t or uint64_t. * Bool promoted to uint64_t * Reals promoted to double. * String stored as std::string * Compound (Struct, Union, Any) stored as Value */ aligned_union<8, double, // Real uint64_t, // Bool, Integer std::string, // String Value, // Union, Any shared_array // array of POD, std::string, or std::shared_ptr >::type store; // index of this field in StructTop::members StructTop *top; bool valid=false; StoreType code=StoreType::Null; void init(StoreType code); void deinit(); ~FieldStorage(); size_t index() const; template T& as() { return *reinterpret_cast(&store); } template const T& as() const { return *reinterpret_cast(&store); } inline uint8_t* buffer() { return reinterpret_cast(&store); } inline const uint8_t* buffer() const { return reinterpret_cast(&store); } }; // hidden (publicly) management of an allocated Struct struct StructTop { // type of first top level struct. always !NULL. // Actually the first element of a vector std::shared_ptr desc; // our members (inclusive). always size()>=1 std::vector members; // empty, or the field of a structure which encloses this. std::weak_ptr enclosing; INST_COUNTER(StructTop); }; using Type = std::shared_ptr; //! serialize all Value fields PVXS_API void to_wire_full(Buffer& buf, const Value& val); //! serialize BitMask and marked valid Value fields PVXS_API void to_wire_valid(Buffer& buf, const Value& val, const BitMask* mask=nullptr); //! deserialize type description PVXS_API void from_wire_type(Buffer& buf, TypeStore& ctxt, Value& val); //! deserialize full Value PVXS_API void from_wire_full(Buffer& buf, TypeStore& ctxt, Value& val); //! deserialize BitMask and partial Value PVXS_API void from_wire_valid(Buffer& buf, TypeStore& ctxt, Value& val); //! deserialize type description and full value (a la. pvRequest) PVXS_API void from_wire_type_value(Buffer& buf, TypeStore& ctxt, Value& val); PVXS_API std::ostream& operator<<(std::ostream& strm, const FieldDesc* desc); } // namespace impl Value Value::Helper::build(const std::shared_ptr& desc, const std::shared_ptr& pstore, const impl::FieldDesc* pdesc) { Value ret(desc); auto& enc = ret.store->top->enclosing; enc = pstore; return ret; } } // namespace pvxs #endif // DATAIMPL_H