Skip to content
Merged
Show file tree
Hide file tree
Changes from 49 commits
Commits
Show all changes
58 commits
Select commit Hold shift + click to select a range
b4580a2
Add wrapper for std::map
SerhiiMalyi Jul 10, 2025
a1b58a1
Fixes after review
SerhiiMalyi Jul 11, 2025
170144a
add kmtest submodule
ElwooD07 Jul 16, 2025
63001e4
add cmake build configuration
ElwooD07 Jul 16, 2025
ad3f8e3
make kf as static library
ElwooD07 Jul 18, 2025
613439c
fix build with STL features
ElwooD07 Jul 18, 2025
4c10758
implement tests for Hex, fix compilation and linkage
ElwooD07 Jul 21, 2025
935a393
fix _Xout_of_range logic
belyshevdenis Jul 21, 2025
5956d53
fix misspelling in Hex.h
belyshevdenis Jul 21, 2025
b1f8f69
fix parameters check in kf::Hex::decode
ElwooD07 Jul 21, 2025
31c0ec0
Merge branch 'add-cmake' of https://github.com/apriorit/kf into add-c…
ElwooD07 Jul 21, 2025
0379561
Merge branch 'map' into map-test
Jul 22, 2025
3b0039b
fix tests build and linkage
Jul 22, 2025
3f92843
implement tests for Map
Jul 22, 2025
a515987
implement tests for Map
Jul 22, 2025
18b7b07
add kfbenchmark, make benchmark for kf::Map
Jul 22, 2025
2188e4c
Merge branch 'map-test' of https://github.com/apriorit/kf into map-test
Jul 22, 2025
f7b57c2
Update kfbenchmark/pch.cpp
belyshevdenis Jul 22, 2025
20ce1a0
Update test/MapTest.cpp
belyshevdenis Jul 22, 2025
155adf6
Update include/kf/Hex.h
belyshevdenis Jul 22, 2025
bca43c8
Merge branch 'map-test' of https://github.com/apriorit/kf into map-test
Jul 22, 2025
a90f6f2
Merge branch 'map-test' of https://github.com/apriorit/kf into map-test
Jul 22, 2025
ab2d09a
move GetTickCount to the usage space
Jul 22, 2025
b4ff4ea
move GetTickCount to the usage space
Jul 22, 2025
2f95ae7
make kf project as header-only target
Jul 24, 2025
69a8388
replace gitmodules with FetchContent
Jul 24, 2025
2b0e120
Merge branch 'map-test' of https://github.com/apriorit/kf into map-test
Jul 24, 2025
5b1fefe
Merge branch 'add-cmake' into map-test
Jul 24, 2025
a6a669a
rename kfbenchmark to benchmark, fix its build
Jul 24, 2025
4003078
remove debug message
Jul 24, 2025
db986e7
Merge branch 'add-cmake' into map-test
Jul 24, 2025
7af9d5e
split generation of standalone project by CMake from simple inclusion…
belyshevdenis Jul 25, 2025
d97ce2c
update README.md and add it to the project root
belyshevdenis Jul 25, 2025
5e6a1a0
Merge branch 'add-cmake' into map-test
belyshevdenis Jul 25, 2025
4fb02b5
refactoring
belyshevdenis Jul 25, 2025
5d3249f
Merge branch 'main' into map-test
belyshevdenis Jul 25, 2025
2d301b4
Fix build with kf headers included
belyshevdenis Jul 28, 2025
32c5548
fix MapTest and MapBenchmark
belyshevdenis Jul 28, 2025
10fd12a
fix build in Release mode
belyshevdenis Jul 28, 2025
df4d496
move common CXX settings to the main CMakeLists.txt
belyshevdenis Jul 28, 2025
8a76252
fix kf/stl/new, remove extra operators
belyshevdenis Jul 29, 2025
25016e2
revert hex and test
belyshevdenis Jul 30, 2025
49ba782
remove kf-benchmark
belyshevdenis Jul 30, 2025
f77cd4e
revert CMakeLists.txt for kf.test
belyshevdenis Jul 30, 2025
bcf0ae1
fix new operator
belyshevdenis Jul 30, 2025
9b4c388
delete CMakeLists.txt for include
belyshevdenis Jul 30, 2025
db5c3ac
changes for review
belyshevdenis Jul 30, 2025
4c6139f
changes for review
belyshevdenis Jul 30, 2025
d927ae5
move BuildHelpers out of main kf project
belyshevdenis Jul 30, 2025
d6f576f
fixes for review
belyshevdenis Jul 30, 2025
39f0ae9
add more noexcept for EarlyAllocator
belyshevdenis Jul 30, 2025
3f32e00
fixes for review
belyshevdenis Jul 30, 2025
ce3e1e7
fixes for review
belyshevdenis Jul 30, 2025
d061620
delete _Xbad_alloc implementation
belyshevdenis Jul 30, 2025
77eed3a
fix _Raise_handler_impl
belyshevdenis Jul 30, 2025
23ddf7d
Merge branch 'main' into map-test
belyshevdenis Jul 31, 2025
6728e17
Clean up and fix optional access
SergiusTheBest Jul 31, 2025
6a26aed
Rename and move map to stl directory
SergiusTheBest Jul 31, 2025
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
2 changes: 1 addition & 1 deletion CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -49,4 +49,4 @@ if(${IS_TOPLEVEL_PROJECT})
endif()
endif()

# TODO: add install target
# TODO: add install target
30 changes: 19 additions & 11 deletions include/kf/EarlyAllocator.h
Original file line number Diff line number Diff line change
Expand Up @@ -24,43 +24,51 @@ namespace kf

template<class Y>
constexpr EarlyAllocator(const EarlyAllocator<Y>& other) noexcept : m_ptr(reinterpret_cast<T*>(other.m_ptr)), m_size(other.m_size)
{
}
{ }

_CONSTEXPR20_DYNALLOC ~EarlyAllocator() = default;
_CONSTEXPR20_DYNALLOC EarlyAllocator& operator=(const EarlyAllocator&) = default;
~EarlyAllocator() = default;
EarlyAllocator& operator=(const EarlyAllocator&) = default;

template<POOL_TYPE poolType>
T* initialize(const size_t count)
T* initialize(const size_t count) noexcept
{
assert(!m_ptr);
assert(!m_size);
if (m_ptr != nullptr || m_size != 0)
{
_Xinvalid_argument("m_ptr != nullptr || m_size != nullptr");
}

UNREFERENCED_PARAMETER(count);

m_size = count * sizeof(T);
m_ptr = static_cast<T*>(operator new(m_size, poolType));

return m_ptr;
}

_CONSTEXPR20_DYNALLOC void deallocate(const T* ptr, const size_t count)
void deallocate(const T* ptr, const size_t count) noexcept
{
if (ptr != m_ptr || count * sizeof(T) > m_size)
{
_Xinvalid_argument("ptr != m_ptr || count * sizeof(T) > m_size");
}

UNREFERENCED_PARAMETER(ptr);
UNREFERENCED_PARAMETER(count);

operator delete(m_ptr);
m_ptr = nullptr;
m_size = 0;
}

_NODISCARD _CONSTEXPR20_DYNALLOC T* allocate(const size_t count)
_NODISCARD T* allocate(const size_t count) noexcept
{
if (!m_ptr || count * sizeof(T) > m_size)
if (m_ptr == nullptr || count * sizeof(T) > m_size)
{
_Xinvalid_argument("!m_ptr || count * sizeof(T) > m_size");
_Xinvalid_argument("m_ptr == nullptr || count * sizeof(T) > m_size");
}

UNREFERENCED_PARAMETER(count);

return m_ptr;
}

Expand Down
166 changes: 166 additions & 0 deletions include/kf/Map.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,166 @@
#pragma once
#include <kf/MapAllocator.h>
#include <map>
#include <optional>

#if _ITERATOR_DEBUG_LEVEL > 0
#error "_ITERATOR_DEBUG_LEVEL must not be greater than 0"
#endif

namespace kf
{
template<typename KeyType, typename ValueType, POOL_TYPE poolType, typename LessComparer = std::less<KeyType>>
class Map
{
public:
using AllocatorType = MapAllocator<std::pair<const KeyType, ValueType>, poolType>;
using MapType = std::map<KeyType, ValueType, LessComparer, AllocatorType>;
using Iterator = MapType::iterator;
using ConstIterator = MapType::const_iterator;
using SizeType = MapType::size_type;

public:
Map() = default;

Map(const Map&) = delete;
Map& operator=(const Map&) = delete;

Map(Map&& other) = default;
Map& operator=(Map&& other) = default;

[[nodiscard]] NTSTATUS initialize()
{
AllocatorType allocator;
if (!allocator.initialize())
{
return STATUS_INSUFFICIENT_RESOURCES;
}

// Prepare memory for head node
if (!allocator.prepareMemory(kNodeSize))
{
return STATUS_INSUFFICIENT_RESOURCES;
}

m_internalMap = make_unique<MapType, poolType>(allocator);
if (!m_internalMap)
{
return STATUS_INSUFFICIENT_RESOURCES;
}

return STATUS_SUCCESS;
}

std::optional<std::reference_wrapper<ValueType>> operator[](KeyType&& key)
{
if (!m_internalMap->get_allocator().prepareMemory(kNodeSize))
{
return {};
}

return std::ref((*m_internalMap)[std::forward<KeyType>(key)]);
}

template <class... ValuesType>
std::optional<std::pair<Iterator, bool>> emplace(ValuesType&&... values)
{
if (!m_internalMap->get_allocator().prepareMemory(kNodeSize))
{
return {};
}

return m_internalMap->emplace(std::forward<ValuesType>(values)...);
}

[[nodiscard]] Iterator find(const KeyType& key)
{
return m_internalMap->find(key);
}

[[nodiscard]] ConstIterator find(const KeyType& key) const
{
return m_internalMap->find(key);
}

#if _HAS_CXX20
[[nodiscard]] bool contains(const KeyType& key) const
{
return m_internalMap->contains(key);
}
#endif

void clear() noexcept
{
m_internalMap->clear();
}

Iterator erase(ConstIterator where) noexcept
{
return m_internalMap->erase(where);
}

Iterator erase(ConstIterator first, ConstIterator last) noexcept
{
return m_internalMap->erase(first, last);
}

SizeType erase(const KeyType& key) noexcept
{
return m_internalMap->erase(key);
}

[[nodiscard]] Iterator begin() noexcept
{
return m_internalMap->begin();
}

[[nodiscard]] ConstIterator begin() const noexcept
{
return m_internalMap->begin();
}

[[nodiscard]] Iterator end() noexcept
{
return m_internalMap->end();
}

[[nodiscard]] ConstIterator end() const noexcept
{
return m_internalMap->end();
}

[[nodiscard]] Iterator upper_bound(const KeyType& key)
{
return m_internalMap->upper_bound(key);
}

[[nodiscard]] ConstIterator upper_bound(const KeyType& key) const
{
return m_internalMap->upper_bound(key);
}

[[nodiscard]] Iterator lower_bound(const KeyType& key)
{
return m_internalMap->lower_bound(key);
}

[[nodiscard]] ConstIterator lower_bound(const KeyType& key) const
{
return m_internalMap->lower_bound(key);
}

bool empty() const noexcept
{
return m_internalMap->empty();
}

SizeType size() const noexcept
{
return m_internalMap->size();
}

private:
static constexpr size_t kNodeSize = sizeof(MapType::_Alnode_traits::value_type);
std::unique_ptr<MapType> m_internalMap;
};
}
89 changes: 89 additions & 0 deletions include/kf/MapAllocator.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,89 @@
#pragma once
#include <kf/stl/memory>

namespace kf
{
struct AllocatorState
{
std::unique_ptr<char[]> buffer;
size_t size;
};

template<typename T, POOL_TYPE poolType>
class MapAllocator
{
public:
using value_type = T;

MapAllocator() = default;

// Needed because allocator has extra parameter for POOL_TYPE
template <typename U>
struct rebind
{
using other = MapAllocator<U, poolType>;
};

friend class MapAllocator;

template<typename U>
MapAllocator(const MapAllocator<U, poolType>& other)
: m_state(other.m_state)
{
}

[[nodiscard]] bool initialize()
{
m_state = make_shared<AllocatorState, poolType>();
return m_state != nullptr;
}

T* allocate(std::size_t n)
{
if (!m_state || !m_state->buffer)
{
return nullptr;
}

if (m_state->size < n)
{
return nullptr;
}

auto buffer = reinterpret_cast<T*>(m_state->buffer.release());
m_state->size = 0;
return buffer;
}

void deallocate(T*, std::size_t)
{
m_state->buffer.reset();
m_state->size = 0;
}

[[nodiscard]] bool prepareMemory(std::size_t size)
{
if (!m_state)
{
return false;
}

if (m_state->buffer)
{
return true;
}

m_state->buffer.reset(new(poolType) char[size]);
if (!m_state->buffer)
{
return false;
}
m_state->size = size;

return true;
}

private:
std::shared_ptr<AllocatorState> m_state;
};
}
1 change: 1 addition & 0 deletions include/kf/UString.h
Original file line number Diff line number Diff line change
Expand Up @@ -75,6 +75,7 @@ namespace kf

if (newByteLength > 0)
{
#pragma warning(suppress : 4996) // ExAllocatePoolWithTag is deprecated, use ExAllocatePool2
#pragma warning(suppress: 28160) // Must succeed pool allocations are forbidden. Allocation failures cause a system crash.
newBuffer = ::ExAllocatePoolWithTag(poolType, newByteLength, PoolTag);

Expand Down
1 change: 1 addition & 0 deletions include/kf/stl/memory
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
#pragma once
#include <memory>
#include <type_traits>
#include <kf/stl/new>
#include <kf/EarlyAllocator.h>

template<typename T, POOL_TYPE PoolType, typename... TArgs>
Expand Down
16 changes: 12 additions & 4 deletions include/kf/stl/new
Original file line number Diff line number Diff line change
Expand Up @@ -3,21 +3,22 @@
#pragma warning(push)
#pragma warning(disable : 4595) // non-member operator new or delete functions may not be declared inline

inline void* __cdecl operator new(size_t size, POOL_TYPE poolType)
inline void* __cdecl operator new(size_t size, POOL_TYPE poolType) noexcept
{
#pragma warning(suppress: 28160) // Must succeed pool allocations are forbidden. Allocation failures cause a system crash.
#pragma warning(suppress: 4996) // ExAllocatePoolWithTag is deprecated, use ExAllocatePool2
return ::ExAllocatePoolWithTag(poolType, size ? size : 1, 'n++C');
}

inline void __cdecl operator delete(void* ptr)
inline void __cdecl operator delete(void* ptr) noexcept
{
if (ptr)
{
::ExFreePoolWithTag(ptr, 'n++C');
}
}

inline void __cdecl operator delete[](void* ptr)
inline void __cdecl operator delete[](void* ptr) noexcept
{
if (ptr)
{
Expand All @@ -26,7 +27,14 @@ inline void __cdecl operator delete[](void* ptr)
}

// size-aware deallocation
inline void __cdecl operator delete(void* ptr, size_t)
inline void __cdecl operator delete(void* ptr, size_t) noexcept
{
operator delete(ptr);
}

// To avoid warning C4291: 'void *operator new(size_t,POOL_TYPE) noexcept':
// no matching operator delete found; memory will not be freed if initialization throws an exception
inline void operator delete(void* ptr, POOL_TYPE) noexcept
{
operator delete(ptr);
}
Expand Down
Loading