Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions include/gkit/core/object.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,8 @@ namespace gkit::core {
static auto create(Args&&...) noexcept -> UniqueObject; */

virtual auto class_name() const -> std::string final;
inline virtual auto class_raw_name() const -> const char* final {
return typeid(*this).name();
}
};
} // namespace gkit::core
73 changes: 5 additions & 68 deletions include/gkit/core/object_id.hpp
Original file line number Diff line number Diff line change
@@ -1,72 +1,9 @@
#pragma once

#include "gkit/core/templates/singleton.hpp"

#include <cstddef>
#include <cstdint>
#include <functional>
#include <mutex>
#include <stack>
#include <unordered_map>
#include "gkit/core/object_id.hpp"
#include "gkit/core/templates/gen_id.hpp"

namespace gkit::core {
class ObjectIdAllocator;

class ObjectId final {
friend ObjectIdAllocator;
friend std::hash<gkit::core::ObjectId>;
// defalut is invalid value
uint32_t id = 0u;
uint32_t version = 0u;

public:
ObjectId() noexcept;

public:
ObjectId(const ObjectId& other) noexcept = default;
ObjectId(ObjectId&& other) noexcept;
auto operator=(const ObjectId& other) -> ObjectId& = default;
auto operator=(ObjectId&& other) -> ObjectId& = default;

auto operator==(const ObjectId& other) const -> bool {
return this->id == other.id && this->version == other.version;
}

/**
* @brief check ObjectId is invalid
* @return bool - Both id and version are not zero.
*/
inline auto available() const -> bool { return this->id != 0 && this->version != 0; }
}; // class ObjectId

class ObjectIdAllocator final : public gkit::core::templates::Singleton<ObjectIdAllocator> {
friend gkit::core::templates::Singleton<ObjectIdAllocator>;
std::mutex id_alloc_lock{};
std::stack<uint32_t> id_pool{};
std::unordered_map<uint32_t, uint32_t> id_version{};

ObjectIdAllocator() noexcept;
~ObjectIdAllocator() = default;

public:
/**
* @brief alloc a new ObjectId instance
* @return ObjectId
*/
auto new_one() noexcept -> ObjectId;

/**
* @brief drop an ObjectId and recycle its id
* @param obj_id - which ObjectId is needed to be dropped
*/
auto drop(const ObjectId& obj_id) noexcept -> void;
}; // class ObjectIdAllocator
} // namespace gkit::core

template<>
struct std::hash<gkit::core::ObjectId> {
auto operator()(const gkit::core::ObjectId& objid) const -> std::size_t {
auto uint_hash = std::hash<uint32_t>();
return uint_hash(objid.id) ^ uint_hash(objid.version);
}
};
class ObjectIdTag;
using ObjectId = templates::GenId<ObjectIdTag>;
} // namespace gkit::core
114 changes: 114 additions & 0 deletions include/gkit/core/templates/gen_id.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,114 @@
#pragma once

#include "singleton.hpp"

#include <cstdint>
#include <mutex>
#include <stack>
#include <unordered_map>
#include <utility>

namespace gkit::core::templates {
template<class T>
class GenId {
std::uint32_t id = 0u;
std::uint32_t gen = 0u;

public:
class IdAllocator;

GenId() = default;
virtual ~GenId() = default;
GenId(const GenId<T>& other) : id(other.id), gen(other.gen) {}
GenId(GenId<T>&& other) noexcept : id(other.id), gen(other.gen) {
other.id = 0u;
other.gen = 0u;
}

auto operator=(const GenId<T>&) -> GenId<T>& = default;
auto operator=(GenId<T>&& other) noexcept -> GenId<T>& {
if (this != &other) {
this->id = other.id;
this->gen = other.gen;
other.id = 0u;
other.gen = 0u;
}

return *this;
};

inline auto operator==(const GenId<T>& other) const -> bool {
return this->id == other.id && this->gen == other.gen;
}

/**
* @brief check ObjectId is invalid
* @return bool - Both id and version are not zero.
*/
inline auto available() const -> bool { return this->id != 0 && this->gen != 0; }
inline auto properties() const -> std::pair<uint32_t, uint32_t> { return {this->id, this->gen}; }
}; // class GenId

template<class T>
class GenId<T>::IdAllocator : public Singleton<GenId<T>::IdAllocator> {
friend Singleton<GenId<T>::IdAllocator>;
std::mutex alloc_mutex{};
std::stack<uint32_t> id_pool{{1}};
std::unordered_map<uint32_t, uint32_t> id_gen_map{};

IdAllocator() noexcept = default;
~IdAllocator() noexcept = default;

public:
auto new_one() -> GenId<T>;
auto drop(const GenId<T>& dropped_id) -> void;
}; // class GenId<T>::IdAllocator

template<class T>
auto GenId<T>::IdAllocator::new_one() -> GenId<T> {
auto new_id = GenId<T>();
{
std::unique_lock alloc_locker(this->alloc_mutex);
if (this->id_pool.size() <= 1) {
// Final element in id_pool is not alloc before be called top().
// So the version of final element always is one.
new_id.id = id_pool.top()++;
new_id.gen = 1;
} else {
// version of recycle id is not always one
// and is recorded to gen map when the id is dropped.
new_id.id = id_pool.top();
id_pool.pop();
new_id.gen = ++this->id_gen_map[new_id.id];
}
}

return new_id;
}

template<class T>
auto GenId<T>::IdAllocator::drop(const GenId<T>& dropped_id) -> void {
auto old_id = dropped_id.id;
auto old_version = dropped_id.gen;

{
std::unique_lock alloc_locker(this->alloc_mutex);
this->id_pool.push(old_id);
auto version_it = this->id_gen_map.find(old_id);

// no record version ever
if (version_it == this->id_gen_map.end()) {
this->id_gen_map[old_id] = 1;
}
}
}
} // namespace gkit::core::templates

template<class T>
struct std::hash<gkit::core::templates::GenId<T>> {
auto operator()(const gkit::core::templates::GenId<T>& obj_id) const -> std::size_t {
auto uint_hash = std::hash<uint32_t>();
auto [id, version] = obj_id.properties();
return uint_hash(id) ^ uint_hash(version);
}
};
1 change: 0 additions & 1 deletion src/core/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,6 @@ set (CORE_SRC
"./reflect/serdebase.cpp"

"./log.cpp"
"./object_id.cpp"
"./object_pool.cpp"
"./object.cpp"
"./processer.cpp"
Expand Down
60 changes: 0 additions & 60 deletions src/core/object_id.cpp

This file was deleted.

2 changes: 1 addition & 1 deletion src/core/object_pool.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,7 @@ namespace gkit::core {
this->id_instance_map.erase(target_it);
delete drop_obj;

auto& id_alloc = ObjectIdAllocator::instance();
auto& id_alloc = ObjectId::IdAllocator::instance();
id_alloc.drop(drop_id);
}

Expand Down
4 changes: 2 additions & 2 deletions src/core/object_pool.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -27,9 +27,9 @@ namespace gkit::core {
auto ObjectPool::create(Args&&... args) noexcept -> std::optional<std::pair<ObjectId, Object*>> {
try {
auto* obj_ptr = new T(std::forward(args)...);
auto obj_id = ObjectIdAllocator::instance().new_one();
auto obj_id = ObjectId::IdAllocator::instance().new_one();
this->id_instance_map.emplace(obj_id, obj_ptr);
return std::make_pair(std::move(obj_id), std::move(obj_ptr));
return std::make_pair(obj_id, obj_ptr);
} catch (...) {
return std::nullopt;
}
Expand Down
Loading