diff --git a/documentation/value.rst b/documentation/value.rst index ef09be2..fcd0bad 100644 --- a/documentation/value.rst +++ b/documentation/value.rst @@ -120,9 +120,16 @@ Array fields ------------ Array fields are represented with the `pvxs::shared_array` container -using void vs. non-void, and const vs. non-const element types. +using void vs. non-void, and const vs. mutable element types. -Arrays are initially created as non-const and non-void. +.. code-block:: c++ + + shared_array typed_mutable; + shared_array typed_const; + shared_array void_mutable; + shared_array void_const; + +Arrays may be initially created as mutable 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`. @@ -133,8 +140,8 @@ being stored in a `pvxs::Value`. 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! + // 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. @@ -146,7 +153,7 @@ The const non-void option is a convenience which may **allocate** and do an elem .. code-block:: c++ - # extract reference, or converted copy + // extract reference, or converted copy arr = top["value"].as>(); When it is desirable to avoid an implicit allocate and convert, @@ -156,10 +163,10 @@ of the underlying array prior to using `pvxs::shared_array::castTo`. .. code-block:: c++ - # extract untyped reference. Never copies + // extract untyped reference. Never copies shared_array varr = top["value"].as>(); if(varr.original_type()==ArrayType::Float64) { - # castTo() throws std::logic_error if the underlying type is not 'double'. + // castTo() throws std::logic_error if the underlying type is not 'double'. shared_array temp = varr.castTo(); } diff --git a/src/pvxs/sharedArray.h b/src/pvxs/sharedArray.h index 0c85c07..a7d6f3c 100644 --- a/src/pvxs/sharedArray.h +++ b/src/pvxs/sharedArray.h @@ -209,6 +209,8 @@ shared_array copyAs(ArrayType dtype, ArrayType stype, const void *sbase, s } // namespace detail /** std::vector-like contiguous array of items passed by reference. + * + * Somewhat analogous to ``std::shared_ptr>``. * * shared_array comes in const and non-const, as well as void and non-void variants. * @@ -257,9 +259,18 @@ public: typedef E element_type; + //! Pointer to no array. + //! @post size()==0 constexpr shared_array() noexcept :base_t() {} - //! allocate new array and populate from initializer list + /** Allocate new array and populate from initializer list. + * + * @code + * shared_array arr({1,2,3}); + * @endcode + * + * @post size()==L.size() + */ template shared_array(std::initializer_list L) :base_t(new _E_non_const[L.size()], L.size()) @@ -268,8 +279,16 @@ public: std::copy(L.begin(), L.end(), raw); } - //! Construct a copy of another a sequence. - //! Requires random access iterators. + /** Construct a copy of a sequence or range of random access iterators. + * + * @code + * special_vectorish X(...); + * shared_array Y(X.begin(), X.end()); + * + * uint32_t cvals[] = {1,2,3,4}; + * shared_array Z(cvals, cvals + NELEMENTS(cvals)); + * @endcode + */ template::difference_type=0> shared_array(Iter begin, Iter end) :shared_array(std::distance(begin, end)) @@ -277,12 +296,12 @@ public: std::copy(begin, end, const_cast<_E_non_const*>(this->begin())); } - //! @brief Allocate (with new[]) a new vector of size c + //! Allocate (with new[]) a new vector of c elements, which are default constructed. explicit shared_array(size_t c) :base_t(new _E_non_const[c], c) {} - //! @brief Allocate (with new[]) a new vector of size c and fill with value e + //! @brief Allocate (with new[]) a new vector of size c and fill with copies of e template shared_array(size_t c, V e) :base_t(new _E_non_const[c], c) @@ -290,23 +309,54 @@ public: std::fill_n((_E_non_const*)this->_data.get(), this->_count, e); } - //! use existing alloc with delete[] + /** Wrap existing alloc with delete[] + * + * @param a Array allocated with ``new E[len]``. + * @param len Number of elements + */ shared_array(E* a, size_t len) :base_t(a, len) {} - //! use existing alloc w/ custom deletor + /** Wrap existing alloc w/ custom deletor + * + * @param a Array base pointer + * @param b Deletor object. ``b(a)`` must be valid. + * @param len Number of elements + */ template shared_array(E* a, B b, size_t len) :base_t(a, b, len) {} - //! build around existing shared_ptr + /** Wrap around existing shared_ptr + * + * Argument shared_ptr will likely be creating using that class's aliasing constructor. + */ shared_array(const std::shared_ptr& a, size_t len) :base_t(a, len) {} - //! alias existing shared_array + /** Alias existing shared_ptr + * + * A powerful tool for adapting external data containers to shared_array without copying. + * + * @param a Ownership object + * @param b Base pointer. Must remain valid until ownership object is destructed. + * @param len Number of elements + * + * @post data()==b + * + * @code + * auto stdvec(std::make_shared>({1,2,3})); + * + * shared_array aliasvec(stdvec, stdvec->data(), stdvec->size()); + * + * stdvec.reset(); // release original reference + * + * aliasvec.reset(); // ~vector runs! + * @endcode + */ template shared_array(const std::shared_ptr& a, E* b, size_t len) :base_t(a, b, len) @@ -398,10 +448,24 @@ public: return (*this)[i]; } - //! Cast to const, consuming this - //! @pre unique()==true - //! @post empty()==true - //! @throws std::logic_error if !unique() + /** Cast single mutable reference to const, consuming this + * + * Transfers reference from this object to the returned object. + * + * @pre unique()==true + * @post empty()==true + * @throws std::logic_error if !unique() + * + * @code + * shared_array mutator({1,2,3}); + * mutator[0] = 42; + * + * shared_array frozen(mutator.freeze()); + * + * assert(mutator.empty()); // array reference transferred to 'frozen' + * assert(frozen.size()==3); + * @endcode + */ shared_array::type> freeze() { if(!this->unique())