[Zion/Glacier] Add a HashMap to store process capabilities.
This commit is contained in:
parent
6756d25e5c
commit
6e227e1cf6
|
@ -0,0 +1,222 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "glacier/container/array.h"
|
||||
#include "glacier/container/linked_list.h"
|
||||
#include "glacier/container/pair.h"
|
||||
#include "glacier/status/error.h"
|
||||
|
||||
namespace glcr {
|
||||
|
||||
template <typename T>
|
||||
struct HashFunc {
|
||||
uint64_t operator()(const T&);
|
||||
};
|
||||
|
||||
template <>
|
||||
struct HashFunc<uint64_t> {
|
||||
uint64_t operator()(const uint64_t& value) {
|
||||
// FIXME: Write a real hash function.
|
||||
return 0xABBAABBAABBAABBA ^ value;
|
||||
}
|
||||
};
|
||||
|
||||
template <typename K, typename V, class H = HashFunc<K>>
|
||||
class HashMap {
|
||||
public:
|
||||
HashMap() = default;
|
||||
HashMap(const HashMap&) = delete;
|
||||
HashMap& operator=(const HashMap&) = delete;
|
||||
// TODO: Implement Move.
|
||||
HashMap(HashMap&&) = delete;
|
||||
HashMap& operator=(HashMap&&) = delete;
|
||||
|
||||
// Accessors.
|
||||
uint64_t size() { return size_; }
|
||||
uint64_t empty() { return size_ == 0; }
|
||||
|
||||
// Returns load as a percentage (i.e. 60 means the load is 0.6).
|
||||
//
|
||||
// If data is a zero-size array, return load as 100 so it will be flagged for
|
||||
// resize.
|
||||
// TODO: Return a double here once FPE is enabled.
|
||||
uint64_t load() {
|
||||
if (data_.size() == 0) {
|
||||
return 100;
|
||||
}
|
||||
return size_ * 100 / data_.size();
|
||||
}
|
||||
|
||||
V& at(const K&);
|
||||
const V& at(const K&) const;
|
||||
|
||||
bool Contains(const K&) const;
|
||||
|
||||
// Setters.
|
||||
[[nodiscard]] ErrorCode Insert(const K&, const V&);
|
||||
[[nodiscard]] ErrorCode Insert(K&&, V&&);
|
||||
|
||||
[[nodiscard]] ErrorCode Update(const K&, const V&);
|
||||
[[nodiscard]] ErrorCode Update(const K&, V&&);
|
||||
|
||||
[[nodiscard]] ErrorCode Delete(const K&);
|
||||
|
||||
void Resize(uint64_t new_size);
|
||||
|
||||
private:
|
||||
Array<LinkedList<Pair<K, V>>> data_;
|
||||
uint64_t size_ = 0;
|
||||
|
||||
void ResizeIfNecessary();
|
||||
};
|
||||
|
||||
template <typename K, typename V, class H>
|
||||
V& HashMap<K, V, H>::at(const K& key) {
|
||||
uint64_t hc = H()(key);
|
||||
auto& ll = data_[hc % data_.size()];
|
||||
|
||||
for (auto& pair : ll) {
|
||||
if (pair.first() == key) {
|
||||
return pair.second();
|
||||
}
|
||||
}
|
||||
// TODO: Add a failure mode here instead of constructing an object.
|
||||
ll.PushFront({key, {}});
|
||||
return ll.PeekFront().second();
|
||||
}
|
||||
|
||||
template <typename K, typename V, class H>
|
||||
const V& HashMap<K, V, H>::at(const K& key) const {
|
||||
uint64_t hc = H()(key);
|
||||
auto& ll = data_[hc % data_.size()];
|
||||
|
||||
for (auto& pair : ll) {
|
||||
if (pair.first() == key) {
|
||||
return pair.second();
|
||||
}
|
||||
}
|
||||
// TODO: Add a failure mode here instead of constructing an object.
|
||||
ll.PushFront({key, {}});
|
||||
return ll.PeekFront().second();
|
||||
}
|
||||
|
||||
template <typename K, typename V, class H>
|
||||
bool HashMap<K, V, H>::Contains(const K& key) const {
|
||||
uint64_t hc = H()(key);
|
||||
auto& ll = data_[hc % data_.size()];
|
||||
|
||||
for (auto& pair : ll) {
|
||||
if (pair.first() == key) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
template <typename K, typename V, class H>
|
||||
ErrorCode HashMap<K, V, H>::Insert(const K& key, const V& value) {
|
||||
ResizeIfNecessary();
|
||||
|
||||
uint64_t hc = H()(key);
|
||||
auto& ll = data_[hc % data_.size()];
|
||||
|
||||
for (auto& pair : ll) {
|
||||
if (pair.first() == key) {
|
||||
return ALREADY_EXISTS;
|
||||
}
|
||||
}
|
||||
ll.PushFront({Move(key), Move(value)});
|
||||
size_++;
|
||||
return OK;
|
||||
}
|
||||
|
||||
template <typename K, typename V, class H>
|
||||
ErrorCode HashMap<K, V, H>::Insert(K&& key, V&& value) {
|
||||
ResizeIfNecessary();
|
||||
|
||||
uint64_t hc = H()(key);
|
||||
auto& ll = data_[hc % data_.size()];
|
||||
|
||||
for (auto& pair : ll) {
|
||||
if (pair.first() == key) {
|
||||
return ALREADY_EXISTS;
|
||||
}
|
||||
}
|
||||
ll.PushFront({Move(key), Move(value)});
|
||||
size_++;
|
||||
return OK;
|
||||
}
|
||||
|
||||
template <typename K, typename V, class H>
|
||||
ErrorCode HashMap<K, V, H>::Update(const K& key, const V& value) {
|
||||
ResizeIfNecessary();
|
||||
|
||||
uint64_t hc = H()(key);
|
||||
auto& ll = data_[hc % data_.size()];
|
||||
|
||||
for (auto& pair : ll) {
|
||||
if (pair.first() == key) {
|
||||
pair.second() = value;
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
template <typename K, typename V, class H>
|
||||
ErrorCode HashMap<K, V, H>::Update(const K& key, V&& value) {
|
||||
ResizeIfNecessary();
|
||||
|
||||
uint64_t hc = H()(key);
|
||||
auto& ll = data_[hc % data_.size()];
|
||||
|
||||
for (auto& pair : ll) {
|
||||
if (pair.first() == key) {
|
||||
pair.second() = Move(value);
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
template <typename K, typename V, class H>
|
||||
ErrorCode HashMap<K, V, H>::Delete(const K& key) {
|
||||
uint64_t hc = H()(key);
|
||||
auto& ll = data_[hc % data_.size()];
|
||||
|
||||
for (auto& pair : ll) {
|
||||
if (pair.first() == key) {
|
||||
ll.Remove(pair);
|
||||
size_--;
|
||||
return OK;
|
||||
}
|
||||
}
|
||||
return NOT_FOUND;
|
||||
}
|
||||
|
||||
template <typename K, typename V, class H>
|
||||
void HashMap<K, V, H>::Resize(uint64_t new_size) {
|
||||
Array<LinkedList<Pair<K, V>>> new_data(new_size);
|
||||
|
||||
for (uint64_t i = 0; i < data_.size(); i++) {
|
||||
auto& ll = data_[i];
|
||||
while (!ll.empty()) {
|
||||
auto pair = ll.PopFront();
|
||||
uint64_t hc = H()(pair.first());
|
||||
new_data[hc % new_size].PushFront(Move(pair));
|
||||
}
|
||||
}
|
||||
data_ = glcr::Move(new_data);
|
||||
}
|
||||
|
||||
template <typename K, typename V, class H>
|
||||
void HashMap<K, V, H>::ResizeIfNecessary() {
|
||||
if (data_.size() == 0) {
|
||||
Resize(8);
|
||||
} else if (load() > 75) {
|
||||
Resize(data_.size() * 2);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace glcr
|
|
@ -23,6 +23,8 @@ class LinkedList {
|
|||
|
||||
T PopFront();
|
||||
|
||||
void Remove(const T& item);
|
||||
|
||||
void PushFront(const T& item);
|
||||
void PushFront(T&& item);
|
||||
|
||||
|
@ -53,7 +55,9 @@ class LinkedList {
|
|||
};
|
||||
|
||||
Iterator begin() { return {front_}; }
|
||||
const Iterator begin() const { return {front_}; }
|
||||
Iterator end() { return {nullptr}; }
|
||||
const Iterator end() const { return {nullptr}; }
|
||||
|
||||
private:
|
||||
uint64_t size_ = 0;
|
||||
|
@ -123,4 +127,21 @@ T LinkedList<T>::PopFront() {
|
|||
return Move(ret);
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
void LinkedList<T>::Remove(const T& item) {
|
||||
if (front_->item == item) {
|
||||
PopFront();
|
||||
return;
|
||||
}
|
||||
ListItem* iter = front_;
|
||||
while (iter != nullptr) {
|
||||
if (iter->next != nullptr && iter->next->item == item) {
|
||||
iter->next = iter->next->next;
|
||||
size_--;
|
||||
return;
|
||||
}
|
||||
iter = iter->next;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace glcr
|
||||
|
|
|
@ -1,14 +1,23 @@
|
|||
#pragma once
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include "glacier/memory/move.h"
|
||||
|
||||
namespace glcr {
|
||||
|
||||
template <typename T, typename U>
|
||||
class Pair {
|
||||
public:
|
||||
Pair(const T& first, const U& second) : first_(first), second_(second) {}
|
||||
Pair(T&& first, U&& second) : first_(Move(first)), second_(Move(second)) {}
|
||||
T& first() { return first_; }
|
||||
U& second() { return second_; }
|
||||
|
||||
bool operator==(const Pair& other) {
|
||||
return other.first_ == first_ && other.second_ == second_;
|
||||
}
|
||||
|
||||
private:
|
||||
T first_;
|
||||
U second_;
|
||||
|
|
|
@ -8,37 +8,26 @@ uint64_t CapabilityTable::AddExistingCapability(
|
|||
const glcr::RefPtr<Capability>& cap) {
|
||||
MutexHolder h(lock_);
|
||||
uint64_t id = next_cap_id_++;
|
||||
capabilities_.PushBack({.id = id, .cap = cap});
|
||||
if (capabilities_.Insert(id, cap) != glcr::OK) {
|
||||
panic("Reusing capability id.");
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
||||
glcr::RefPtr<Capability> CapabilityTable::GetCapability(uint64_t id) {
|
||||
MutexHolder h(lock_);
|
||||
auto iter = capabilities_.begin();
|
||||
while (iter != capabilities_.end()) {
|
||||
if (iter->cap && iter->id == id) {
|
||||
return iter->cap;
|
||||
if (!capabilities_.Contains(id)) {
|
||||
panic("Bad cap access {}", id);
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
dbgln("Bad cap access {}", id);
|
||||
dbgln("Num caps: {}", capabilities_.size());
|
||||
return {};
|
||||
return capabilities_.at(id);
|
||||
}
|
||||
|
||||
glcr::RefPtr<Capability> CapabilityTable::ReleaseCapability(uint64_t id) {
|
||||
MutexHolder h(lock_);
|
||||
auto iter = capabilities_.begin();
|
||||
while (iter != capabilities_.end()) {
|
||||
if (iter->cap && iter->id == id) {
|
||||
// FIXME: Do an actual release here.
|
||||
auto cap = iter->cap;
|
||||
iter->cap = {nullptr};
|
||||
if (!capabilities_.Contains(id)) {
|
||||
panic("Bad cap release {}", id);
|
||||
}
|
||||
auto cap = capabilities_.at(id);
|
||||
(void)capabilities_.Delete(id);
|
||||
return cap;
|
||||
}
|
||||
++iter;
|
||||
}
|
||||
dbgln("Bad cap release: {}", id);
|
||||
dbgln("Num caps: {}", capabilities_.size());
|
||||
return {};
|
||||
}
|
||||
|
|
|
@ -1,9 +1,10 @@
|
|||
#pragma once
|
||||
|
||||
#include <glacier/container/linked_list.h>
|
||||
#include <glacier/container/hash_map.h>
|
||||
#include <glacier/memory/ref_ptr.h>
|
||||
|
||||
#include "capability/capability.h"
|
||||
#include "debug/debug.h"
|
||||
#include "object/mutex.h"
|
||||
|
||||
class CapabilityTable {
|
||||
|
@ -28,12 +29,8 @@ class CapabilityTable {
|
|||
glcr::RefPtr<Mutex> lock_ = Mutex::Create();
|
||||
// TODO: Do some randomization.
|
||||
uint64_t next_cap_id_ = 0x100;
|
||||
// FIXME: use a map data structure.
|
||||
struct CapEntry {
|
||||
uint64_t id;
|
||||
glcr::RefPtr<Capability> cap;
|
||||
};
|
||||
glcr::LinkedList<CapEntry> capabilities_;
|
||||
// TODO: Consider not holding a uniqueptr here instead of a refptr?
|
||||
glcr::HashMap<uint64_t, glcr::RefPtr<Capability>> capabilities_;
|
||||
};
|
||||
|
||||
template <typename T>
|
||||
|
@ -41,7 +38,9 @@ uint64_t CapabilityTable::AddNewCapability(const glcr::RefPtr<T>& object,
|
|||
uint64_t permissions) {
|
||||
MutexHolder h(lock_);
|
||||
uint64_t id = next_cap_id_++;
|
||||
capabilities_.PushBack(
|
||||
{.id = id, .cap = MakeRefCounted<Capability>(object, permissions)});
|
||||
if (capabilities_.Insert(
|
||||
id, MakeRefCounted<Capability>(object, permissions)) != glcr::OK) {
|
||||
panic("Reusing capability id {}", id);
|
||||
}
|
||||
return id;
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue