7171#define OK_ASSERT (x ) do { \
7272 if (!(x)) { \
7373 OK_LOG_ERROR (" %s:%d: Assertion failed: %s\n " , __FILE__, __LINE__, #x); \
74+ /* @Portability */ \
7475 __builtin_trap (); \
7576 } \
7677} while (0 )
7778#endif // OK_ASSERT
7879#else
7980#define OK_ASSERT (x )
80- #endif // OK_DEBUG
81+ #endif // OK_STRIP_ASSERTIONS
8182
83+ // NOTE(oleh): All of thsse are pretty much duplicates.
8284#define OK_VERIFY (x ) do { \
8385 if (!(x)) { \
8486 OK_LOG_ERROR (" %s:%d: Verification failed: %s\n " , __FILE__, __LINE__, #x); \
87+ /* @Portability */ \
8588 __builtin_trap (); \
8689 } \
8790} while (0 )
8891
8992#define OK_TODO () do { \
9093 OK_LOG_ERROR (" %s:%d: TODO: Not implemented\n " , __FILE__, __LINE__); \
94+ /* @Portability */ \
9195 __builtin_trap (); \
9296} while (0 )
9397
9498#define OK_TODO_MSG (msg ) do { \
9599 OK_LOG_ERROR (" %s:%d: TODO: " msg " \n " , __FILE__, __LINE__); \
100+ /* @Portability */ \
96101 __builtin_trap (); \
97102} while (0 )
98103
99104#define OK_TODO_MSG_FMT (fmt, ...) do { \
100105 OK_LOG_ERROR (" %s:%d: TODO: " fmt " \n " , __FILE__, __LINE__, __VA_ARGS__); \
106+ /* @Portability */ \
101107 __builtin_trap (); \
102108} while (0 )
103109
104110#define OK_UNUSED (arg ) (void )(arg)
105111
106112#define OK_UNREACHABLE () do { \
107113 OK_LOG_ERROR (" %s:%d: Encountered unreachable code\n " , __FILE__, __LINE__); \
114+ /* @Portability */ \
108115 __builtin_trap (); \
109116} while (0 )
110117
111118#define OK_PANIC (msg ) do { \
112119 OK_LOG_ERROR (" %s:%d: PROGRAM PANICKED: %s\n " , __FILE__, __LINE__, (msg)); \
120+ /* @Portability */ \
113121 __builtin_trap (); \
114122} while (0 )
115123
116124#define OK_PANIC_FMT (fmt, ...) do { \
117125 OK_LOG_ERROR (" %s:%d: PROGRAM PANICKED: " fmt " \n " , __FILE__, __LINE__, __VA_ARGS__); \
126+ /* @Portability */ \
118127 __builtin_trap (); \
119128} while (0 )
120129
121130#define OK_ARR_LEN (xs ) (sizeof ((xs)) / sizeof ((xs)[0 ]))
122131
123132#if defined(__unix__) || defined(__unix) || defined(__APPLE__)
124133
134+ // NOTE(oleh): No need for values here.
125135#define OK_UNIX 1
126136#define OK_WINDOWS 0
127137
130140#include < unistd.h>
131141#include < spawn.h>
132142
143+ // @Customization
133144#define OK_ALLOC_PAGE (sz ) (mmap(NULL , (sz), PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1 , 0 ))
134145#define OK_DEALLOC_PAGE (page, size ) (munmap((page), (size)))
135146#define OK_ALLOC_SMOL (sz ) (sbrk((sz)))
136147
148+ // @Customization
137149#define OK_PAGE_SIZE 4096
138150#define OK_PAGE_ALIGN OK_PAGE_SIZE
139151
151163#undef max
152164#undef min
153165
166+ // @Customization
154167#define OK_PAGE_SIZE 4096
155168#define OK_PAGE_ALIGN (64 * 1024 )
156169
170+ // @Customization
157171#define OK_ALLOC_PAGE (sz ) (VirtualAlloc(nullptr , (sz), MEM_COMMIT | MEM_RESERVE, PAGE_READWRITE))
158172#define OK_DEALLOC_PAGE (page, size ) (VirtualFree((page), 0 , MEM_RELEASE))
159173#define OK_ALLOC_SMOL (sz ) (HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, (sz)))
160174
161175#elif defined(__wasm__)
162176
177+ // NOTE(oleh): Once again, these should be empty defs.
163178#define OK_UNIX 0
164179#define OK_WINDOWS 0
165180#define OK_WASM 1
175190#elif SIZE_MAX == UINT64_MAX
176191# define OK_BITS_64
177192#else
178- # error "Could not determine architecture bit size"
193+ # error "Could not determine word size"
179194#endif // word size check
180195
181196using U8 = uint8_t ;
@@ -222,6 +237,7 @@ namespace ok {
222237# define OK_PAGE_ALIGN OK_PAGE_SIZE
223238# endif // OK_PAGE_ALIGN
224239
240+ // NOTE(oleh): This should be optional.
225241# ifndef OK_VSNPRINTF
226242# error "you have to define `OK_VSNPRINTF` when compiling with `OK_NO_STDLIB`"
227243# endif // OK_VSNPRINTF
@@ -310,6 +326,7 @@ struct Allocator {
310326 Slice<T> alloc_slice (UZ);
311327};
312328
329+ // NOTE(oleh): This should be removed in favor of temp allocator handles.
313330Allocator *temp_allocator ();
314331
315332struct FixedBufferAllocator : public Allocator {
@@ -378,6 +395,7 @@ struct ArenaAllocator : public Allocator {
378395 }
379396
380397 inline void free () {
398+ // @Leak
381399 for (Region* r = head; r != nullptr ; r = r->next ) OK_DEALLOC_PAGE (head->data , head->size );
382400 }
383401
@@ -576,6 +594,7 @@ Slice<T> Allocator::alloc_slice(UZ count) {
576594 return Slice<T>{ptr, count};
577595}
578596
597+ // NOTE(oleh): Just remove this. It's a mess.
579598template <typename T>
580599struct MultiListBase {
581600 T *items;
@@ -750,6 +769,7 @@ struct String;
750769#define OK_SV_FMT " %.*s"
751770#define OK_SV_ARG (sv ) (int )(sv).count, reinterpret_cast <const char *>((sv).data)
752771
772+ // NOTE(oleh): This needs more methods.
753773template <typename Self, typename Char>
754774struct StringBase : public ArrayBase <Self, Char> {
755775 inline bool starts_with (const char * prefix) const {
@@ -1062,20 +1082,23 @@ struct Pair {
10621082 B b;
10631083};
10641084
1085+ // NOTE(oleh): We need more hash implementations, or at least a better default.
10651086namespace hash {
10661087U64 fnv1 (StringView);
10671088};
10681089
10691090template <typename T>
10701091struct Hash {
10711092 static U64 hash (const T& value) {
1093+ // NOTE(oleh): Just make this a function, not a method.
10721094 return value.ok_hash_value ();
10731095 }
10741096};
10751097
10761098template <typename T>
10771099struct HashPtr {
10781100 HashPtr (const T* v) : value{v} {}
1101+ // @Dead
10791102 HashPtr (T* v) : value{v} {}
10801103
10811104 inline bool operator ==(const T* ptr) const {
@@ -1085,7 +1108,10 @@ struct HashPtr {
10851108 const T* value;
10861109};
10871110
1111+ // NOTE(oleh): Remove these all in favor of `ok_hash_value`.
1112+
10881113// Default hash implementations
1114+ // NOTE(oleh): Is this even needed?
10891115template <typename T>
10901116struct Hash <HashPtr<T>> {
10911117 static U64 hash (const HashPtr<T>& ptr) {
@@ -1161,14 +1187,27 @@ struct Table {
11611187
11621188 void put (const TKey& key, const TValue& value);
11631189
1164- Optional<TValue> get (const TKey& key);
1190+ // NOTE(oleh): Not sure if we need the `get_ref` methods.
1191+ // Also not sure if we shouldn't just keep the template overloads?
1192+ Optional<TValue> get (const TKey& key) const ;
1193+
11651194 template <typename K>
1166- Optional<TValue> get (const K& key);
1195+ Optional<TValue> get (const K& key) const ;
1196+
1197+ Optional<TValue&> get_ref (const TKey& key);
1198+ Optional<const TValue&> get_ref (const TKey& key) const ;
1199+
1200+ template <typename K>
1201+ Optional<TValue&> get_ref (const K& key);
1202+ template <typename K>
1203+ Optional<const TValue&> get_ref (const K& key) const ;
11671204
11681205 bool has (const TKey& key) const ;
11691206 template <typename K>
11701207 bool has (const K& key) const ;
11711208
1209+ bool remove (const TKey&);
1210+
11721211 static constexpr UZ DEFAULT_CAPACITY = 47 ;
11731212
11741213 inline void clear () {
@@ -1200,7 +1239,7 @@ struct Table {
12001239 allocator->dealloc (keys, capacity);
12011240 allocator->dealloc (values, capacity);
12021241
1203- memset (this , 0 , sizeof (this ));
1242+ memset (this , 0 , sizeof (* this ));
12041243 }
12051244
12061245 TKey* keys;
@@ -1478,7 +1517,7 @@ void Table<K, V>::put(const K& key, const V& value) {
14781517}
14791518
14801519template <typename K, typename V>
1481- Optional<V> Table<K, V>::get(const K& key) {
1520+ Optional<V> Table<K, V>::get(const K& key) const {
14821521 U64 idx = Hash<K>::hash (key) % capacity;
14831522 U64 initial_idx = idx;
14841523
@@ -1495,7 +1534,7 @@ Optional<V> Table<K, V>::get(const K& key) {
14951534
14961535template <typename TKey, typename TValue>
14971536template <typename K>
1498- Optional<TValue> Table<TKey, TValue>::get(const K& key) {
1537+ Optional<TValue> Table<TKey, TValue>::get(const K& key) const {
14991538 U64 idx = Hash<K>::hash (key) % capacity;
15001539 U64 initial_idx = idx;
15011540
@@ -1510,6 +1549,72 @@ Optional<TValue> Table<TKey, TValue>::get(const K& key) {
15101549 return Optional<TValue>::empty ();
15111550}
15121551
1552+ template <typename K, typename V>
1553+ Optional<V&> Table<K, V>::get_ref(const K& key) {
1554+ U64 idx = Hash<K>::hash (key) % capacity;
1555+ U64 initial_idx = idx;
1556+
1557+ do {
1558+ if (OK_TAB_IS_OCCUPIED (meta[idx]) && keys[idx] == key) {
1559+ return values[idx];
1560+ }
1561+
1562+ idx = (idx + 1 ) % capacity;
1563+ } while (idx != initial_idx);
1564+
1565+ return Optional<V&>::empty ();
1566+ }
1567+
1568+ template <typename K, typename V>
1569+ Optional<const V&> Table<K, V>::get_ref(const K& key) const {
1570+ U64 idx = Hash<K>::hash (key) % capacity;
1571+ U64 initial_idx = idx;
1572+
1573+ do {
1574+ if (OK_TAB_IS_OCCUPIED (meta[idx]) && keys[idx] == key) {
1575+ return values[idx];
1576+ }
1577+
1578+ idx = (idx + 1 ) % capacity;
1579+ } while (idx != initial_idx);
1580+
1581+ return Optional<const V&>::empty ();
1582+ }
1583+
1584+ template <typename TKey, typename TValue>
1585+ template <typename K>
1586+ Optional<TValue&> Table<TKey, TValue>::get_ref(const K& key) {
1587+ U64 idx = Hash<K>::hash (key) % capacity;
1588+ U64 initial_idx = idx;
1589+
1590+ do {
1591+ if (OK_TAB_IS_OCCUPIED (meta[idx]) && keys[idx] == key) {
1592+ return values[idx];
1593+ }
1594+
1595+ idx = (idx + 1 ) % capacity;
1596+ } while (idx != initial_idx);
1597+
1598+ return Optional<TValue&>::empty ();
1599+ }
1600+
1601+ template <typename TKey, typename TValue>
1602+ template <typename K>
1603+ Optional<const TValue&> Table<TKey, TValue>::get_ref(const K& key) const {
1604+ U64 idx = Hash<K>::hash (key) % capacity;
1605+ U64 initial_idx = idx;
1606+
1607+ do {
1608+ if (OK_TAB_IS_OCCUPIED (meta[idx]) && keys[idx] == key) {
1609+ return values[idx];
1610+ }
1611+
1612+ idx = (idx + 1 ) % capacity;
1613+ } while (idx != initial_idx);
1614+
1615+ return Optional<const TValue&>::empty ();
1616+ }
1617+
15131618template <typename K, typename V>
15141619bool Table<K, V>::has(const K& key) const {
15151620 U64 idx = Hash<K>::hash (key) % capacity;
@@ -1526,7 +1631,6 @@ bool Table<K, V>::has(const K& key) const {
15261631 return false ;
15271632}
15281633
1529-
15301634template <typename TKey, typename TValue>
15311635template <typename K>
15321636bool Table<TKey, TValue>::has(const K& key) const {
@@ -1544,6 +1648,16 @@ bool Table<TKey, TValue>::has(const K& key) const {
15441648 return false ;
15451649}
15461650
1651+ // NOTE(oleh): Should we call destructors here?
1652+ template <typename TKey, typename TValue>
1653+ bool Table<TKey, TValue>::remove(const TKey& key) {
1654+ U64 idx = Hash<TKey>::hash (key) % capacity;
1655+ bool result = OK_TAB_IS_OCCUPIED (meta[idx]);
1656+ if (result) --count;
1657+ meta[idx] &= ~OK_TAB_META_OCCUPIED;
1658+ return result;
1659+ }
1660+
15471661// SET IMPLEMENTATION
15481662template <typename T>
15491663Set<T> Set<T>::alloc(Allocator* a, UZ capacity) {
@@ -1715,6 +1829,7 @@ struct File {
17151829};
17161830
17171831// Procedures.
1832+ // NOTE(oleh): These should accept format strings like `std::print`.
17181833void println (const char *);
17191834void println (StringView);
17201835void println (String);
0 commit comments