aboutsummaryrefslogtreecommitdiffstats
path: root/include/jau/cow_darray.hpp
diff options
context:
space:
mode:
authorSven Gothel <[email protected]>2021-01-02 15:15:39 +0100
committerSven Gothel <[email protected]>2021-01-02 15:15:39 +0100
commit9b26be8a50d8789f5e8460dbd06fce0d555356a4 (patch)
tree647fec900e2f354e70f931f4e548c1f5ebdea391 /include/jau/cow_darray.hpp
parent584bd04044c0715dfa55acd4fc02c7aa8e334f21 (diff)
cow_vector, cow_darray, darray: Use std container typedefs'; Add missing constexpr ..
Addint to cow_vector, cow_darray, darray: - constexpr size_type max_size() const noexcept, returning derived difference_type's maximum. cow_darray, darray: - Using template typename Size_type (-> size_type) derived difference_type and validating alloc size_type < its maximum. darray: - allocStore: throw if size_ > std::numeric_limits<difference_type>::max() - clone_range, clone_range_foreign: throw if (first > last) and (dest_capacity < size_type(last-first))
Diffstat (limited to 'include/jau/cow_darray.hpp')
-rw-r--r--include/jau/cow_darray.hpp138
1 files changed, 82 insertions, 56 deletions
diff --git a/include/jau/cow_darray.hpp b/include/jau/cow_darray.hpp
index cfcae18..da4c33c 100644
--- a/include/jau/cow_darray.hpp
+++ b/include/jau/cow_darray.hpp
@@ -28,6 +28,7 @@
#include <cstring>
#include <string>
#include <cstdint>
+#include <limits>
#include <atomic>
#include <memory>
#include <mutex>
@@ -78,7 +79,7 @@ namespace jau {
* </p>
* <p>
* Index operation via ::operator[](size_t) or ::at(size_t) are not supported for now,
- * since they would be only valid if Value_type itself is a std::shared_ptr
+ * since they would be only valid if value_type itself is a std::shared_ptr
* and hence prohibit the destruction of the object if mutating the storage,
* e.g. via jau::cow_darray::push_back().
* </p>
@@ -99,8 +100,22 @@ namespace jau {
class cow_darray
{
public:
- typedef darray<Value_type, Alloc_type, Size_type> storage_t;
- typedef std::shared_ptr<storage_t> storage_ref_t;
+ /** Default growth factor using the golden ratio 1.618 */
+ constexpr static const float DEFAULT_GROWTH_FACTOR = 1.618f;
+
+ // std container conform typedefs'
+
+ typedef Value_type value_type;
+ // typedef value_type* pointer;
+ // typedef const value_type* const_pointer;
+ // typedef value_type& reference;
+ // typedef const value_type& const_reference;
+ typedef Size_type size_type;
+ typedef typename std::make_signed<size_type>::type difference_type;
+ typedef Alloc_type allocator_type;
+
+ typedef darray<value_type, allocator_type, size_type> storage_t;
+ typedef std::shared_ptr<storage_t> storage_ref_t;
/**
* Immutable, read-only const_iterator, lock-free,
@@ -109,7 +124,7 @@ namespace jau {
* Using jau::cow_darray::get_snapshot() at construction.
* </p>
*/
- typedef cow_ro_iterator<Value_type, storage_t, storage_ref_t> const_iterator;
+ typedef cow_ro_iterator<value_type, storage_t, storage_ref_t, size_type> const_iterator;
/**
* Mutable, read-write iterator, holding the write-lock and a store copy until destruction.
@@ -118,12 +133,14 @@ namespace jau {
* and jau::cow_darray::set_store() at destruction.
* </p>
*/
- typedef cow_rw_iterator<Value_type, storage_t, storage_ref_t, cow_darray> iterator;
+ typedef cow_rw_iterator<value_type, storage_t, storage_ref_t, cow_darray, size_type> iterator;
- /** Default growth factor using the golden ratio 1.618 */
- inline static const float DEFAULT_GROWTH_FACTOR = 1.618f;
+ // typedef std::reverse_iterator<iterator> reverse_iterator;
+ // typedef std::reverse_iterator<const_iterator> const_reverse_iterator;
private:
+ static constexpr size_type DIFF_MAX = std::numeric_limits<difference_type>::max();
+
storage_ref_t store_ref;
sc_atomic_bool sync_atomic;
std::recursive_mutex mtx_write;
@@ -141,9 +158,9 @@ namespace jau {
* Creating an empty instance with initial capacity and other (default) properties.
* @param capacity initial capacity of the new instance.
* @param growth_factor given growth factor
- * @param alloc given Alloc_type
+ * @param alloc given allocator_type
*/
- constexpr explicit cow_darray(Size_type capacity, const float growth_factor=DEFAULT_GROWTH_FACTOR, const Alloc_type& alloc = Alloc_type())
+ constexpr explicit cow_darray(size_type capacity, const float growth_factor=DEFAULT_GROWTH_FACTOR, const allocator_type& alloc = allocator_type())
: store_ref(std::make_shared<storage_t>(capacity, growth_factor, alloc)), sync_atomic(false) {}
// conversion ctor on storage_t elements
@@ -151,13 +168,13 @@ namespace jau {
constexpr cow_darray(const storage_t& x)
: store_ref(std::make_shared<storage_t>(x)), sync_atomic(false) {}
- constexpr explicit cow_darray(const storage_t& x, const float growth_factor, const Alloc_type& alloc)
+ constexpr explicit cow_darray(const storage_t& x, const float growth_factor, const allocator_type& alloc)
: store_ref(std::make_shared<storage_t>(x, growth_factor, alloc)), sync_atomic(false) {}
constexpr cow_darray(storage_t && x) noexcept
: store_ref(std::make_shared<storage_t>(std::move(x))), sync_atomic(false) {}
- constexpr explicit cow_darray(storage_t && x, const float growth_factor, const Alloc_type& alloc) noexcept
+ constexpr explicit cow_darray(storage_t && x, const float growth_factor, const allocator_type& alloc) noexcept
: store_ref(std::make_shared<storage_t>(std::move(x), growth_factor, alloc)), sync_atomic(false) {}
// copy_ctor on cow_darray elements
@@ -182,9 +199,9 @@ namespace jau {
* Capacity and size will equal the given array, i.e. the result is a trimmed array.
* @param x the given cow_darray, all elements will be copied into the new instance.
* @param growth_factor custom growth factor
- * @param alloc custom Alloc_type instance
+ * @param alloc custom allocator_type instance
*/
- constexpr explicit cow_darray(const cow_darray& x, const float growth_factor, const Alloc_type& alloc)
+ constexpr explicit cow_darray(const cow_darray& x, const float growth_factor, const allocator_type& alloc)
: sync_atomic(false) {
storage_ref_t x_store_ref;
{
@@ -198,14 +215,14 @@ namespace jau {
* Creates a new instance with custom initial storage capacity, copying all elements from the given array.<br>
* Size will equal the given array.
* <p>
- * Calculated safe capacity is: <code>std::max<Size_type>(x.size(), _capacity)</code>
+ * Throws jau::IllegalArgumentException() if <code>_capacity < x.size()</code>.
* </p>
* @param x the given cow_darray, all elements will be copied into the new instance.
* @param _capacity custom initial storage capacity
* @param growth_factor custom growth factor
- * @param alloc custom Alloc_type instance
+ * @param alloc custom allocator_type instance
*/
- constexpr explicit cow_darray(const cow_darray& x, const Size_type _capacity, const float growth_factor, const Alloc_type& alloc)
+ constexpr explicit cow_darray(const cow_darray& x, const size_type _capacity, const float growth_factor, const allocator_type& alloc)
: sync_atomic(false) {
storage_ref_t x_store_ref;
{
@@ -229,45 +246,54 @@ namespace jau {
/**
* Creates a new instance with custom initial storage capacity,
- * copying all elements from the given const_iterator Value_type range [first, last).<br>
- * Size will equal the range [first, last), i.e. <code>Size_type(last-first)</code>.
+ * copying all elements from the given const_iterator value_type range [first, last).<br>
+ * Size will equal the range [first, last), i.e. <code>size_type(last-first)</code>.
* <p>
- * Calculated safe capacity is: <code>std::max<Size_type>(Size_type(last-first), _capacity)</code>
+ * Throws jau::IllegalArgumentException() if <code>_capacity < size_type(last - first)</code>.
* </p>
* @param _capacity custom initial storage capacity
- * @param first const_iterator to first element of Value_type range [first, last)
- * @param last const_iterator to last element of Value_type range [first, last)
+ * @param first const_iterator to first element of value_type range [first, last)
+ * @param last const_iterator to last element of value_type range [first, last)
* @param growth_factor custom growth factor
- * @param alloc custom Alloc_type instance
+ * @param alloc custom allocator_type instance
*/
- constexpr cow_darray(const Size_type _capacity, const_iterator first, const_iterator last,
- const float growth_factor=DEFAULT_GROWTH_FACTOR, const Alloc_type& alloc = Alloc_type())
+ constexpr cow_darray(const size_type _capacity, const_iterator first, const_iterator last,
+ const float growth_factor=DEFAULT_GROWTH_FACTOR, const allocator_type& alloc = allocator_type())
: store_ref(std::make_shared<storage_t>(_capacity, first.underling(), last.underling(), growth_factor, alloc)), sync_atomic(false)
{ }
/**
* Creates a new instance with custom initial storage capacity,
- * copying all elements from the given template input-iterator Value_type range [first, last).<br>
- * Size will equal the range [first, last), i.e. <code>Size_type(last-first)</code>.
+ * copying all elements from the given template input-iterator value_type range [first, last).<br>
+ * Size will equal the range [first, last), i.e. <code>size_type(last-first)</code>.
* <p>
- * Calculated safe capacity is: <code>std::max<Size_type>(Size_type(last-first), _capacity)</code>
+ * Throws jau::IllegalArgumentException() if <code>_capacity < size_type(last - first)</code>.
* </p>
* @tparam InputIt template input-iterator custom type
* @param _capacity custom initial storage capacity
- * @param first template input-iterator to first element of Value_type range [first, last)
- * @param last template input-iterator to last element of Value_type range [first, last)
+ * @param first template input-iterator to first element of value_type range [first, last)
+ * @param last template input-iterator to last element of value_type range [first, last)
* @param growth_factor custom growth factor
- * @param alloc custom Alloc_type instance
+ * @param alloc custom allocator_type instance
*/
template< class InputIt >
- constexpr explicit cow_darray(const Size_type _capacity, InputIt first, InputIt last,
- const float growth_factor=DEFAULT_GROWTH_FACTOR, const Alloc_type& alloc = Alloc_type())
+ constexpr explicit cow_darray(const size_type _capacity, InputIt first, InputIt last,
+ const float growth_factor=DEFAULT_GROWTH_FACTOR, const allocator_type& alloc = allocator_type())
: store_ref(std::make_shared<storage_t>(_capacity, first, last, growth_factor, alloc)), sync_atomic(false)
{ }
~cow_darray() noexcept { }
+ /**
+ * Returns <code>std::numeric_limits<difference_type>::max()</code> as the maximum array size.
+ * <p>
+ * We rely on the signed <code>difference_type</code> for pointer arithmetic,
+ * deducing ranges from iterator.
+ * </p>
+ */
+ constexpr size_type max_size() const noexcept { return DIFF_MAX; }
+
// cow_vector features
/**
@@ -381,17 +407,17 @@ namespace jau {
// read access
- const Alloc_type& get_allocator_ref() const noexcept {
+ const allocator_type& get_allocator_ref() const noexcept {
sc_atomic_critical sync( const_cast<cow_darray *>(this)->sync_atomic );
return store_ref->get_allocator_ref();
}
- Alloc_type get_allocator() const noexcept {
+ allocator_type get_allocator() const noexcept {
sc_atomic_critical sync( const_cast<cow_darray *>(this)->sync_atomic );
return store_ref->get_allocator();
}
- constexpr Size_type capacity() const noexcept {
+ constexpr size_type capacity() const noexcept {
sc_atomic_critical sync( const_cast<cow_darray *>(this)->sync_atomic );
return store_ref->capacity();
}
@@ -413,7 +439,7 @@ namespace jau {
* This read operation is <i>lock-free</i>.
* </p>
*/
- constexpr Size_type size() const noexcept {
+ constexpr size_type size() const noexcept {
sc_atomic_critical sync( const_cast<cow_darray *>(this)->sync_atomic );
return store_ref->size();
}
@@ -430,7 +456,7 @@ namespace jau {
* This write operation uses a mutex lock and is blocking this instances' write operations only.
* </p>
*/
- void reserve(Size_type new_capacity) {
+ void reserve(size_type new_capacity) {
const std::lock_guard<std::recursive_mutex> lock(mtx_write);
storage_ref_t old_store_ref = store_ref;
if( new_capacity > old_store_ref->capacity() ) {
@@ -574,7 +600,7 @@ namespace jau {
* </p>
* @param x the value to be added at the tail.
*/
- void push_back(const Value_type& x) {
+ void push_back(const value_type& x) {
const std::lock_guard<std::recursive_mutex> lock(mtx_write);
storage_ref_t old_store_ref = store_ref;
if( old_store_ref->capacity_reached() ) {
@@ -599,7 +625,7 @@ namespace jau {
* This write operation uses a mutex lock and is blocking this instances' write operations only.
* </p>
*/
- void push_back(Value_type&& x) {
+ void push_back(value_type&& x) {
const std::lock_guard<std::recursive_mutex> lock(mtx_write);
storage_ref_t old_store_ref = store_ref;
if( old_store_ref->capacity_reached() ) {
@@ -619,19 +645,19 @@ namespace jau {
}
/**
- * Like std::vector::push_back(), but appends the whole Value_type range [first, last).
+ * Like std::vector::push_back(), but appends the whole value_type range [first, last).
* <p>
* This write operation uses a mutex lock and is blocking this instances' write operations only.
* </p>
- * @tparam InputIt foreign input-iterator to range of Value_type [first, last)
- * @param first first foreign input-iterator to range of Value_type [first, last)
- * @param last last foreign input-iterator to range of Value_type [first, last)
+ * @tparam InputIt foreign input-iterator to range of value_type [first, last)
+ * @param first first foreign input-iterator to range of value_type [first, last)
+ * @param last last foreign input-iterator to range of value_type [first, last)
*/
template< class InputIt >
constexpr void push_back( InputIt first, InputIt last ) {
const std::lock_guard<std::recursive_mutex> lock(mtx_write);
storage_ref_t old_store_ref = store_ref;
- const Size_type new_size_ = old_store_ref->size() + Size_type(last - first);
+ const size_type new_size_ = old_store_ref->size() + size_type(last - first);
if( new_size_ > old_store_ref->capacity() ) {
// grow and swap all refs
@@ -650,17 +676,17 @@ namespace jau {
}
/**
- * Like std::vector::push_back(), but appends the whole Value_type range [first, last).
+ * Like std::vector::push_back(), but appends the whole value_type range [first, last).
* <p>
* This write operation uses a mutex lock and is blocking this instances' write operations only.
* </p>
- * @param first first const_iterator to range of Value_type [first, last)
- * @param last last const_iterator to range of Value_type [first, last)
+ * @param first first const_iterator to range of value_type [first, last)
+ * @param last last const_iterator to range of value_type [first, last)
*/
constexpr void push_back( const_iterator first, const_iterator last ) {
const std::lock_guard<std::recursive_mutex> lock(mtx_write);
storage_ref_t old_store_ref = store_ref;
- const Size_type new_size_ = old_store_ref->size() + Size_type(last - first);
+ const size_type new_size_ = old_store_ref->size() + size_type(last - first);
if( new_size_ > old_store_ref->capacity() ) {
// grow and swap all refs
@@ -679,12 +705,12 @@ namespace jau {
}
/**
- * Generic Value_type equal comparator to be user defined for e.g. jau::cow_darray::push_back_unique().
+ * Generic value_type equal comparator to be user defined for e.g. jau::cow_darray::push_back_unique().
* @param a one element of the equality test.
* @param b the other element of the equality test.
* @return true if both are equal
*/
- typedef bool(*equal_comparator)(const Value_type& a, const Value_type& b);
+ typedef bool(*equal_comparator)(const value_type& a, const value_type& b);
/**
* Like std::vector::push_back(), but only if the newly added element does not yet exist.
@@ -710,7 +736,7 @@ namespace jau {
* @param comparator the equal comparator to return true if both given elements are equal
* @return true if the element has been uniquely added, otherwise false
*/
- bool push_back_unique(const Value_type& x, equal_comparator comparator) {
+ bool push_back_unique(const value_type& x, equal_comparator comparator) {
const std::lock_guard<std::recursive_mutex> lock(mtx_write);
for(auto it = store_ref->begin(); it != store_ref->end(); ) {
if( comparator( *it, x ) ) {
@@ -747,7 +773,7 @@ namespace jau {
* @param comparator the equal comparator to return true if both given elements are equal
* @return number of erased elements
*/
- int erase_matching(const Value_type& x, const bool all_matching, equal_comparator comparator) {
+ int erase_matching(const value_type& x, const bool all_matching, equal_comparator comparator) {
int count = 0;
const std::lock_guard<std::recursive_mutex> lock(mtx_write);
storage_ref_t new_store_ref = std::make_shared<storage_t>( *store_ref );
@@ -770,7 +796,7 @@ namespace jau {
}
/**
- * Thread safe Value_type copy assignment to Value_type at given position with bounds checking.
+ * Thread safe value_type copy assignment to value_type at given position with bounds checking.
* <p>
* This write operation uses a mutex lock and is blocking this instances' write operations only.
* </p>
@@ -780,7 +806,7 @@ namespace jau {
* @param i the position within this store
* @param x the value to be assigned to the object at the given position
*/
- void put(size_t i, const Value_type& x) {
+ void put(size_type i, const value_type& x) {
const std::lock_guard<std::recursive_mutex> lock(mtx_write);
storage_ref_t new_store_ref = std::make_shared<storage_t>( *store_ref );
new_store_ref->at(i) = x;
@@ -791,7 +817,7 @@ namespace jau {
}
/**
- * Thread safe Value_type move assignment to Value_type at given position with bounds checking.
+ * Thread safe value_type move assignment to value_type at given position with bounds checking.
* <p>
* This write operation uses a mutex lock and is blocking this instances' write operations only.
* </p>
@@ -801,7 +827,7 @@ namespace jau {
* @param i the position within this store
* @param x the value to be assigned to the object at the given position
*/
- void put(size_t i, Value_type&& x) {
+ void put(size_type i, value_type&& x) {
const std::lock_guard<std::recursive_mutex> lock(mtx_write);
storage_ref_t new_store_ref = std::make_shared<storage_t>( *store_ref );
new_store_ref->at(i) = std::move(x);