Skip to content

Commit

Permalink
array19 cleanup
Browse files Browse the repository at this point in the history
* rename DynamicArrayOf to DynamicArray
* rename AllocatedArrayOf to AllocatedArray
* rename SliceOf to Span
* drop MoveSliceOf - use Span for that
* added span methods to simplify array implementations
  • Loading branch information
arBmind committed Oct 29, 2023
1 parent 1206ffc commit 80806a8
Show file tree
Hide file tree
Showing 86 changed files with 2,085 additions and 2,090 deletions.
2 changes: 1 addition & 1 deletion Readme.md
Original file line number Diff line number Diff line change
Expand Up @@ -24,7 +24,7 @@ Co-Cpp19 contains a lot of sublibraries and is splitted into many small headers.
This aims to enable the "pay only what you use policy" of C++ at compile time.

* cpp19 - compiler configuration (yours should be somewhat similar)
* array19 - static and dynamic arrays, slices
* array19 - static and dynamic arrays, spans
* meta19 - utilities, type, index and pack wrappers and operations
* coro19 - basic coroutine with generator support
* strong19 - named strong types with tags
Expand Down
20 changes: 11 additions & 9 deletions helpers/array19.natvis
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@
</Expand>
</Type>

<Type Name="array19::SliceOf&lt;*&gt;">
<Type Name="array19::Span&lt;*&gt;">
<DisplayString Condition="m_data==0 || m_count==0">{{empty}}</DisplayString>
<DisplayString Condition="m_data!=0 &amp;&amp; m_count!=0">&amp;{m_data,[m_count]na}</DisplayString>
<Expand>
Expand All @@ -21,27 +21,29 @@
</ArrayItems>
</Expand>
</Type>
<Type Name="array19::MoveSliceOf&lt;*&gt;">

<Type Name="array19::DynamicArray&lt;*&gt;">
<DisplayString Condition="m_data==0 || m_count==0">{{empty}}</DisplayString>
<DisplayString Condition="m_data!=0 &amp;&amp; m_count!=0">&amp;&amp;{m_data,[m_count]na}</DisplayString>
<DisplayString Condition="m_data!=0 &amp;&amp; m_count==1">[{m_data,na}]</DisplayString>
<DisplayString Condition="m_data!=0 &amp;&amp; m_count >1">[{m_count}]</DisplayString>
<Expand>
<ArrayItems Condition="m_data!=0">
<Size>m_count</Size>
<ValuePointer>m_data</ValuePointer>
</ArrayItems>
<Item Name="[…] unused_capacity" Condition="m_data!=0 &amp;&amp; m_capacity > m_count" ExcludeView="simple">m_capacity - m_count</Item>
</Expand>
</Type>

<Type Name="array19::DynamicArrayOf&lt;*&gt;">
<DisplayString Condition="m_pointer==0 || m_count==0">{{empty}}</DisplayString>
<DisplayString Condition="m_pointer!=0 &amp;&amp; m_count==1">[{m_pointer,na}]</DisplayString>
<DisplayString Condition="m_pointer!=0 &amp;&amp; m_count >1">[{m_count}]</DisplayString>
<Type Name="array19::AllocatedArray&lt;*&gt;">
<DisplayString Condition="m_data==0 || m_count==0">{{empty}}</DisplayString>
<DisplayString Condition="m_data!=0 &amp;&amp; m_count==1">[{m_data,na}]</DisplayString>
<DisplayString Condition="m_data!=0 &amp;&amp; m_count >1">[{m_count}]</DisplayString>
<Expand>
<ArrayItems Condition="m_pointer!=0">
<Size>m_count</Size>
<ValuePointer>m_pointer</ValuePointer>
<ValuePointer>m_data</ValuePointer>
</ArrayItems>
<Item Name="[…] unused_capacity" Condition="m_pointer!=0 &amp;&amp; m_capacity > m_count" ExcludeView="simple">m_capacity - m_count</Item>
</Expand>
</Type>
</AutoVisualizer>
17 changes: 11 additions & 6 deletions helpers/gdbhelpers.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@ def qdump__array19__Array(d, value):
if d.isExpanded():
d.putPlotData(value.address(), count, inner_type)

def qdump__array19__SliceOf(d, value):
def qdump__array19__Span(d, value):
inner_type = value.type[0]
data = value['m_data'].pointer()
count = value['m_count'].integer()
Expand All @@ -32,18 +32,24 @@ def qdump__array19__SliceOf(d, value):
d.checkPointer(data)
d.putPlotData(data, count, inner_type)

def qdump__array19__MoveSliceOf(d, value):
def qdump__array19__DynamicArray(d, value):
inner_type = value.type[0]
data = value['m_data'].pointer()
count = value['m_count'].integer()

d.putItemCount(count)
d.putNumChild(count + 1)
if count > 0:
d.checkPointer(data)
d.putPlotData(data, count, inner_type)
if d.isExpanded():
with Children(d):
for i in range(count):
d.putSubItem(i, d.createValue(data + i * inner_type.size(), inner_type))
d.putSubItem('capacity', value["m_capacity"])

def qdump__array19__DynamicArrayOf(d, value):
def qdump__array19__AllocatedArray(d, value):
inner_type = value.type[0]
data = value['m_pointer'].pointer()
data = value['m_data'].pointer()
count = value['m_count'].integer()

d.putItemCount(count)
Expand All @@ -54,7 +60,6 @@ def qdump__array19__DynamicArrayOf(d, value):
with Children(d):
for i in range(count):
d.putSubItem(i, d.createValue(data + i * inner_type.size(), inner_type))
d.putSubItem('capacity', value["m_capacity"])

def qdump__variant19__Variant(d, value):
whichValue = value["indexed"]["which"].integer()
Expand Down
15 changes: 15 additions & 0 deletions src/array19.lib/array19/AllocatedArray.equals.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
#pragma once
#include "AllocatedArray.h"
#include "Zip.h"

namespace array19 {

template<class T> bool operator==(AllocatedArray<T> const& a, AllocatedArray<T> const& b) noexcept {
if (a.count() != b.count()) return false;
for (auto [av, bv] : Zip(a, b)) {
if (!(av == bv)) return false;
}
return true;
}

} // namespace array19
116 changes: 116 additions & 0 deletions src/array19.lib/array19/AllocatedArray.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
#pragma once
#include "AllocatedArrayUtils.h"
#include "Span.one.h"

#include <new> // new allocators
#include <stddef.h> // size_t
#include <type_traits> // is_nothrow_*

namespace array19 {

/// allocated array on the heap
/// * count is fixated at construction time
/// * all array elements are initialized (unlike std::vector)
///
/// note:
/// * C++ lacks a new T[] (custom-initializer) thing - so we would not be able to copy without default initializing
/// => to work around this we use ::operator new[] & ::operator delete[] and construct explicitly
template<class T> struct AllocatedArray final {
using Data = T;
using Count = size_t;
using Index = size_t;

using ConstIterator = Data const*;
using Iterator = Data*;
using ConstSpan = Span<Data const>;
using AmendSpan = Span<Data>;
using MoveSpan = Span<Data&&>;

private:
using Utils = AllocatedArrayUtils<Data>;
Data* m_data{};
Count m_count{}; // equals capacity

public:
AllocatedArray() = default;
~AllocatedArray() noexcept {
if (m_data) {
Utils::destruct(amend());
Utils::deallocate(amend());
}
}

explicit AllocatedArray(ConstSpan span) : m_data{Utils::allocate(span.count())}, m_count{span.count()} {
Utils::copyConstruct(m_data, span);
}

explicit AllocatedArray(MoveSpan span) : m_data{Utils::allocate(span.count())}, m_count{span.count()} {
Utils::moveConstruct(m_data, span);
}

template<will_construct<T>... Ts> requires(sizeof...(Ts) > 0)
explicit AllocatedArray(Ts&&... args) : m_data{Utils::allocate(sizeof...(Ts))} {
(new (m_data + m_count++) Data{(Ts &&) args}, ...);
}

AllocatedArray(AllocatedArray const& o) : AllocatedArray(Span{o}) {}
AllocatedArray& operator=(AllocatedArray const& o) {
if (!m_data || o.m_count != m_count) {
*this = AllocatedArray(o);
}
else if (0 < m_count) {
Utils::copyAssign(m_data, o);
}
return *this;
}

AllocatedArray(AllocatedArray&& o) noexcept : m_data{std::exchange(o.m_data, nullptr)}, m_count{o.m_count} {}
AllocatedArray& operator=(AllocatedArray&& o) noexcept {
if (m_data) {
Utils::destruct(amend());
Utils::deallocate(amend());
}
m_data = std::exchange(o.m_data, nullptr);
m_count = o.m_count;
return *this;
}

[[nodiscard]] static auto createCount(Count count) -> AllocatedArray {
auto result = AllocatedArray{};
result.m_data = Utils::allocate(count);
Utils::defaultConstruct(AmendSpan{result.m_data, count});
result.m_count = count;
return result;
}

[[nodiscard]] auto isEmpty() const noexcept -> bool { return m_count == 0; }
[[nodiscard]] auto count() const noexcept -> Count { return m_count; }

[[nodiscard]] auto begin() const noexcept -> ConstIterator { return std::launder(m_data); }
[[nodiscard]] auto end() const noexcept -> ConstIterator { return begin() + m_count; }

// requires: m_data && m_count != 0
[[nodiscard]] auto front() const -> const Data& { return *begin(); }
// requires: m_data && m_count != 0
[[nodiscard]] auto back() const -> const Data& { return *(begin() + m_count - 1); }

// requires: index < m_count
[[nodiscard]] auto operator[](Index index) const noexcept -> Data const& { return *std::launder(m_data + index); }

[[nodiscard]] operator ConstSpan() const noexcept { return ConstSpan{begin(), m_count}; }
[[nodiscard]] auto amend() noexcept -> AmendSpan { return AmendSpan{std::launder(m_data), m_count}; }
[[nodiscard]] auto move() noexcept -> MoveSpan { return MoveSpan{std::launder(m_data), m_count}; }
};

/// simplified deduction guide
/// usage:
/// AllocatedArray{1,2,3}
template<class T, class... Ts> AllocatedArray(T&&, Ts&&...) -> AllocatedArray<T>;

/// deduce Span from AllocatedArray
/// usage:
/// auto a = AllocatedArray{1,2,3};
/// auto span = Span{a};
template<class T> Span(AllocatedArray<T> const&) -> Span<T const>;

} // namespace array19
12 changes: 12 additions & 0 deletions src/array19.lib/array19/AllocatedArray.ostream.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
#pragma once
#include "AllocatedArray.h"
#include "Span.ostream.h"

namespace array19 {

template<class Chr, class Traits, class T>
auto operator<<(std::basic_ostream<Chr, Traits>& out, AllocatedArray<T> const& a) -> decltype(out)& {
return out << Span{a};
}

} // namespace array19
19 changes: 0 additions & 19 deletions src/array19.lib/array19/AllocatedArrayOf.equals.h

This file was deleted.

Loading

0 comments on commit 80806a8

Please sign in to comment.