Skip to content

Commit

Permalink
karm-base: Simple Set type.
Browse files Browse the repository at this point in the history
  • Loading branch information
sleepy-monax committed Apr 19, 2024
1 parent c25350e commit 7813e4c
Show file tree
Hide file tree
Showing 8 changed files with 248 additions and 25 deletions.
7 changes: 3 additions & 4 deletions src/libs/karm-base/buf.h
Original file line number Diff line number Diff line change
Expand Up @@ -27,11 +27,10 @@ struct Buf {
return buf;
}

Buf() = default;

Buf(usize cap)
Buf(usize cap = 0)
: _cap(cap) {
_buf = new Inert<T>[cap];
if (cap)
_buf = new Inert<T>[cap];
}

Buf(std::initializer_list<T> other) {
Expand Down
20 changes: 5 additions & 15 deletions src/libs/karm-base/hash.h
Original file line number Diff line number Diff line change
@@ -1,21 +1,11 @@
#pragma once

#include <karm-base/checked.h>
#include <karm-base/slice.h>
#include "checked.h"
#include "slice.h"

namespace Karm {

struct Hash {
usize _value;

constexpr explicit operator usize() const {
return _value;
}
constexpr auto operator<=>(Hash const &) const = default;
constexpr auto operator+(Hash const &o) const {
return Hash(_value + o._value + 0x9e3779b9 + (_value << 6) + (_value >> 2));
}
};
using Hash = usize;

template <typename T>
struct Hasher;
Expand All @@ -30,11 +20,11 @@ struct Hasher<Hash> {
template <>
struct Hasher<Bytes> {
static constexpr Hash hash(Bytes bytes) {
usize hash = 0;
Hash hash = 0;
for (auto &b : bytes)
hash = (1000003 * hash) ^ b;
hash ^= bytes.len();
return {hash};
return hash;
}
};

Expand Down
2 changes: 1 addition & 1 deletion src/libs/karm-base/inert.h
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,7 @@
namespace Karm {

template <typename T>
union Inert {
struct Inert {
alignas(alignof(T)) char _inner[sizeof(T)];

template <typename... Args>
Expand Down
1 change: 0 additions & 1 deletion src/libs/karm-base/map.h
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"

Expand Down
139 changes: 139 additions & 0 deletions src/libs/karm-base/set.h
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
2 changes: 1 addition & 1 deletion src/libs/karm-base/sieve.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,7 +77,7 @@ struct Sieve {
return NONE;
}

bool contains(K const &key) {
bool has(K const &key) {
return _lookup(key) != nullptr;
}

Expand Down
96 changes: 96 additions & 0 deletions src/libs/karm-base/tests/test-set.cpp
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
6 changes: 3 additions & 3 deletions src/libs/karm-base/tests/test-sieve.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,11 @@ test$("sieve-access") {

test$("sieve-contains") {
Sieve<int, int> cache{10};
expect$(not cache.contains(0));
expect$(not cache.has(0));
(void)cache.access(0, [&] {
return 0;
});
expect$(cache.contains(0));
expect$(cache.has(0));
return Ok();
}

Expand Down Expand Up @@ -66,7 +66,7 @@ test$("seive-evict") {
return 10 * 10;
});

expect$(not cache.contains(0));
expect$(not cache.has(0));
expectEq$(cache.len(), 10uz);

return Ok();
Expand Down

0 comments on commit 7813e4c

Please sign in to comment.