-
-
Notifications
You must be signed in to change notification settings - Fork 130
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
- Loading branch information
1 parent
c25350e
commit 7813e4c
Showing
8 changed files
with
248 additions
and
25 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,6 +1,5 @@ | ||
#pragma once | ||
|
||
#include "cons.h" | ||
#include "std.h" | ||
#include "vec.h" | ||
|
||
|
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,139 @@ | ||
#pragma once | ||
|
||
#include "clamp.h" | ||
#include "hash.h" | ||
#include "inert.h" | ||
|
||
namespace Karm { | ||
|
||
template <typename T> | ||
struct Set { | ||
enum State {}; | ||
|
||
struct Slot : public Inert<T> { | ||
enum struct State : u8 { | ||
FREE, | ||
USED, | ||
DEAD, | ||
}; | ||
|
||
using enum State; | ||
State state = State::FREE; | ||
}; | ||
|
||
Slot *_slots = nullptr; | ||
usize _cap = 0; | ||
usize _len = 0; | ||
|
||
Set(usize cap = 0) : _cap(cap) { | ||
if (cap) | ||
_slots = new Slot[cap]; | ||
} | ||
|
||
~Set() { | ||
clear(); | ||
} | ||
|
||
void ensure(usize desired) { | ||
if (desired <= _cap) | ||
return; | ||
|
||
if (not _slots) { | ||
_slots = new Slot[desired]; | ||
_cap = desired; | ||
return; | ||
} | ||
|
||
auto *oldSlots = _slots; | ||
usize oldCap = _cap; | ||
|
||
_slots = new Slot[desired]; | ||
_cap = desired; | ||
_len = 0; | ||
|
||
for (usize i = 0; i < _cap; i++) | ||
_slots[i].state = Slot::FREE; | ||
|
||
for (usize i = 0; i < oldCap; i++) { | ||
if (oldSlots[i].state != Slot::USED) | ||
continue; | ||
_put(oldSlots[i].unwrap()); | ||
} | ||
|
||
delete[] oldSlots; | ||
} | ||
|
||
usize _usage() const { | ||
if (not _cap) | ||
return 100; | ||
return (_len * 100) / _cap; | ||
} | ||
|
||
void _put(T const &t) { | ||
usize i = hash(t) % _cap; | ||
while (_slots[i].state != Slot::FREE) { | ||
if (_slots[i].unwrap() == t) | ||
return; | ||
i = (i + 1) % _cap; | ||
} | ||
|
||
_slots[i].ctor(t); | ||
_slots[i].state = Slot::USED; | ||
_len++; | ||
} | ||
|
||
void put(T const &t) { | ||
if (_usage() > 80) | ||
ensure(max(_cap * 2, 16uz)); | ||
|
||
_put(t); | ||
} | ||
|
||
Slot *_lookup(T const &t) const { | ||
if (_len == 0) | ||
return nullptr; | ||
|
||
usize i = hash(t) % _cap; | ||
while (_slots[i].state != Slot::FREE) { | ||
auto &s = _slots[i]; | ||
if (s.state == Slot::USED and | ||
s.unwrap() == t) | ||
return &s; | ||
i = (i + 1) % _cap; | ||
} | ||
return nullptr; | ||
} | ||
|
||
bool has(T const &t) const { | ||
return _lookup(t); | ||
} | ||
|
||
void del(T const &t) { | ||
auto *slot = _lookup(t); | ||
if (not slot) | ||
return; | ||
|
||
slot->state = Slot::DEAD; | ||
slot->dtor(); | ||
_len--; | ||
} | ||
|
||
void clear() { | ||
if (not _slots) | ||
return; | ||
for (usize i = 0; i < _cap; i++) | ||
if (_slots[i].state == Slot::USED) | ||
_slots[i].dtor(); | ||
delete[] _slots; | ||
|
||
_slots = nullptr; | ||
_cap = 0; | ||
_len = 0; | ||
} | ||
|
||
usize len() const { | ||
return _len; | ||
} | ||
}; | ||
|
||
} // namespace Karm |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,96 @@ | ||
#include <karm-base/set.h> | ||
#include <karm-test/macros.h> | ||
|
||
namespace Karm::Base::Tests { | ||
|
||
test$("set-put") { | ||
Set<int> set{}; | ||
set.put(420); | ||
expect$(set.has(420)); | ||
|
||
return Ok(); | ||
} | ||
|
||
test$("set-remove") { | ||
Set<int> set{}; | ||
set.put(420); | ||
expect$(set.has(420)); | ||
set.del(420); | ||
expect$(not set.has(420)); | ||
|
||
return Ok(); | ||
} | ||
|
||
test$("set-clear") { | ||
Set<int> set{}; | ||
set.put(420); | ||
set.put(69); | ||
expect$(set.has(420)); | ||
expect$(set.has(69)); | ||
set.clear(); | ||
expect$(not set.has(420)); | ||
expect$(not set.has(69)); | ||
|
||
return Ok(); | ||
} | ||
|
||
test$("set-len") { | ||
Set<int> set{}; | ||
expectEq$(set.len(), 0uz); | ||
set.put(420); | ||
expectEq$(set.len(), 1uz); | ||
set.put(69); | ||
expectEq$(set.len(), 2uz); | ||
set.del(420); | ||
expectEq$(set.len(), 1uz); | ||
|
||
return Ok(); | ||
} | ||
|
||
test$("set-usage") { | ||
Set<int> set{10}; | ||
expectEq$(set._usage(), 0uz); | ||
set.put(420); | ||
expectEq$(set._usage(), 10uz); | ||
set.put(69); | ||
expectEq$(set._usage(), 20uz); | ||
set.del(420); | ||
expectEq$(set._usage(), 10uz); | ||
|
||
return Ok(); | ||
} | ||
|
||
test$("set-ensure") { | ||
Set<int> set{10}; | ||
expectEq$(set._cap, 10uz); | ||
set.ensure(20); | ||
expectEq$(set._cap, 20uz); | ||
set.ensure(10); | ||
expectEq$(set._cap, 20uz); | ||
|
||
return Ok(); | ||
} | ||
|
||
test$("set-put-collision") { | ||
Set<int> set{10}; | ||
set.put(420); | ||
set.put(69); | ||
set.put(420); | ||
expectEq$(set.len(), 2uz); | ||
|
||
return Ok(); | ||
} | ||
|
||
test$("set-put-resize") { | ||
Set<int> set{10}; | ||
for (int i = 0; i < 10; i++) { | ||
set.put(i); | ||
} | ||
expectEq$(set.len(), 10uz); | ||
set.put(420); | ||
expect$(set.has(420)); | ||
|
||
return Ok(); | ||
} | ||
|
||
} // namespace Karm::Base::Tests |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters