Skip to content

Commit 2337414

Browse files
committed
SequentialMap::erase, insert, find const, and make interface closer to std::map
1 parent 38c9c82 commit 2337414

File tree

3 files changed

+161
-11
lines changed

3 files changed

+161
-11
lines changed

tests/sequential_map_tests.cc

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#include "doctest.h"
2+
#include "util/sequential_map.hh"
3+
4+
TEST_CASE("Basic use") {
5+
6+
SequentialMap<int, float, 4> sm;
7+
8+
// Pre-conditions:
9+
CHECK(sm.size() == 0);
10+
CHECK(sm.is_full() == false);
11+
12+
// Add a value
13+
sm[2] = 3.f;
14+
CHECK(sm.size() == 1);
15+
CHECK(sm.is_full() == false);
16+
CHECK(sm.contains(2));
17+
CHECK(sm[2] == 3.f);
18+
19+
sm[9] = 99.f;
20+
CHECK(sm.size() == 2);
21+
CHECK(sm.is_full() == false);
22+
CHECK(sm.contains(9));
23+
CHECK(sm[9] == 99.f);
24+
25+
// Change a value
26+
sm[2] = 5.f;
27+
CHECK(sm.size() == 2);
28+
CHECK(sm.is_full() == false);
29+
CHECK(sm.contains(2));
30+
CHECK(sm[2] == 5.f);
31+
32+
// Fill it up
33+
sm[20] = 20.20f;
34+
CHECK(sm.size() == 3);
35+
CHECK(sm.is_full() == false);
36+
37+
sm[30] = 30.30f;
38+
CHECK(sm.size() == 4);
39+
CHECK(sm.is_full() == true);
40+
41+
// Overflow is handled by overwriting the last value added
42+
CHECK(sm.contains(30));
43+
sm[99] = 10.010f;
44+
CHECK_FALSE(sm.contains(30));
45+
CHECK(sm.contains(99));
46+
}
47+
48+
TEST_CASE("Erase") {
49+
SequentialMap<char, unsigned, 4> sm;
50+
51+
sm['a'] = 1;
52+
sm['b'] = 10;
53+
sm['c'] = 100;
54+
sm['d'] = 1000;
55+
56+
auto it_b = sm.find('b');
57+
58+
SUBCASE("Erase first") {
59+
CHECK(sm.erase('a') == 1);
60+
CHECK(sm.size() == 3);
61+
CHECK(sm.contains('a') == false);
62+
CHECK(sm.contains('b') == true);
63+
CHECK(sm.contains('c') == true);
64+
CHECK(sm.contains('d') == true);
65+
66+
// Iterator is now invalid!
67+
// This breaks with std::map
68+
CHECK_FALSE(it_b->first == 'b');
69+
CHECK_FALSE(it_b->second == 10);
70+
}
71+
72+
SUBCASE("Erase middle") {
73+
CHECK(sm.erase('b') == 1);
74+
CHECK(sm.size() == 3);
75+
CHECK(sm.contains('a') == true);
76+
CHECK(sm.contains('b') == false);
77+
CHECK(sm.contains('c') == true);
78+
CHECK(sm.contains('d') == true);
79+
}
80+
81+
SUBCASE("Erase last") {
82+
CHECK(sm.erase('d') == 1);
83+
CHECK(sm.size() == 3);
84+
CHECK(sm.contains('a') == true);
85+
CHECK(sm.contains('b') == true);
86+
CHECK(sm.contains('c') == true);
87+
CHECK(sm.contains('d') == false);
88+
89+
// Iterator is still valid
90+
CHECK(it_b->first == 'b');
91+
CHECK(it_b->second == 10);
92+
}
93+
94+
// Can still add a new one
95+
sm['e'] = 10000;
96+
CHECK(sm.contains('e'));
97+
CHECK(sm['e'] == 10000);
98+
}

util/fixed_vector.hh

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -77,7 +77,7 @@ public:
7777
return back_idx;
7878
}
7979

80-
constexpr size_t max_size() {
80+
constexpr size_t max_size() const {
8181
return MaxElements;
8282
}
8383

@@ -129,6 +129,8 @@ public:
129129
back_idx -= count;
130130
}
131131

132+
using iterator = decltype(data)::iterator;
133+
132134
auto begin() const {
133135
return data.begin();
134136
}

util/sequential_map.hh

Lines changed: 60 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,11 @@
11
#pragma once
22
#include "util/fixed_vector.hh"
3-
#include <type_traits>
43

54
template<typename KeyT, typename ValT, size_t N>
65
class SequentialMap {
76
public:
87
struct PairT {
9-
KeyT key;
8+
KeyT first;
109
ValT second;
1110
};
1211

@@ -15,54 +14,105 @@ public:
1514

1615
const ValT &operator[](const KeyT key) const {
1716
for (auto &pair : data) {
18-
if (pair.key == key)
17+
if (pair.first == key)
1918
return pair.second;
2019
}
2120
return ValT{};
2221
}
2322

2423
ValT &operator[](const KeyT key) {
2524
for (auto &pair : data) {
26-
if (pair.key == key)
25+
if (pair.first == key) {
2726
return pair.second;
27+
}
2828
}
2929

3030
auto newsize = data.push_back_for_overwrite();
3131
if (newsize == data.max_size()) {
3232
// Overflow: silently return last element
3333
newsize--;
3434
}
35+
data[newsize].first = key;
3536
return data[newsize].second;
3637
}
3738

39+
// TODO: unit tests for this
40+
std::pair<typename DataT::iterator, bool> insert(const PairT &entry) {
41+
for (auto it = data.begin(); it < data.end(); it++) {
42+
if (it->first == entry.first) {
43+
return {it, false};
44+
}
45+
}
46+
47+
auto newsize = data.push_back_for_overwrite();
48+
if (newsize == data.max_size()) {
49+
return {data.end(), false};
50+
}
51+
52+
data[newsize].first = entry.first;
53+
return {data.end() - 1, true};
54+
}
55+
56+
size_t size() const {
57+
return data.size();
58+
}
59+
60+
size_t max_size() const {
61+
return data.max_size();
62+
}
63+
3864
void clear() {
3965
data.clear();
4066
}
4167

68+
bool empty() const {
69+
return data.size() == 0;
70+
}
71+
4272
bool is_full() const {
4373
return data.size() == data.max_size();
4474
}
4575

46-
auto find(KeyT key) {
76+
// TODO: unit tests for this
77+
auto find(const KeyT &key) {
78+
for (auto it = data.begin(); it < data.end(); it++) {
79+
if (it->first == key)
80+
return it;
81+
}
82+
return data.end();
83+
}
84+
85+
// TODO: unit tests for this
86+
auto find(const KeyT &key) const {
4787
for (auto it = data.begin(); it < data.end(); it++) {
48-
if (it->key == key)
88+
if (it->first == key)
4989
return it;
5090
}
5191
return data.end();
5292
}
5393

54-
bool exists(const KeyT key) const {
94+
// Unlike std::map, this will invalidate iterators
95+
// to elements before the erased element
96+
size_t erase(const KeyT &key) {
97+
if (auto it = find(key); it != data.end()) {
98+
data.erase(it, it + 1);
99+
return 1;
100+
}
101+
return 0;
102+
}
103+
104+
bool contains(const KeyT &key) const {
55105
for (auto &pair : data) {
56-
if (pair.key == key)
106+
if (pair.first == key)
57107
return true;
58108
}
59109
return false;
60110
}
61111

62-
const auto begin() const {
112+
auto begin() const {
63113
return data.begin();
64114
}
65-
const auto end() const {
115+
auto end() const {
66116
return data.end();
67117
}
68118

0 commit comments

Comments
 (0)