This is an automated email from the ASF dual-hosted git repository. bneradt pushed a commit to branch stuff-1 in repository https://gitbox.apache.org/repos/asf/trafficserver-libswoc.git
commit 38e8c208ddf46a93655be1e2a188a2df83a695df Author: Alan M. Carroll <[email protected]> AuthorDate: Fri May 20 16:38:24 2022 -0500 fix. --- code/include/swoc/Vectray.h | 65 +++++++++++++++++++++++++++++++++++++++++++-- doc/code/Vectray.en.rst | 14 +++++----- 2 files changed, 71 insertions(+), 8 deletions(-) diff --git a/code/include/swoc/Vectray.h b/code/include/swoc/Vectray.h index a446880..42f7a37 100644 --- a/code/include/swoc/Vectray.h +++ b/code/include/swoc/Vectray.h @@ -1,3 +1,11 @@ +// SPDX-License-Identifier: Apache-2.0 +// Copyright Apache Software Foundation 2019 +/** @file + + Container that acts like a vector but has static storage to avoid memory allocation for + some specified number of elements. +*/ + #pragma once #include <array> @@ -32,13 +40,17 @@ class Vectray { public: // STL compliance types. using value_type = T; + using reference = std::remove_reference<T>&; + using const_reference = std::remove_reference<T> const&; + using pointer = std::remove_reference<T>*; + using const_pointer = std::remove_reference<T> const*; using allocator_type = A; using size_type = typename vector_type::size_type; using difference_type = typename vector_type::difference_type; using iterator = typename swoc::MemSpan<T>::iterator; using const_iterator = typename swoc::MemSpan<const T>::iterator; + // Need to add reverse iterators - @c reverse_iterator and @c const_reverse_iterator -protected: /// Internal (fixed) storage. struct FixedStore { std::array<std::byte, sizeof(T) * N> _raw; ///< Raw memory for element storage. @@ -57,6 +69,12 @@ protected: /// @return A span containing the valid elements. MemSpan<T> span(); + + /// @return A pointer to the data. + T * data(); + + /// @return A pointer to the data. + T const * data() const; }; using DynamicStore = vector_type; ///< Dynamic (heap) storage. @@ -90,6 +108,15 @@ public: /// @return The number of elements in the container. size_type size() const; + /// @return A pointer to the data. + T * data(); + + /// @return A pointer to the data. + T const * data() const; + + /// @return @c true if no valid elements, @c false if at least one valid element. + bool empty() const; + /// Implicitly convert to a @c MemSpan. operator span () { return this->items(); } /// Implicitly convert to a @c MemSpan. @@ -237,6 +264,16 @@ MemSpan<T> Vectray<T, N, A>::FixedStore::span() { return MemSpan(_raw).template rebind<T>(); } +template<typename T, size_t N, class A> +T * Vectray<T, N, A>::FixedStore::data() { + return reinterpret_cast<T*>(_raw.data()); +} + +template<typename T, size_t N, class A> +T const * Vectray<T, N, A>::FixedStore::data() const { + return reinterpret_cast<T*>(_raw.data()); +} + template<typename T, size_t N, typename A> T& Vectray<T,N,A>::operator[](size_type idx) { return this->items()[idx]; @@ -310,11 +347,19 @@ auto Vectray<T, N, A>::pop_back() -> self_type & { template<typename T, size_t N, typename A> auto Vectray<T,N,A>::size() const -> size_type { return std::visit(swoc::meta::vary{ - [](FixedStore const& fs) { return fs._count; } + [](FixedStore const& fs) { return fs._count; } , [](DynamicStore const& ds) { return ds.size(); } }, _store); } +template<typename T, size_t N, typename A> +bool Vectray<T,N,A>::empty() const { + return std::visit(swoc::meta::vary{ + [](FixedStore const& fs) { return fs._count > 0; } + , [](DynamicStore const& ds) { return ds.empty(); } + }, _store); +} + // --- iterators template<typename T, size_t N, typename A> auto Vectray<T,N,A>::begin() const -> const_iterator { return this->items().begin(); } @@ -349,6 +394,22 @@ auto Vectray<T, N, A>::items() const -> const_span { }, _store); } +template<typename T, size_t N, class A> +T * Vectray<T, N, A>::data() { + return std::visit(swoc::meta::vary{ + [](FixedStore const& fs) { fs.data(); } + , [](DynamicStore const& ds) { return ds.data(); } + }, _store); +} + +template<typename T, size_t N, class A> +T const * Vectray<T, N, A>::data() const { + return std::visit(swoc::meta::vary{ + [](FixedStore const& fs) { fs.data(); } + , [](DynamicStore const& ds) { return ds.data(); } + }, _store); +} + template<typename T, size_t N, class A> auto Vectray<T, N, A>::items() -> span { return std::visit(swoc::meta::vary{ diff --git a/doc/code/Vectray.en.rst b/doc/code/Vectray.en.rst index 04f8f38..68e6908 100644 --- a/doc/code/Vectray.en.rst +++ b/doc/code/Vectray.en.rst @@ -24,11 +24,11 @@ Synopsis |V| is a class intended to replace :code:`std::vector` in situations where performance is critical. An instance of |V| contains a static array of size :arg:`N` which is used in preference to allocating memory. If the number of instances is generally less than :arg:`N` then no memory allocation / -deallocation is done and the performance is as fast as a :code:`std::array`. Unlike an array if +deallocation is done and the performance is as fast as a :code:`std::array`. Unlike an array, if the required memory exceeds the static limits the internal storage is changed to a :code:`std::vector` -without data loss. +without data loss. Another key difference is the number of valid elements in the container can vary. -Performance gain from using this class depends on +Performance gain from using this class depends upon * The static limit :arg:`N` being relatively small to minimize fixed costs. * Required storage usually fits within the static limits. @@ -41,11 +41,13 @@ for a parameter) and only rarely longer. |V| can then significantly reduce memor cost. The second common use case is for stack buffers of moderate size, such as logging buffers. Generally -these are selected to be large to enough to cover almost cases, except for the occasional truncation. +these are selected to be large to enough to cover most cases, except for the occasional truncation. In this case |V| preserves the performance of the common case while providing an escape in the rare circumstance of exceeding the buffer size. -As always, performance tuning is an art, not a science. Do not simply assume |V| is a better choice. +As always, performance tuning is an art, not a science. Do not simply assume |V| is a better choice +and use it to replace `std::vector` or `std::array` in general. Use where it looks helpful and do +measurements to verify. Usage ***** @@ -60,5 +62,5 @@ The static elements are not default constructed, but are constructed as needed. Allocator ========= -Generally this should be defaulted, but is provided so a polymorphic memory resource based +Generally this should be defaulted, but is exposed so a polymorphic memory resource based allocator can be used when needed.
