doc: shared_array

This commit is contained in:
Michael Davidsaver
2026-01-26 18:10:02 -08:00
parent a4259c7376
commit b7c2d1b2c4
2 changed files with 91 additions and 20 deletions
+14 -7
View File
@@ -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<uint32_t> typed_mutable;
shared_array<const uint32_t> typed_const;
shared_array<void> void_mutable;
shared_array<const void> 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<shared_array<const double>>();
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<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'.
// castTo() throws std::logic_error if the underlying type is not 'double'.
shared_array<const double> temp = varr.castTo<const double>();
}
+77 -13
View File
@@ -209,6 +209,8 @@ shared_array<void> 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<std::vector<T>>``.
*
* 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<uint32> arr({1,2,3});
* @endcode
*
* @post size()==L.size()
*/
template<typename A>
shared_array(std::initializer_list<A> 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<uint32_t> X(...);
* shared_array<uint32_t> Y(X.begin(), X.end());
*
* uint32_t cvals[] = {1,2,3,4};
* shared_array<uint32_t> Z(cvals, cvals + NELEMENTS(cvals));
* @endcode
*/
template<typename Iter, typename std::iterator_traits<Iter>::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<typename V>
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<typename B>
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<E>& 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<std::vector<uint32_t>>({1,2,3}));
*
* shared_array<uint32_t> aliasvec(stdvec, stdvec->data(), stdvec->size());
*
* stdvec.reset(); // release original reference
*
* aliasvec.reset(); // ~vector runs!
* @endcode
*/
template<typename A>
shared_array(const std::shared_ptr<A>& 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<uint32_t> mutator({1,2,3});
* mutator[0] = 42;
*
* shared_array<const utin32_t> frozen(mutator.freeze());
*
* assert(mutator.empty()); // array reference transferred to 'frozen'
* assert(frozen.size()==3);
* @endcode
*/
shared_array<typename std::add_const<E>::type>
freeze() {
if(!this->unique())