Skip to content

Commit 0a1170e

Browse files
committed
more defaulted equals operators, more operator[] instead of at(), SliceOf lost weight
1 parent 83dcc8b commit 0a1170e

27 files changed

Lines changed: 135 additions & 238 deletions

src/array19.lib/array19/Array.equals.h

Lines changed: 0 additions & 24 deletions
This file was deleted.

src/array19.lib/array19/Array.equals.test.cpp

Lines changed: 0 additions & 22 deletions
This file was deleted.

src/array19.lib/array19/Array.h

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -7,28 +7,29 @@ namespace array19 {
77

88
/// simplified version of std::array
99
/// * no member types
10-
/// * no `operator[]` - use `at` and `amendAt`
1110
/// * no exceptions
1211
template<class T, size_t C> struct Array {
1312
using Element = T;
1413
static constexpr auto count = C;
15-
using Size = decltype(C);
16-
using Index = size_t;
1714

1815
T m[count];
1916

17+
constexpr bool operator==(const Array&) const = default;
18+
19+
[[nodiscard]] constexpr auto isEmpty() const noexcept -> bool { return count == 0; }
2020
[[nodiscard]] constexpr auto begin() const noexcept -> const T* { return m; }
2121
[[nodiscard]] constexpr auto end() const noexcept -> const T* { return m + C; }
2222
[[nodiscard]] constexpr auto operator[](size_t i) const noexcept -> const T& { return m[i]; }
23-
constexpr operator SliceOf<const T>() const noexcept { return SliceOf{m, count}; }
23+
constexpr operator SliceOf<const T>() const noexcept { return SliceOf{m, C}; }
2424

2525
// hint: use `amendSliceOfArray()` if you need to iterate and mutate
2626
[[nodiscard]] constexpr auto amendBegin() noexcept -> T* { return m; }
2727
[[nodiscard]] constexpr auto amendEnd() noexcept -> T* { return m + C; }
28-
[[nodiscard]] constexpr auto amend() noexcept -> SliceOf<T> { return SliceOf{m, count}; }
28+
[[nodiscard]] constexpr auto amend() noexcept -> SliceOf<T> { return SliceOf{m, C}; }
2929
};
3030

31-
/// deduction guide without checking all types are the same
31+
/// simplified deduction guide
32+
/// * not checking that all types are the same
3233
/// usage:
3334
/// Array{1, 2, 3};
3435
template<class T, class... Ts> Array(T, Ts...)->Array<T, 1 + sizeof...(Ts)>;

src/array19.lib/array19/Array.test.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,5 +23,5 @@ void mutable_Array_test() {
2323
return a;
2424
}();
2525

26-
static_assert(ca[1] == 5);
26+
static_assert(ca == Array{1, 5, 3});
2727
}

src/array19.lib/array19/DynamicArrayOf.h

Lines changed: 41 additions & 34 deletions
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,7 @@ template<class ElemStorage> struct DynamicStorage final {
4040

4141
template<class T> struct DynamicArrayOf final {
4242
using Element = T;
43-
using Size = size_t;
43+
using Count = size_t;
4444
using Index = size_t;
4545

4646
using Reference = Element&;
@@ -54,84 +54,91 @@ template<class T> struct DynamicArrayOf final {
5454
~DynamicArrayOf() noexcept(std::is_nothrow_destructible_v<Element>) { destructSlice(amendSlice()); }
5555

5656
DynamicArrayOf(const DynamicArrayOf& o) noexcept(std::is_nothrow_copy_constructible_v<Element>)
57-
: m_storage(Storage::create(o._count))
58-
, m_count(o._count) {
57+
: m_storage(Storage::create(o.m_count))
58+
, m_count(o.m_count) {
5959
copyConstructSlice(m_storage.pointer, o.slice());
6060
}
6161
DynamicArrayOf& operator=(const DynamicArrayOf& o) noexcept(std::is_nothrow_copy_assignable_v<Element>) {
62-
if (m_storage.capacity < o.count()) {
62+
if (m_storage.capacity < o.m_count) {
6363
*this = DynamicArrayOf(o);
6464
}
6565
else {
66-
auto countDiff = m_count - o._count;
66+
auto countDiff = m_count - o.m_count;
6767
if (countDiff > 0) {
68-
copyAssignSlice(amendBegin(), ConstSlice{o.begin(), o.begin() + m_count});
69-
copyConstructSlice(storageEnd(), ConstSlice{o.begin() + m_count, o.end()});
68+
copyAssignSlice(amendBegin(), o.slice());
69+
destructSlice(Slice{amendBegin() + o.m_count, countDiff});
7070
}
7171
else {
72-
copyAssignSlice(amendBegin(), o.slice());
73-
destructSlice(Slice{amendBegin() + o._count, amendEnd()});
72+
copyAssignSlice(amendBegin(), ConstSlice{o.begin(), m_count});
73+
copyConstructSlice(storageEnd(), ConstSlice{o.begin() + m_count, -countDiff});
7474
}
75-
m_count = o.count();
75+
m_count = o.m_count;
7676
}
7777
}
7878

79-
DynamicArrayOf(DynamicArrayOf&& o) noexcept : m_storage(std::move(o)), m_count(o._count) { o._count = 0; }
79+
DynamicArrayOf(DynamicArrayOf&& o) noexcept : m_storage(std::move(o)), m_count(o.m_count) { o.m_count = 0; }
8080
DynamicArrayOf& operator=(DynamicArrayOf&& o) noexcept {
8181
destructSlice(amendSlice());
82-
m_storage = std::move(o);
83-
m_count = o._count;
84-
o._count = 0;
82+
m_storage = std::move(o.m_storage);
83+
m_count = o.m_count;
84+
o.m_count = 0;
8585
}
8686

87-
[[nodiscard]] auto count() const -> Size { return m_count; }
88-
[[nodiscard]] auto totalCapacity() const -> Size { return m_storage.capacity; }
89-
[[nodiscard]] auto unusedCapacity() const -> Size { return m_storage.capacity - m_count; }
87+
[[nodiscard]] constexpr auto isEmpty() const noexcept -> bool { return m_count == 0; }
88+
[[nodiscard]] auto count() const -> Count { return m_count; }
89+
[[nodiscard]] auto totalCapacity() const -> Count { return m_storage.capacity; }
90+
[[nodiscard]] auto unusedCapacity() const -> Count { return m_storage.capacity - m_count; }
9091

91-
[[nodiscard]] auto begin() const & noexcept -> ConstIterator {
92+
[[nodiscard]] auto begin() const noexcept -> ConstIterator {
9293
return std::launder(reinterpret_cast<const T*>(m_storage.pointer));
9394
}
9495
// NOTE: end() is not laundered!
95-
[[nodiscard]] auto end() const & noexcept -> ConstIterator {
96+
[[nodiscard]] auto end() const noexcept -> ConstIterator {
9697
return reinterpret_cast<const T*>(m_storage.pointer + m_count);
9798
}
98-
99-
[[nodiscard]] auto operator[](Index index) const & noexcept -> ConstReference {
99+
[[nodiscard]] auto operator[](Index index) const noexcept -> ConstReference {
100100
return *std::launder(reinterpret_cast<const T*>(m_storage.pointer + index));
101101
}
102-
[[nodiscard]] operator ConstSlice() const noexcept { return ConstSlice{begin(), end()}; }
102+
[[nodiscard]] operator ConstSlice() const noexcept { return ConstSlice{begin(), m_count}; }
103103

104104
[[nodiscard]] auto amendBegin() & noexcept -> Iterator {
105105
return std::launder(reinterpret_cast<T*>(m_storage.pointer));
106106
}
107107
// NOTE: end() is not laundered!
108108
[[nodiscard]] auto amendEnd() & noexcept -> Iterator { return amendBegin() + m_count; }
109109

110-
[[nodiscard]] auto amend() -> Slice { return Slice{amendBegin(), amendEnd()}; }
110+
[[nodiscard]] auto amend() -> Slice { return Slice{amendBegin(), m_count}; }
111+
112+
void ensureCapacity(Count count) {
113+
if (totalCapacity() < size) growBy(size - totalCapacity());
114+
}
115+
void ensureUnusedCapacity(Count count) {
116+
if (unusedCapacity() < count) growBy(count);
117+
}
111118

112119
void append(ConstSlice elems) {
113-
if (unusedCapacity() < elems.count()) grow(elems.count());
120+
ensureUnusedCapacity(elems.count());
114121
copyConstructSlice(storageEnd(), elems);
115122
m_count += elems.count();
116123
}
117124

118125
void pop() noexcept(std::is_nothrow_destructible_v<Element>) {
119-
destructSlice(Slice{amendBegin() + m_count - 1, amendEnd()});
126+
destructSlice(Slice{amendBegin() + m_count - 1, 1});
120127
m_count--;
121128
}
122129

123-
void splice(Iterator it, Size removeCount, ConstSlice insertSlice) {
130+
void splice(Iterator it, Count removeCount, ConstSlice insertSlice) {
124131
auto offset = it - amendBegin();
125132
auto insertCount = insertSlice.count();
126133
auto remainCount = m_count - offset - removeCount;
127-
auto remainSlice = Slice{it + removeCount, amendEnd()};
134+
auto remainSlice = Slice{it + removeCount, remainCount};
128135
// old: [ ..(offset)..,[it] ..(removeCount).., ..(remainCount)... ]
129136
// new: [ ..(offset)..,[it] ..(insertCount).., ..(remainCount)... ]
130137

131138
auto countDiff = insertCount - removeCount;
132139
if (unusedCapacity() < countDiff) { // not enough storage => arrange everything in new storage
133140
auto newStorage = grownStorage(countDiff);
134-
moveConstructSlice(newStorage.pointer, Slice{amendBegin(), it});
141+
moveConstructSlice(newStorage.pointer, Slice{amendBegin(), offset});
135142
copyConstructSlice(newStorage.pointer + offset, insertSlice);
136143
moveConstructSlice(newStorage.pointer + offset + insertCount, remainSlice);
137144
destructSlice(amendSlice());
@@ -140,7 +147,7 @@ template<class T> struct DynamicArrayOf final {
140147
else if (countDiff <= 0) { // shrinking
141148
copyAssignSlice(it, insertSlice);
142149
forwardMoveConstructSlice(it + insertCount, remainSlice);
143-
destructSlice(Slice{amendEnd() + countDiff, amendEnd()});
150+
destructSlice(Slice{amendEnd() + countDiff, -countDiff});
144151
}
145152
else if (offset + insertCount <= m_count) { // parts of remainSlice is moved beyond end()
146153
moveConstructSlice(storageEnd(), remainSlice.slice(remainCount - countDiff, countDiff));
@@ -165,8 +172,8 @@ template<class T> struct DynamicArrayOf final {
165172
using StorageIterator = ElementStorage*;
166173
constexpr static auto element_size = sizeof(ElementStorage);
167174

168-
auto byteSize() const -> Size { return m_count * element_size; }
169-
auto storageEnd() -> StorageIterator { return m_storage.pointer + m_count; }
175+
[[nodiscard]] auto byteSize() const -> size_t { return m_count * element_size; }
176+
[[nodiscard]] auto storageEnd() -> StorageIterator { return m_storage.pointer + m_count; }
170177

171178
static void destructSlice(Slice slice) {
172179
for (auto& elem : slice) elem.~Element();
@@ -222,14 +229,14 @@ template<class T> struct DynamicArrayOf final {
222229
for (auto& from : fromSlice) new (to++) Element(std::move(from));
223230
}
224231
}
225-
auto grownStorage(int growBy) const -> Size {
232+
[[nodiscard]] auto grownStorage(int growBy) const -> Storage {
226233
auto cur = totalCapacity();
227234
auto res = (cur << 1) - (cur >> 1) + (cur >> 4); // * 1.563
228235
if (res < 5) res = 5;
229236
if (res < totalCapacity() + growBy) res = totalCapacity() + growBy;
230237
return Storage::create(res);
231238
}
232-
void grow(int by) {
239+
void growBy(int by) {
233240
auto newStorage = grownStorage(by);
234241
moveConstructSlice(newStorage.pointer, amendSlice());
235242
destructSlice(amendSlice());
@@ -238,7 +245,7 @@ template<class T> struct DynamicArrayOf final {
238245

239246
private:
240247
Storage m_storage;
241-
Size m_count;
248+
Count m_count;
242249
};
243250

244251
} // namespace array19

src/array19.lib/array19/SliceOf.h

Lines changed: 6 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,17 @@ template<class T> struct SliceOf {
1515
using Index = size_t;
1616

1717
constexpr SliceOf() = default;
18-
constexpr SliceOf(const SliceOf&) = default;
19-
constexpr SliceOf& operator=(const SliceOf&) = default;
20-
constexpr SliceOf(SliceOf&&) = default;
21-
constexpr SliceOf& operator=(SliceOf&&) = default;
22-
23-
constexpr explicit SliceOf(Element* data, Element* end) noexcept : m_data(data), m_count(end - data) {}
2418
constexpr explicit SliceOf(Element* data, Count count) noexcept : m_data(data), m_count(count) {}
2519

26-
[[nodiscard]] constexpr auto count() const -> Count { return m_count; }
27-
[[nodiscard]] constexpr auto slice(Index offset, Count count) const -> SliceOf {
20+
[[nodiscard]] constexpr auto isEmpty() const noexcept -> bool { return m_count == 0; }
21+
[[nodiscard]] constexpr auto count() const noexcept -> Count { return m_count; }
22+
[[nodiscard]] constexpr auto slice(Index offset, Count count) const noexcept -> SliceOf {
2823
return SliceOf{m_data + offset, count};
2924
}
3025

31-
[[nodiscard]] constexpr auto begin() const & noexcept -> Element* { return m_data; }
32-
[[nodiscard]] constexpr auto end() const& -> Element* { return m_data + m_count; }
33-
[[nodiscard]] constexpr auto operator[](Index index) const & noexcept -> Element& { return *(m_data + index); }
26+
[[nodiscard]] constexpr auto begin() const noexcept -> Element* { return m_data; }
27+
[[nodiscard]] constexpr auto end() const noexcept -> Element* { return m_data + m_count; }
28+
[[nodiscard]] constexpr auto operator[](Index index) const noexcept -> Element& { return *(m_data + index); }
3429

3530
[[nodiscard]] constexpr operator SliceOf<const T>() const noexcept { return SliceOf<const T>{m_data, m_count}; }
3631

src/array19.lib/array19/WithIndex.h

Lines changed: 12 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -3,40 +3,38 @@
33

44
namespace array19 {
55

6+
/// Iterate a container with indices
7+
/// usage:
8+
/// for(auto [value, index] : WithIndex{container});
69
template<class C> struct WithIndex {
710
using It = decltype(adlBegin(*static_cast<C*>(nullptr)));
811
using Res = decltype(**static_cast<It*>(nullptr));
912

13+
// not using std::pair to avoid reference hassles
1014
struct result {
1115
Res value;
1216
size_t index;
1317
};
1418

19+
// minimal iterator that is just enough to run ranged for loop
1520
struct iterator {
16-
constexpr iterator(It it) : it(it) {}
21+
It it;
22+
size_t index{};
1723

1824
[[nodiscard]] constexpr auto operator*() const -> result { return {*it, index}; }
19-
25+
[[nodiscard]] constexpr bool operator!=(const It& o) const { return it != o; }
2026
constexpr auto operator++() -> iterator& { return (++it, ++index, *this); }
21-
constexpr auto operator--() -> iterator& { return (--it, --index, *this); }
22-
23-
constexpr bool operator==(const iterator& o) const { return it == o.it; }
24-
constexpr bool operator!=(const iterator& o) const { return !(*this == o); }
25-
26-
private:
27-
It it;
28-
size_t index{};
2927
};
3028

31-
constexpr WithIndex(C& c) : c(c) {}
29+
constexpr WithIndex(C& c) noexcept : c(c) {}
3230

33-
[[nodiscard]] constexpr auto begin() -> iterator { return {adlBegin(c)}; }
34-
[[nodiscard]] constexpr auto end() -> iterator { return {adlEnd(c)}; }
31+
[[nodiscard]] constexpr auto begin() -> iterator { return iterator{adlBegin(c), {}}; }
32+
[[nodiscard]] constexpr auto end() -> It { return adlEnd(c); }
3533

3634
private:
3735
C& c;
3836
};
3937

40-
template<class C> WithIndex(C&)->WithIndex<C>;
38+
template<class C> WithIndex(C&) -> WithIndex<C>;
4139

4240
} // namespace array19

src/array19.lib/array19/Zip.h

Lines changed: 7 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,9 @@ namespace array19 {
55

66
/// Zip allows to iterate two containers in lockstep
77
///
8+
/// precondition:
9+
/// * both containers have the same length
10+
///
811
/// usage:
912
/// for (auto [valueA, valueB] : Zip{a, b});
1013
template<class A, class B> struct Zip {
@@ -19,19 +22,12 @@ template<class A, class B> struct Zip {
1922
};
2023

2124
struct iterator {
22-
constexpr iterator(AIt aIt, BIt bIt) : aIt(aIt), bIt(bIt) {}
25+
AIt aIt;
26+
BIt bIt;
2327

2428
constexpr auto operator*() const -> result { return {*aIt, *bIt}; }
25-
2629
constexpr auto operator++() -> iterator& { return (++aIt, ++bIt, *this); }
27-
constexpr auto operator--() -> iterator& { return (--aIt, --bIt, *this); }
28-
29-
constexpr bool operator==(const iterator& o) const { return aIt == o.aIt && bIt == o.bIt; }
30-
constexpr bool operator!=(const iterator& o) const { return !(*this == o); }
31-
32-
private:
33-
AIt aIt;
34-
BIt bIt;
30+
constexpr bool operator==(const iterator& o) const = default;
3531
};
3632

3733
constexpr Zip() = default;
@@ -45,6 +41,6 @@ template<class A, class B> struct Zip {
4541
B* b{};
4642
};
4743

48-
template<class A, class B> Zip(A&, B&) -> Zip<A, B>;
44+
template<class A, class B> Zip(A&, B&)->Zip<A, B>;
4945

5046
} // namespace array19

src/array19.lib/array19/array19.qbs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,6 @@ Product {
33
Depends { name: "cpp19" }
44

55
files: [
6-
"Array.equals.h",
76
"Array.h",
87
"Array.ostream.h",
98
"Array.slice.h",

0 commit comments

Comments
 (0)