From 3958fe5fd4e0256471d4a7104425b66bb4898d9d Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 16 Mar 2025 22:42:00 +0800 Subject: [PATCH 01/10] Misc fix of C++ implementation --- Sources/OpenGraph_SPI/Debug/og-debug-server.hpp | 2 +- Sources/OpenGraph_SPI/Graph/Graph.cpp | 2 +- Sources/OpenGraph_SPI/Graph/OGSubgraph.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Sources/OpenGraph_SPI/Debug/og-debug-server.hpp b/Sources/OpenGraph_SPI/Debug/og-debug-server.hpp index 8b056f8c..36b393d5 100644 --- a/Sources/OpenGraph_SPI/Debug/og-debug-server.hpp +++ b/Sources/OpenGraph_SPI/Debug/og-debug-server.hpp @@ -66,4 +66,4 @@ typedef struct OGDebugServerStorage { OG_ASSUME_NONNULL_END #endif /* OG_TARGET_OS_DARWIN */ -#endif /* og_debug_server_ hpp */ +#endif /* og_debug_server_hpp */ diff --git a/Sources/OpenGraph_SPI/Graph/Graph.cpp b/Sources/OpenGraph_SPI/Graph/Graph.cpp index d6217fce..6b1cadcb 100644 --- a/Sources/OpenGraph_SPI/Graph/Graph.cpp +++ b/Sources/OpenGraph_SPI/Graph/Graph.cpp @@ -22,7 +22,7 @@ OG::Graph::Graph() OG_NOEXCEPT { // Tracked via https://github.com/swiftwasm/swift/issues/5565 #if !OG_TARGET_OS_WASI static dispatch_once_t make_keys; - dispatch_once_f(&make_keys, nullptr, [](void *context){ + dispatch_once_f(&make_keys, nullptr, [](void * _Nullable context){ pthread_key_create(&_current_update_key, nullptr); OG::Subgraph::make_current_subgraph_key(); }); diff --git a/Sources/OpenGraph_SPI/Graph/OGSubgraph.cpp b/Sources/OpenGraph_SPI/Graph/OGSubgraph.cpp index 534f5672..c9c1476f 100644 --- a/Sources/OpenGraph_SPI/Graph/OGSubgraph.cpp +++ b/Sources/OpenGraph_SPI/Graph/OGSubgraph.cpp @@ -176,7 +176,7 @@ OGUniqueID OGSubgraphAddObserver(OGSubgraphRef cf_subgraph, static bool should_record_tree; static dispatch_once_t should_record_tree_once; -void init_should_record_tree(void *) { +void init_should_record_tree(void * _Nullable context) { should_record_tree = OG::get_env("OG_TREE") != 0; } #endif From 2cbf4e0a032356d93426efaf96b71139715c3c0c Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 16 Mar 2025 22:45:15 +0800 Subject: [PATCH 02/10] Add table implementation --- README.md | 4 + Sources/OpenGraph_SPI/Data/page.cpp | 5 ++ Sources/OpenGraph_SPI/Data/page.hpp | 36 ++++++++ Sources/OpenGraph_SPI/Data/ptr.hpp | 83 ++++++++++++++++++ Sources/OpenGraph_SPI/Data/table.cpp | 126 +++++++++++++++++++++++++++ Sources/OpenGraph_SPI/Data/table.hpp | 93 ++++++++++++++++++++ 6 files changed, 347 insertions(+) create mode 100644 Sources/OpenGraph_SPI/Data/page.cpp create mode 100644 Sources/OpenGraph_SPI/Data/page.hpp create mode 100644 Sources/OpenGraph_SPI/Data/ptr.hpp create mode 100644 Sources/OpenGraph_SPI/Data/table.cpp create mode 100644 Sources/OpenGraph_SPI/Data/table.hpp diff --git a/README.md b/README.md index 58be9580..51e9ef90 100644 --- a/README.md +++ b/README.md @@ -25,6 +25,10 @@ The project is for the following purposes: Currently, this project is in early development. +## Credits + +Part of the Graph implementation is from https://github.com/jcmosc/Compute + ## License See LICENSE file - MIT diff --git a/Sources/OpenGraph_SPI/Data/page.cpp b/Sources/OpenGraph_SPI/Data/page.cpp new file mode 100644 index 00000000..6c337001 --- /dev/null +++ b/Sources/OpenGraph_SPI/Data/page.cpp @@ -0,0 +1,5 @@ +// +// page.cpp +// OpenGraph_SPI + +#include "page.hpp" diff --git a/Sources/OpenGraph_SPI/Data/page.hpp b/Sources/OpenGraph_SPI/Data/page.hpp new file mode 100644 index 00000000..c75810fd --- /dev/null +++ b/Sources/OpenGraph_SPI/Data/page.hpp @@ -0,0 +1,36 @@ +// +// page.hpp +// OpenGraph_SPI + +#ifndef page_hpp +#define page_hpp + +#include "OGBase.h" + +namespace OG { +namespace data { + +constexpr const uint32_t page_mask_bits = 9; + +/// 0x200 +constexpr const uint32_t page_size = 1 << page_mask_bits; + +/// 0x1FF +constexpr const uint32_t page_mask = page_size - 1; + +/// 0xFFFF_FFE0 +constexpr const uintptr_t page_alignment = ~page_mask; + +class zone; + +struct page { +// zone *zone; +// ptr previous; +// uint32_t total; +// uint32_t in_use; +}; /* page */ + +} /* data */ +} /* OG */ + +#endif /* page_hpp */ diff --git a/Sources/OpenGraph_SPI/Data/ptr.hpp b/Sources/OpenGraph_SPI/Data/ptr.hpp new file mode 100644 index 00000000..9e7f3e10 --- /dev/null +++ b/Sources/OpenGraph_SPI/Data/ptr.hpp @@ -0,0 +1,83 @@ +// +// ptr.hpp +// OpenGraph_SPI +// +// Status: Complete +// Modified from https://github.com/jcmosc/Compute/blob/0a6b21a4cdeb9bbdd95e7e914c4e18bed37a2456/Sources/ComputeCxx/Data/Pointer.h [MIT License] + +#ifndef ptr_hpp +#define ptr_hpp + +#include "OGBase.h" +#include "table.hpp" +#include +#include +#include +#include "page.hpp" + +OG_ASSUME_NONNULL_BEGIN + +namespace OG { +namespace data { + +struct page; + +template class ptr { +public: + using element_type = T; + using difference_type = uint32_t; + +private: + difference_type _offset; + + template friend class ptr; + +public: + ptr(difference_type offset = 0) : _offset(offset){}; + ptr(nullptr_t){}; + + void assert_valid() const { + if (_offset >= table::shared().data_capacity()) { + precondition_failure("invalid data offset: %u", _offset); + } + } + + element_type *_Nonnull get() const noexcept { + assert(_offset != 0); + return reinterpret_cast(table::shared().data_base() + _offset); + } + + ptr page_ptr() const noexcept { return ptr(_offset & page_alignment); } + + difference_type page_relative_offset() const noexcept { return _offset & page_mask; } + + template ptr aligned(difference_type alignment_mask = sizeof(difference_type) - 1) const { + return ptr((_offset + alignment_mask) & ~alignment_mask); + }; + + operator bool() const noexcept { return _offset != 0; }; + std::add_lvalue_reference_t operator*() const noexcept { return *get(); }; + T *_Nonnull operator->() const noexcept { return get(); }; + + bool operator==(nullptr_t) const noexcept { return _offset == 0; }; + bool operator!=(nullptr_t) const noexcept { return _offset != 0; }; + + bool operator<(difference_type offset) const noexcept { return _offset < offset; }; + bool operator<=(difference_type offset) const noexcept { return _offset <= offset; }; + bool operator>(difference_type offset) const noexcept { return _offset > offset; }; + bool operator>=(difference_type offset) const noexcept { return _offset >= offset; }; + + template ptr operator+(difference_type shift) const noexcept { return ptr(_offset + shift); }; + template ptr operator-(difference_type shift) const noexcept { return ptr(_offset - shift); }; + + template difference_type operator-(const ptr &other) const noexcept { + return _offset - other._offset; + }; +}; /* ptr */ + +} /* data */ +} /* OG */ + +OG_ASSUME_NONNULL_END + +#endif /* ptr_hpp */ diff --git a/Sources/OpenGraph_SPI/Data/table.cpp b/Sources/OpenGraph_SPI/Data/table.cpp new file mode 100644 index 00000000..82594fb0 --- /dev/null +++ b/Sources/OpenGraph_SPI/Data/table.cpp @@ -0,0 +1,126 @@ +// +// table.cpp +// OpenGraph_SPI +// +// Audited for iOS 18.0 +// Status: WIP + +#include "table.hpp" +#include "page.hpp" +#include "../Util/assert.hpp" +#include +#include +#include + +void *OGGraphVMRegionBaseAddress; + +namespace OG { +namespace data { + +uint8_t _shared_table_bytes[sizeof(table) / sizeof(uint8_t)] = {}; + +malloc_zone_t *_Nullable _malloc_zone; + +void table::print() const OG_NOEXCEPT { + os_unfair_lock_lock(&_lock); + fprintf(stderr, "data::table %p:\n %.2fKB allocated, %.2fKB used, %.2fKB reusable.\n", + this, + double(_region_capacity - page_size) / 1024.0, + double(this->used_pages_num()) / 1024.0, + double(_reusable_pages_num) / 1024.0); + os_unfair_lock_unlock(&_lock); +} + +//uint64_t table::raw_page_seed(ptr page) { +// page.assert_valid(); +// +// lock(); +// +// uint32_t page_index = (page / page_size) - 1; +// uint32_t map_index = page_index / pages_per_map; +// +// uint64_t result = 0; +// if (map_index < _page_metadata_maps.size() && _page_metadata_maps[map_index].test(page_index % page_size)) { +// auto raw_zone_info = page->zone->info().to_raw_value(); +// result = raw_zone_info | (1 < 8); +// } +// +// unlock(); +// +// return result; +//} + +// dealloc_page_locked(OG::data::ptr + +// alloc_page(OG::data::zone&, unsigned int) + +// make_pages_reusable(unsigned int, bool) + +void table::grow_region() OG_NOEXCEPT { + uint32_t new_size = 4 * _region_capacity; + // Check size does not exceed 32 bits + if (new_size <= _region_capacity) { + precondition_failure("exhausted data space"); + } + void *new_region = mmap(nullptr, new_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + if (new_region == MAP_FAILED) { + precondition_failure("memory allocation failure (%u bytes, %u)", new_size, errno); + } + + vm_prot_t cur_protection = VM_PROT_NONE; + vm_prot_t max_protection = VM_PROT_NONE; + kern_return_t error = vm_remap(mach_task_self(), + reinterpret_cast(&new_region), + _region_capacity, + 0, + VM_FLAGS_OVERWRITE, + mach_task_self(), + reinterpret_cast(_region_base), + false, + &cur_protection, + &max_protection, + VM_INHERIT_NONE); + if (error) { + precondition_failure("vm_remap failure: 0x%x", error); + } + _remapped_regions.push_back({this->region_base(), this->region_capacity()}); + OGGraphVMRegionBaseAddress = new_region; + _data_base = reinterpret_cast(new_region) - page_size; + _region_base = reinterpret_cast(new_region); + _region_capacity = new_size; + _data_capacity = new_size + page_size; +} + +// FIXME +table::table() { + constexpr vm_size_t initial_size = 32 * pages_per_map * page_size; + _region_capacity = initial_size; + void *region = mmap(nullptr, initial_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + _region_base = reinterpret_cast(region); + OGGraphVMRegionBaseAddress = region; + if (region == MAP_FAILED) { + OG::precondition_failure("memory allocation failure (%u bytes, %u)", _region_capacity, errno); + } + _data_base = reinterpret_cast(region) - page_size; + _data_capacity = initial_size + page_size; + if (_malloc_zone == nullptr) { + malloc_zone_t *zone = malloc_create_zone(0, 0); + _malloc_zone = zone; + malloc_set_zone_name(zone, "OpenGraph graph data"); + } +} + +table &table::ensure_shared() { + static dispatch_once_t once; + dispatch_once_f(&once, nullptr, [](void *_Nullable context){ + new (_shared_table_bytes) table(); + }); + return shared(); +} + +table &table::shared() { return *reinterpret_cast(&_shared_table_bytes); } + +} /* data */ +} /* OG */ + +// AG::data::table::malloc_zone_deleter diff --git a/Sources/OpenGraph_SPI/Data/table.hpp b/Sources/OpenGraph_SPI/Data/table.hpp new file mode 100644 index 00000000..40c5661f --- /dev/null +++ b/Sources/OpenGraph_SPI/Data/table.hpp @@ -0,0 +1,93 @@ +// +// table.hpp +// OpenGraph_SPI + +#ifndef table_hpp +#define table_hpp + +#include "OGBase.h" +#include "../Util/vector.hpp" +#include +#include +#include + +namespace OG { +namespace data { +class zone; +class page; +template class ptr; + +class table { +public: + class malloc_zone_deleter { + }; + +public: + static table &ensure_shared(); + static table &shared(); + + table(); + + OG_INLINE OG_CONSTEXPR + vm_address_t data_base() const OG_NOEXCEPT { return _data_base; }; + + OG_INLINE OG_CONSTEXPR + vm_address_t region_base() const OG_NOEXCEPT { return _region_base; }; + + OG_INLINE OG_CONSTEXPR + void lock() const OG_NOEXCEPT { return os_unfair_lock_lock(&_lock); }; + + OG_INLINE OG_CONSTEXPR + void unlock() const OG_NOEXCEPT { return os_unfair_lock_unlock(&_lock); }; + + OG_INLINE OG_CONSTEXPR + uint32_t region_capacity() const OG_NOEXCEPT { return _region_capacity; }; + + OG_INLINE OG_CONSTEXPR + uint32_t data_capacity() const OG_NOEXCEPT { return _data_capacity; }; + + OG_INLINE OG_CONSTEXPR + uint32_t used_pages_num() const OG_NOEXCEPT { return _used_pages_num; }; + + OG_INLINE OG_CONSTEXPR + uint32_t reusable_pages_num() const OG_NOEXCEPT { return _reusable_pages_num; }; + + void print() const OG_NOEXCEPT; + + void grow_region() OG_NOEXCEPT; + +private: + /// _region_base - page_size + vm_address_t _data_base; + + vm_address_t _region_base; + + mutable os_unfair_lock _lock = OS_UNFAIR_LOCK_INIT; + + uint32_t _region_capacity; + + /// _region_capactiy + page_size + uint32_t _data_capacity; + + uint32_t _used_pages_num = 0; + + uint32_t _reusable_pages_num = 0; + + uint32_t _map_search_start = 0; + + uint32_t _zones_num = 0; + + using remapped_region = std::pair; + vector _remapped_regions = {}; +// + constexpr static unsigned int pages_per_map = 64; +// using page_map_type = std::bitset; +// vector _page_maps = {}; +// vector _page_metadata_maps = {}; + +}; /* table */ + +} /* data */ +} /* OG */ + +#endif /* table_hpp */ From eef742d051eb4993a319dd85b542a5b39af34ac5 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 16 Mar 2025 23:59:30 +0800 Subject: [PATCH 03/10] Update vector implementation --- Package.swift | 2 +- Sources/OpenGraph_SPI/Data/table.hpp | 2 +- .../OpenGraph_SPI/Debug/og-debug-server.hpp | 2 +- .../OpenGraph_SPI/Debug/og-debug-server.mm | 6 +- Sources/OpenGraph_SPI/Util/vector.hpp | 159 --------- Sources/OpenGraph_SPI/Util/wrap_iter.hpp | 232 ------------- Sources/OpenGraph_SPI/Vector/vector.hpp | 240 +++++++++++++ Sources/OpenGraph_SPI/Vector/vector.tpp | 315 ++++++++++++++++++ 8 files changed, 562 insertions(+), 396 deletions(-) delete mode 100644 Sources/OpenGraph_SPI/Util/vector.hpp delete mode 100644 Sources/OpenGraph_SPI/Util/wrap_iter.hpp create mode 100644 Sources/OpenGraph_SPI/Vector/vector.hpp create mode 100644 Sources/OpenGraph_SPI/Vector/vector.tpp diff --git a/Package.swift b/Package.swift index d25a0873..20111acf 100644 --- a/Package.swift +++ b/Package.swift @@ -189,7 +189,7 @@ let package = Package( openGraphCompatibilityTestTarget, openGraphSPICompatibilityTestTarget, ], - cxxLanguageStandard: .cxx17 + cxxLanguageStandard: .cxx20 ) diff --git a/Sources/OpenGraph_SPI/Data/table.hpp b/Sources/OpenGraph_SPI/Data/table.hpp index 40c5661f..dc7bc4a3 100644 --- a/Sources/OpenGraph_SPI/Data/table.hpp +++ b/Sources/OpenGraph_SPI/Data/table.hpp @@ -6,7 +6,7 @@ #define table_hpp #include "OGBase.h" -#include "../Util/vector.hpp" +#include "../Vector/vector.hpp" #include #include #include diff --git a/Sources/OpenGraph_SPI/Debug/og-debug-server.hpp b/Sources/OpenGraph_SPI/Debug/og-debug-server.hpp index 36b393d5..f0522912 100644 --- a/Sources/OpenGraph_SPI/Debug/og-debug-server.hpp +++ b/Sources/OpenGraph_SPI/Debug/og-debug-server.hpp @@ -11,7 +11,7 @@ #include "OGBase.h" #if OG_TARGET_OS_DARWIN #include "OGDebugServer.h" -#include "../Util/vector.hpp" +#include "../Vector/vector.hpp" #include #include diff --git a/Sources/OpenGraph_SPI/Debug/og-debug-server.mm b/Sources/OpenGraph_SPI/Debug/og-debug-server.mm index ef61f96e..b6d73275 100644 --- a/Sources/OpenGraph_SPI/Debug/og-debug-server.mm +++ b/Sources/OpenGraph_SPI/Debug/og-debug-server.mm @@ -165,7 +165,8 @@ return; } fcntl(server->sockfd, F_SETFD, O_WRONLY); - server->connections.push_back(std::unique_ptr(new Connection(server, sockfd))); + // FIXME: Link issue about vector + // server->connections.push_back(std::unique_ptr(new Connection(server, sockfd))); } CFURLRef _Nullable OG::DebugServer::copy_url() const { @@ -225,7 +226,8 @@ auto it = connections.begin(); for (; it != connections.end(); it++) { if (it->get() == connection) { - connections.pop_back(); + // FIXME: Link issue about vector + // connections.pop_back(); return; } } diff --git a/Sources/OpenGraph_SPI/Util/vector.hpp b/Sources/OpenGraph_SPI/Util/vector.hpp deleted file mode 100644 index 78ee7625..00000000 --- a/Sources/OpenGraph_SPI/Util/vector.hpp +++ /dev/null @@ -1,159 +0,0 @@ -// -// vector.hpp -// -// -// Created by Kyle on 2024/1/15. -// - -#ifndef vector_hpp -#define vector_hpp - -#include "OGBase.h" -#include "wrap_iter.hpp" -#include "realloc_vector.hpp" -#include -#include - -namespace OG { -template -class vector final { -private: - typedef std::allocator<_Tp> __default_allocator_type; -public: - typedef vector __self; - typedef _Tp value_type; - typedef __default_allocator_type allocator_type; - typedef std::allocator_traits __alloc_traits; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef typename __alloc_traits::size_type size_type; - typedef typename __alloc_traits::difference_type difference_type; - typedef typename __alloc_traits::pointer pointer; - typedef typename __alloc_traits::const_pointer const_pointer; - typedef OG::details::__wrap_iter iterator; - typedef OG::details::__wrap_iter const_iterator; - typedef std::reverse_iterator reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; - - OG_CONSTEXPR void push_back(const_reference __x); - OG_CONSTEXPR void push_back(value_type&& __x); - OG_CONSTEXPR void pop_back(); - - OG_CONSTEXPR const_iterator begin() const OG_NOEXCEPT; - OG_CONSTEXPR const_iterator end() const OG_NOEXCEPT; -private: - // TODO - static OG_CONSTEXPR size_type stack_buffer_byte_size = 0; - - uint8_t _stack_buffer[stack_buffer_byte_size] = {0}; - pointer _buffer; - size_type _count = 0; - size_type _capacity = 0; -}; - -template -OG_CONSTEXPR OG_INLINE void -OG::vector<_Tp, size, _SizeType>::push_back(const_reference __x) -{ - // TODO -} - -template -OG_CONSTEXPR OG_INLINE void -OG::vector<_Tp, size, _SizeType>::push_back(value_type&& __x) -{ - // TODO -} - -template -OG_CONSTEXPR OG_INLINE void -OG::vector<_Tp, size, _SizeType>::pop_back() -{ - // TODO -} - -template -OG_CONSTEXPR OG_INLINE -typename OG::vector<_Tp, size, _SizeType>::const_iterator OG::vector<_Tp, size, _SizeType>::begin() const OG_NOEXCEPT -{ - // TODO -} - -template -OG_CONSTEXPR OG_INLINE -typename OG::vector<_Tp, size, _SizeType>::const_iterator OG::vector<_Tp, size, _SizeType>::end() const OG_NOEXCEPT -{ - // TODO -} - -// MARK: size = 0 - -template -class vector<_Tp, 0, _SizeType> final { -private: - typedef std::allocator<_Tp> __default_allocator_type; -public: - typedef vector __self; - typedef _Tp value_type; - typedef __default_allocator_type allocator_type; - typedef std::allocator_traits __alloc_traits; - typedef value_type& reference; - typedef const value_type& const_reference; - typedef typename __alloc_traits::size_type size_type; - typedef typename __alloc_traits::difference_type difference_type; - typedef typename __alloc_traits::pointer pointer; - typedef typename __alloc_traits::const_pointer const_pointer; - typedef OG::details::__wrap_iter iterator; - typedef OG::details::__wrap_iter const_iterator; - typedef std::reverse_iterator reverse_iterator; - typedef std::reverse_iterator const_reverse_iterator; - - OG_CONSTEXPR void push_back(const_reference __x); - OG_CONSTEXPR void push_back(value_type&& __x); - OG_CONSTEXPR void pop_back(); - - OG_CONSTEXPR const_iterator begin() const OG_NOEXCEPT; - OG_CONSTEXPR const_iterator end() const OG_NOEXCEPT; -private: - pointer _buffer = nullptr; - size_type _count = 0; - size_type _capacity = 0; -}; - -template -OG_CONSTEXPR OG_INLINE void -OG::vector<_Tp, 0, _SizeType>::push_back(const_reference __x) -{ - // TODO -} - -template -OG_CONSTEXPR OG_INLINE void -OG::vector<_Tp, 0, _SizeType>::push_back(value_type&& __x) -{ - // TODO -} - -template -OG_CONSTEXPR OG_INLINE void -OG::vector<_Tp, 0, _SizeType>::pop_back() -{ - // TODO -} - -template -OG_CONSTEXPR OG_INLINE -typename OG::vector<_Tp, 0, _SizeType>::const_iterator OG::vector<_Tp, 0, _SizeType>::begin() const OG_NOEXCEPT -{ - // TODO -} - -template -OG_CONSTEXPR OG_INLINE -typename OG::vector<_Tp, 0, _SizeType>::const_iterator OG::vector<_Tp, 0, _SizeType>::end() const OG_NOEXCEPT -{ - // TODO -} - -} -#endif /* vector_hpp */ diff --git a/Sources/OpenGraph_SPI/Util/wrap_iter.hpp b/Sources/OpenGraph_SPI/Util/wrap_iter.hpp deleted file mode 100644 index 3cbb4332..00000000 --- a/Sources/OpenGraph_SPI/Util/wrap_iter.hpp +++ /dev/null @@ -1,232 +0,0 @@ -// -// wrap_iter.hpp -// -// -// Created by Kyle on 2024/1/17. -// - -#ifndef wrap_iter_hpp -#define wrap_iter_hpp - -#include -#include - -namespace OG { -template -class vector; - -namespace details { - -// LLVM-Project wrap_iter.h -// release/17.0.6 + 6009708b4367171ccdbf4b5905cb6a803753fe18 - -// -*- C++ -*- -//===----------------------------------------------------------------------===// -// -// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. -// See https://llvm.org/LICENSE.txt for license information. -// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception -// -//===----------------------------------------------------------------------===// - -template -class __wrap_iter -{ -public: - typedef _Iter iterator_type; - typedef typename std::iterator_traits::value_type value_type; - typedef typename std::iterator_traits::difference_type difference_type; - typedef typename std::iterator_traits::pointer pointer; - typedef typename std::iterator_traits::reference reference; - typedef typename std::iterator_traits::iterator_category iterator_category; -#if _LIBCPP_STD_VER >= 20 - typedef contiguous_iterator_tag iterator_concept; -#endif - -private: - iterator_type __i_; -public: - OG_CONSTEXPR __wrap_iter() OG_NOEXCEPT - : __i_() - { - } - template OG_CONSTEXPR - __wrap_iter(const __wrap_iter<_Up>& __u, - typename std::enable_if::value>::type* = nullptr) OG_NOEXCEPT - : __i_(__u.base()) - { - } - OG_CONSTEXPR reference operator*() const OG_NOEXCEPT - { - return *__i_; - } - OG_CONSTEXPR pointer operator->() const OG_NOEXCEPT - { - return std::__to_address(__i_); - } - OG_CONSTEXPR __wrap_iter& operator++() OG_NOEXCEPT - { - ++__i_; - return *this; - } - OG_CONSTEXPR __wrap_iter operator++(int) OG_NOEXCEPT - {__wrap_iter __tmp(*this); ++(*this); return __tmp;} - - OG_CONSTEXPR __wrap_iter& operator--() OG_NOEXCEPT - { - --__i_; - return *this; - } - OG_CONSTEXPR __wrap_iter operator--(int) OG_NOEXCEPT - {__wrap_iter __tmp(*this); --(*this); return __tmp;} - OG_CONSTEXPR __wrap_iter operator+ (difference_type __n) const OG_NOEXCEPT - {__wrap_iter __w(*this); __w += __n; return __w;} - OG_CONSTEXPR __wrap_iter& operator+=(difference_type __n) OG_NOEXCEPT - { - __i_ += __n; - return *this; - } - OG_CONSTEXPR __wrap_iter operator- (difference_type __n) const OG_NOEXCEPT - {return *this + (-__n);} - OG_CONSTEXPR __wrap_iter& operator-=(difference_type __n) OG_NOEXCEPT - {*this += -__n; return *this;} - OG_CONSTEXPR reference operator[](difference_type __n) const OG_NOEXCEPT - { - return __i_[__n]; - } - - OG_CONSTEXPR iterator_type base() const OG_NOEXCEPT {return __i_;} - -private: - OG_CONSTEXPR - explicit __wrap_iter(iterator_type __x) OG_NOEXCEPT : __i_(__x) - { - } - - template friend class __wrap_iter; - template - friend class OG::vector; -}; - -template -OG_CONSTEXPR -bool operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) OG_NOEXCEPT -{ - return __x.base() == __y.base(); -} - -template -OG_CONSTEXPR -bool operator==(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) OG_NOEXCEPT -{ - return __x.base() == __y.base(); -} - -template -OG_CONSTEXPR -bool operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) OG_NOEXCEPT -{ - return __x.base() < __y.base(); -} - -template -OG_CONSTEXPR -bool operator<(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) OG_NOEXCEPT -{ - return __x.base() < __y.base(); -} - -template -OG_CONSTEXPR -bool operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) OG_NOEXCEPT -{ - return !(__x == __y); -} - -template -OG_CONSTEXPR -bool operator!=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) OG_NOEXCEPT -{ - return !(__x == __y); -} - -template -OG_CONSTEXPR -bool operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) OG_NOEXCEPT -{ - return __y < __x; -} - -template -OG_CONSTEXPR -bool operator>(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) OG_NOEXCEPT -{ - return __y < __x; -} - -template -OG_CONSTEXPR -bool operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) OG_NOEXCEPT -{ - return !(__x < __y); -} - -template -OG_CONSTEXPR -bool operator>=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) OG_NOEXCEPT -{ - return !(__x < __y); -} - -template -OG_CONSTEXPR -bool operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter1>& __y) OG_NOEXCEPT -{ - return !(__y < __x); -} - -template -OG_CONSTEXPR -bool operator<=(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) OG_NOEXCEPT -{ - return !(__y < __x); -} - -template -OG_CONSTEXPR -#ifndef _LIBCPP_CXX03_LANG -auto operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) OG_NOEXCEPT - -> decltype(__x.base() - __y.base()) -#else -typename __wrap_iter<_Iter1>::difference_type -operator-(const __wrap_iter<_Iter1>& __x, const __wrap_iter<_Iter2>& __y) OG_NOEXCEPT -#endif // C++03 -{ - return __x.base() - __y.base(); -} - -template -OG_CONSTEXPR -__wrap_iter<_Iter1> operator+(typename __wrap_iter<_Iter1>::difference_type __n, __wrap_iter<_Iter1> __x) OG_NOEXCEPT -{ - __x += __n; - return __x; -} -} /* detail */ -} /* OG */ - -namespace std { -template -struct std::pointer_traits > -{ - typedef OG::details::__wrap_iter<_It> pointer; - typedef typename pointer_traits<_It>::element_type element_type; - typedef typename pointer_traits<_It>::difference_type difference_type; - - OG_CONSTEXPR - static element_type *to_address(pointer __w) OG_NOEXCEPT { - return std::__to_address(__w.base()); - } -}; -} /* std */ -#endif /* wrap_iter_hpp */ diff --git a/Sources/OpenGraph_SPI/Vector/vector.hpp b/Sources/OpenGraph_SPI/Vector/vector.hpp new file mode 100644 index 00000000..161c6968 --- /dev/null +++ b/Sources/OpenGraph_SPI/Vector/vector.hpp @@ -0,0 +1,240 @@ +// +// vector.hpp +// OpenGraph_SPI +// +// Status: Complete +// Modified from https://github.com/jcmosc/Compute/blob/00dfebc2c5852144ac5aada8ebe896b78e5f622a/Sources/ComputeCxx/Vector/Vector.h [MIT License] + +#ifndef vector_hpp +#define vector_hpp + +#include "OGBase.h" +#include +#include +#include + +OG_ASSUME_NONNULL_BEGIN + +namespace OG { + +template + requires std::unsigned_integral +class vector { + private: + T _stack_buffer[_stack_size]; + T *_Nullable _buffer = nullptr; + size_type _size = 0; + size_type _capacity = _stack_size; + + void reserve_slow(size_type new_cap); + + public: + using value_type = T; + using reference = value_type &; + using const_reference = const value_type &; + using iterator = value_type *_Nonnull; + using const_iterator = const value_type *_Nonnull; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + ~vector(); + + // Element access + + reference operator[](size_type pos) { return data()[pos]; }; + const_reference operator[](size_type pos) const { return data()[pos]; }; + + reference front() { return &data()[0]; }; + const_reference front() const { return *&data()[0]; }; + reference back() { return *&data()[_size - 1]; }; + const_reference back() const { return *&data()[_size - 1]; }; + + T *_Nonnull data() { return _buffer != nullptr ? _buffer : _stack_buffer; }; + const T *_Nonnull data() const { return _buffer != nullptr ? _buffer : _stack_buffer; }; + + // Iterators + + iterator begin() { return iterator(&data()[0]); }; + const_iterator cbegin() const { return const_iterator(&data()[0]); }; + iterator end() { return iterator(&data()[_size]); }; + const_iterator cend() const { return const_iterator(&data()[_size]); }; + + reverse_iterator rbegin() { return std::reverse_iterator(end()); }; + const_reverse_iterator crbegin() const { return std::reverse_iterator(cend()); }; + reverse_iterator rend() { return std::reverse_iterator(begin()); }; + const_reverse_iterator crend() const { return std::reverse_iterator(cbegin()); }; + + // Capacity + + bool empty() const { return _size == 0; }; + size_type size() const { return _size; }; + void reserve(size_type new_cap); + size_type capacity() const { return _capacity; }; + void shrink_to_fit(); + + // Modifiers + + void clear(); + + void push_back(const T &value); + void push_back(T &&value); + void pop_back(); + + void resize(size_type count); + void resize(size_type count, const value_type &value); +}; + +static_assert(std::contiguous_iterator::iterator>); +static_assert(std::contiguous_iterator::const_iterator>); + +// MARK: Specialization for empty stack buffer + +template + requires std::unsigned_integral +class vector { + private: + T *_Nullable _buffer = nullptr; + size_type _size = 0; + size_type _capacity = 0; + + void reserve_slow(size_type new_cap); + + public: + using value_type = T; + using reference = value_type &; + using const_reference = const value_type &; + using iterator = value_type *_Nonnull; + using const_iterator = const value_type *_Nonnull; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + ~vector(); + + // Element access + + reference operator[](size_type pos) { return data()[pos]; }; + const_reference operator[](size_type pos) const { return data()[pos]; }; + + reference front() { return &data()[0]; }; + const_reference front() const { return *&data()[0]; }; + reference back() { return *&data()[_size - 1]; }; + const_reference back() const { return *&data()[_size - 1]; }; + + T *_Nonnull data() { return _buffer; }; + const T *_Nonnull data() const { return _buffer; }; + + // Iterators + + iterator begin() { return iterator(&data()[0]); }; + iterator end() { return iterator(&data()[_size]); }; + const_iterator cbegin() const { return const_iterator(&data()[0]); }; + const_iterator cend() const { return const_iterator(&data()[_size]); }; + const_iterator begin() const { return cbegin(); }; + const_iterator end() const { return cend(); }; + + reverse_iterator rbegin() { return std::reverse_iterator(end()); }; + reverse_iterator rend() { return std::reverse_iterator(begin()); }; + const_reverse_iterator crbegin() const { return std::reverse_iterator(cend()); }; + const_reverse_iterator crend() const { return std::reverse_iterator(cbegin()); }; + const_reverse_iterator rbegin() const { return crbegin(); }; + const_reverse_iterator rend() const { return crend(); }; + + // Capacity + + bool empty() const { return _size == 0; }; + size_type size() const { return _size; }; + void reserve(size_type new_cap); + size_type capacity() const { return _capacity; }; + void shrink_to_fit(); + + // Modifiers + + void clear(); + + void push_back(const T &value); + void push_back(T &&value); + void pop_back(); + + void resize(size_type count); + void resize(size_type count, const value_type &value); +}; + +// MARK: Specialization for unique_ptr + +template + requires std::unsigned_integral +class vector, 0, size_type> { + private: + std::unique_ptr *_Nullable _buffer = nullptr; + size_type _size = 0; + size_type _capacity = 0; + + void reserve_slow(size_type new_cap); + + public: + using value_type = std::unique_ptr; + using reference = value_type &; + using const_reference = const value_type &; + using iterator = value_type *_Nonnull; + using const_iterator = const value_type *_Nonnull; + using reverse_iterator = std::reverse_iterator; + using const_reverse_iterator = std::reverse_iterator; + + ~vector(); + + // Element access + + reference operator[](size_type pos) { return data()[pos]; }; + const_reference operator[](size_type pos) const { return data()[pos]; }; + + reference front() { return &data()[0]; }; + const_reference front() const { return *&data()[0]; }; + reference back() { return *&data()[_size - 1]; }; + const_reference back() const { return *&data()[_size - 1]; }; + + std::unique_ptr *_Nonnull data() { return _buffer; }; + const std::unique_ptr *_Nonnull data() const { return _buffer; }; + + // Iterators + + iterator begin() { return iterator(&data()[0]); }; + iterator end() { return iterator(&data()[_size]); }; + const_iterator cbegin() const { return const_iterator(&data()[0]); }; + const_iterator cend() const { return const_iterator(&data()[_size]); }; + const_iterator begin() const { return cbegin(); }; + const_iterator end() const { return cend(); }; + + reverse_iterator rbegin() { return std::reverse_iterator(end()); }; + reverse_iterator rend() { return std::reverse_iterator(begin()); }; + const_reverse_iterator crbegin() const { return std::reverse_iterator(cend()); }; + const_reverse_iterator crend() const { return std::reverse_iterator(cbegin()); }; + const_reverse_iterator rbegin() const { return crbegin(); }; + const_reverse_iterator rend() const { return crend(); }; + + // Capacity + + bool empty() const { return _size == 0; }; + size_type size() const { return _size; }; + void reserve(size_type new_cap); + size_type capacity() const { return _capacity; }; + void shrink_to_fit(); + + // Modifiers + + void clear(); + + void push_back(const std::unique_ptr &value) = delete; + void push_back(std::unique_ptr &&value); + void pop_back(); + + void resize(size_type count); + void resize(size_type count, const value_type &value); +}; + +} /* OG */ + +OG_ASSUME_NONNULL_END + +#include "vector.tpp" + +#endif /* vector.hpp */ diff --git a/Sources/OpenGraph_SPI/Vector/vector.tpp b/Sources/OpenGraph_SPI/Vector/vector.tpp new file mode 100644 index 00000000..929ec39b --- /dev/null +++ b/Sources/OpenGraph_SPI/Vector/vector.tpp @@ -0,0 +1,315 @@ +// +// vector.hpp +// OpenGraph_SPI +// +// Status: Complete +// Modified from https://github.com/jcmosc/Compute/blob/00dfebc2c5852144ac5aada8ebe896b78e5f622a/Sources/ComputeCxx/Vector/Vector.tpp [MIT Lisence] + +#include "vector.hpp" +#include "../Util/assert.hpp" + +#include +#include +#include +#include + + +namespace OG { + +#pragma mark - Base implementation + +namespace details { + +template + requires std::unsigned_integral +void *realloc_vector(void *buffer, void *stack_buffer, size_type stack_size, size_type *size, + size_type preferred_new_size) { + // copy data from heap buffer buffer into stack buffer if possible + if (preferred_new_size <= stack_size) { + if (buffer) { + memcpy(stack_buffer, buffer, preferred_new_size * element_size_bytes); + free(buffer); + *size = stack_size; + } + return nullptr; + } + + size_t new_size_bytes = malloc_good_size(preferred_new_size * element_size_bytes); + size_type new_size = new_size_bytes / element_size_bytes; + if (new_size == *size) { + // nothing to do + return buffer; + } + + void *new_buffer = realloc(buffer, new_size_bytes); + if (!new_buffer) { + precondition_failure("allocation failure"); + } + + // copy data from stack buffer into heap buffer + if (!buffer) { + memcpy(new_buffer, stack_buffer, (*size) * element_size_bytes); + } + + *size = new_size; + return new_buffer; +} + +} // namespace details + +template + requires std::unsigned_integral +vector::~vector() { + for (auto i = 0; i < _size; i++) { + data()[i].~T(); + } + if (_buffer) { + free(_buffer); + } +} + +template + requires std::unsigned_integral +void vector::reserve_slow(size_type new_cap) { + size_type effective_new_cap = std::max(capacity() * 1.5, new_cap * 1.0); + _buffer = reinterpret_cast(details::realloc_vector(_buffer, _stack_buffer, _stack_size, + &_capacity, effective_new_cap)); +} + +template + requires std::unsigned_integral +void vector::reserve(size_type new_cap) { + if (new_cap <= capacity()) { + return; + } + reserve_slow(new_cap); +} + +template + requires std::unsigned_integral +void vector::shrink_to_fit() { + if (capacity() > _size) { + _buffer = reinterpret_cast( + details::realloc_vector(_buffer, _stack_buffer, _stack_size, &_capacity, _size)); + } +} + +template + requires std::unsigned_integral +void vector::clear() { + for (auto i = 0; i < _size; i++) { + data()[i].~T(); + } + _size = 0; +} + +template + requires std::unsigned_integral +void vector::push_back(const T &value) { + reserve(_size + 1); + new (&data()[_size]) value_type(value); + _size += 1; +} + +template + requires std::unsigned_integral +void vector::push_back(T &&value) { + reserve(_size + 1); + new (&data()[_size]) value_type(std::move(value)); + _size += 1; +} + +template + requires std::unsigned_integral +void vector::pop_back() { + assert(size() > 0); + data()[_size - 1].~T(); + _size -= 1; +} + +template + requires std::unsigned_integral +void vector::resize(size_type count) { + reserve(count); + if (count < _size) { + for (auto i = count; i < _size; i++) { + data()[i].~T(); + } + } else if (count > _size) { + for (auto i = _size; i < count; i++) { + new (this[i]) value_type(); + } + } + _size = count; +} + +template + requires std::unsigned_integral +void vector::resize(size_type count, const value_type &value) { + reserve(count); + if (count < _size) { + for (auto i = count; i < _size; i++) { + data()[i].~T(); + } + } else if (count > _size) { + for (auto i = _size; i < count; i++) { + new (this[i]) value_type(value); + } + } + _size = count; +} + +#pragma mark - Specialization for empty stack buffer + +namespace details { + +template + requires std::unsigned_integral +void *realloc_vector(void *buffer, size_type *size, size_type preferred_new_size) { + if (preferred_new_size == 0) { + *size = 0; + free(buffer); + return nullptr; + } + + size_t new_size_bytes = malloc_good_size(preferred_new_size * element_size); + size_type new_size = (size_type)(new_size_bytes / element_size); + if (new_size == *size) { + // nothing to do + return buffer; + } + + void *new_buffer = realloc(buffer, new_size_bytes); + if (!new_buffer) { + precondition_failure("allocation failure"); + } + *size = new_size; + return new_buffer; +} + +} // namespace details + +template + requires std::unsigned_integral +vector::~vector() { + for (auto i = 0; i < _size; i++) { + _buffer[i].~T(); + } + if (_buffer) { + free(_buffer); + } +} + +template + requires std::unsigned_integral +void vector::reserve_slow(size_type new_cap) { + size_type effective_new_cap = std::max(capacity() * 1.5, new_cap * 1.0); + _buffer = + reinterpret_cast(details::realloc_vector(_buffer, &_capacity, effective_new_cap)); +} + +template + requires std::unsigned_integral +void vector::reserve(size_type new_cap) { + if (new_cap <= capacity()) { + return; + } + reserve_slow(new_cap); +} + +template +requires std::unsigned_integral +void vector::shrink_to_fit() { + if (capacity() > size()) { + _buffer = + reinterpret_cast(details::realloc_vector(_buffer, &_capacity, 0)); + } +} + +template + requires std::unsigned_integral +void vector::clear() { + for (auto i = 0; i < _size; i++) { + data()[i].~T(); + } + _size = 0; +} + +template + requires std::unsigned_integral +void vector::push_back(const T &value) { + reserve(_size + 1); + new (&_buffer[_size]) value_type(value); + _size += 1; +} + +template + requires std::unsigned_integral +void vector::push_back(T &&value) { + reserve(_size + 1); + new (&_buffer[_size]) value_type(std::move(value)); + _size += 1; +} + +template + requires std::unsigned_integral +void vector::pop_back() { + assert(size() > 0); + data()[_size - 1].~T(); + _size -= 1; +} + +template + requires std::unsigned_integral +void vector::resize(size_type count) { + reserve(count); + if (count < _size) { + for (auto i = count; i < _size; i++) { + data()[i].~T(); + } + } else if (count > _size) { + for (auto i = _size; i < count; i++) { + new (this[i]) value_type(); + } + } + _size = count; +} + +template + requires std::unsigned_integral +void vector::resize(size_type count, const value_type &value) { + reserve(count); + if (count < _size) { + for (auto i = count; i < _size; i++) { + data()[i].~T(); + } + } else if (count > _size) { + for (auto i = _size; i < count; i++) { + new (this[i]) value_type(value); + } + } + _size = count; +} + +#pragma mark - Specialization for unique_ptr + +template + requires std::unsigned_integral +vector, 0, size_type>::~vector() { + for (auto i = 0; i < _size; i++) { + _buffer[i].reset(); + } + if (_buffer) { + free(_buffer); + } +} + +template + requires std::unsigned_integral +void vector, 0, size_type>::push_back(std::unique_ptr &&value) { + reserve(_size + 1); + new (&_buffer[_size]) value_type(std::move(value)); + _size += 1; +} + +} // /* OG */ From cd4b91fb72c597cd1b23033104f7ca1171992d3a Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 17 Mar 2025 00:09:44 +0800 Subject: [PATCH 04/10] Update ptr.hpp --- Sources/OpenGraph_SPI/Data/page.hpp | 21 +++----- Sources/OpenGraph_SPI/Data/page_const.hpp | 28 ++++++++++ Sources/OpenGraph_SPI/Data/ptr.hpp | 62 ++++++++++++++++------- 3 files changed, 78 insertions(+), 33 deletions(-) create mode 100644 Sources/OpenGraph_SPI/Data/page_const.hpp diff --git a/Sources/OpenGraph_SPI/Data/page.hpp b/Sources/OpenGraph_SPI/Data/page.hpp index c75810fd..22c2ce41 100644 --- a/Sources/OpenGraph_SPI/Data/page.hpp +++ b/Sources/OpenGraph_SPI/Data/page.hpp @@ -6,28 +6,19 @@ #define page_hpp #include "OGBase.h" +#include "ptr.hpp" namespace OG { namespace data { -constexpr const uint32_t page_mask_bits = 9; - -/// 0x200 -constexpr const uint32_t page_size = 1 << page_mask_bits; - -/// 0x1FF -constexpr const uint32_t page_mask = page_size - 1; - -/// 0xFFFF_FFE0 -constexpr const uintptr_t page_alignment = ~page_mask; - class zone; +template class ptr; struct page { -// zone *zone; -// ptr previous; -// uint32_t total; -// uint32_t in_use; + zone *zone; + ptr previous; + uint32_t total; + uint32_t in_use; }; /* page */ } /* data */ diff --git a/Sources/OpenGraph_SPI/Data/page_const.hpp b/Sources/OpenGraph_SPI/Data/page_const.hpp new file mode 100644 index 00000000..b03ea77c --- /dev/null +++ b/Sources/OpenGraph_SPI/Data/page_const.hpp @@ -0,0 +1,28 @@ +// +// page_const.hpp +// OpenGraph_SPI + +#ifndef page_const_hpp +#define page_const_hpp + +#include "OGBase.h" + +namespace OG { +namespace data { + +constexpr const uint32_t page_mask_bits = 9; + +/// 0x200 +constexpr const uint32_t page_size = 1 << page_mask_bits; + +/// 0x1FF +constexpr const uint32_t page_mask = page_size - 1; + +/// 0xFFFF_FE00 +constexpr const uintptr_t page_alignment = ~page_mask; + +} /* data */ +} /* OG */ + + +#endif /* page_const_hpp */ diff --git a/Sources/OpenGraph_SPI/Data/ptr.hpp b/Sources/OpenGraph_SPI/Data/ptr.hpp index 9e7f3e10..7d236ac9 100644 --- a/Sources/OpenGraph_SPI/Data/ptr.hpp +++ b/Sources/OpenGraph_SPI/Data/ptr.hpp @@ -13,7 +13,7 @@ #include #include #include -#include "page.hpp" +#include "page_const.hpp" OG_ASSUME_NONNULL_BEGIN @@ -33,44 +33,70 @@ template class ptr { template friend class ptr; public: - ptr(difference_type offset = 0) : _offset(offset){}; - ptr(nullptr_t){}; + OG_INLINE OG_CONSTEXPR ptr(difference_type offset = 0) : _offset(offset){}; + OG_INLINE OG_CONSTEXPR ptr(nullptr_t){}; + OG_INLINE OG_CONSTEXPR void assert_valid() const { if (_offset >= table::shared().data_capacity()) { precondition_failure("invalid data offset: %u", _offset); } } - element_type *_Nonnull get() const noexcept { + OG_INLINE OG_CONSTEXPR + element_type *_Nonnull get() const OG_NOEXCEPT { assert(_offset != 0); return reinterpret_cast(table::shared().data_base() + _offset); } - ptr page_ptr() const noexcept { return ptr(_offset & page_alignment); } + OG_INLINE OG_CONSTEXPR + ptr page_ptr() const OG_NOEXCEPT { return ptr(_offset & page_alignment); } - difference_type page_relative_offset() const noexcept { return _offset & page_mask; } + OG_INLINE OG_CONSTEXPR + difference_type page_relative_offset() const OG_NOEXCEPT { return _offset & page_mask; } template ptr aligned(difference_type alignment_mask = sizeof(difference_type) - 1) const { return ptr((_offset + alignment_mask) & ~alignment_mask); }; - operator bool() const noexcept { return _offset != 0; }; - std::add_lvalue_reference_t operator*() const noexcept { return *get(); }; - T *_Nonnull operator->() const noexcept { return get(); }; + OG_INLINE OG_CONSTEXPR + operator bool() const OG_NOEXCEPT { return _offset != 0; }; - bool operator==(nullptr_t) const noexcept { return _offset == 0; }; - bool operator!=(nullptr_t) const noexcept { return _offset != 0; }; + OG_INLINE OG_CONSTEXPR + std::add_lvalue_reference_t operator*() const OG_NOEXCEPT { return *get(); }; - bool operator<(difference_type offset) const noexcept { return _offset < offset; }; - bool operator<=(difference_type offset) const noexcept { return _offset <= offset; }; - bool operator>(difference_type offset) const noexcept { return _offset > offset; }; - bool operator>=(difference_type offset) const noexcept { return _offset >= offset; }; + OG_INLINE OG_CONSTEXPR + T *_Nonnull operator->() const OG_NOEXCEPT { return get(); }; - template ptr operator+(difference_type shift) const noexcept { return ptr(_offset + shift); }; - template ptr operator-(difference_type shift) const noexcept { return ptr(_offset - shift); }; + OG_INLINE OG_CONSTEXPR + bool operator==(nullptr_t) const OG_NOEXCEPT { return _offset == 0; }; - template difference_type operator-(const ptr &other) const noexcept { + OG_INLINE OG_CONSTEXPR + bool operator!=(nullptr_t) const OG_NOEXCEPT { return _offset != 0; }; + + OG_INLINE OG_CONSTEXPR + bool operator<(difference_type offset) const OG_NOEXCEPT { return _offset < offset; }; + + OG_INLINE OG_CONSTEXPR + bool operator<=(difference_type offset) const OG_NOEXCEPT { return _offset <= offset; }; + + OG_INLINE OG_CONSTEXPR + bool operator>(difference_type offset) const OG_NOEXCEPT { return _offset > offset; }; + + OG_INLINE OG_CONSTEXPR + bool operator>=(difference_type offset) const OG_NOEXCEPT { return _offset >= offset; }; + + template + OG_INLINE OG_CONSTEXPR + ptr operator+(difference_type shift) const OG_NOEXCEPT { return ptr(_offset + shift); }; + + template + OG_INLINE OG_CONSTEXPR + ptr operator-(difference_type shift) const OG_NOEXCEPT { return ptr(_offset - shift); }; + + template + OG_INLINE OG_CONSTEXPR + difference_type operator-(const ptr &other) const OG_NOEXCEPT { return _offset - other._offset; }; }; /* ptr */ From ef74847de8effff238ae6480156bf861e0eefd47 Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 17 Mar 2025 00:17:51 +0800 Subject: [PATCH 05/10] Update zone, table and page --- Sources/OpenGraph_SPI/Data/page.cpp | 5 -- Sources/OpenGraph_SPI/Data/table.cpp | 118 ++++++++++++++------------ Sources/OpenGraph_SPI/Data/table.hpp | 30 +++++-- Sources/OpenGraph_SPI/Data/zone.cpp | 121 +++++++++++++++++++++++++++ Sources/OpenGraph_SPI/Data/zone.hpp | 70 ++++++++++++++++ 5 files changed, 276 insertions(+), 68 deletions(-) delete mode 100644 Sources/OpenGraph_SPI/Data/page.cpp create mode 100644 Sources/OpenGraph_SPI/Data/zone.cpp create mode 100644 Sources/OpenGraph_SPI/Data/zone.hpp diff --git a/Sources/OpenGraph_SPI/Data/page.cpp b/Sources/OpenGraph_SPI/Data/page.cpp deleted file mode 100644 index 6c337001..00000000 --- a/Sources/OpenGraph_SPI/Data/page.cpp +++ /dev/null @@ -1,5 +0,0 @@ -// -// page.cpp -// OpenGraph_SPI - -#include "page.hpp" diff --git a/Sources/OpenGraph_SPI/Data/table.cpp b/Sources/OpenGraph_SPI/Data/table.cpp index 82594fb0..e2b8c138 100644 --- a/Sources/OpenGraph_SPI/Data/table.cpp +++ b/Sources/OpenGraph_SPI/Data/table.cpp @@ -7,6 +7,7 @@ #include "table.hpp" #include "page.hpp" +#include "page.hpp" #include "../Util/assert.hpp" #include #include @@ -21,40 +22,34 @@ uint8_t _shared_table_bytes[sizeof(table) / sizeof(uint8_t)] = {}; malloc_zone_t *_Nullable _malloc_zone; -void table::print() const OG_NOEXCEPT { - os_unfair_lock_lock(&_lock); - fprintf(stderr, "data::table %p:\n %.2fKB allocated, %.2fKB used, %.2fKB reusable.\n", - this, - double(_region_capacity - page_size) / 1024.0, - double(this->used_pages_num()) / 1024.0, - double(_reusable_pages_num) / 1024.0); - os_unfair_lock_unlock(&_lock); +table &table::ensure_shared() { + static dispatch_once_t once; + dispatch_once_f(&once, nullptr, [](void *_Nullable context){ + new (_shared_table_bytes) table(); + }); + return shared(); } -//uint64_t table::raw_page_seed(ptr page) { -// page.assert_valid(); -// -// lock(); -// -// uint32_t page_index = (page / page_size) - 1; -// uint32_t map_index = page_index / pages_per_map; -// -// uint64_t result = 0; -// if (map_index < _page_metadata_maps.size() && _page_metadata_maps[map_index].test(page_index % page_size)) { -// auto raw_zone_info = page->zone->info().to_raw_value(); -// result = raw_zone_info | (1 < 8); -// } -// -// unlock(); -// -// return result; -//} - -// dealloc_page_locked(OG::data::ptr - -// alloc_page(OG::data::zone&, unsigned int) +table &table::shared() { return *reinterpret_cast(&_shared_table_bytes); } -// make_pages_reusable(unsigned int, bool) +// FIXME +table::table() { + constexpr vm_size_t initial_size = 32 * pages_per_map * page_size; + _region_capacity = initial_size; + void *region = mmap(nullptr, initial_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); + _region_base = reinterpret_cast(region); + OGGraphVMRegionBaseAddress = region; + if (region == MAP_FAILED) { + OG::precondition_failure("memory allocation failure (%u bytes, %u)", _region_capacity, errno); + } + _data_base = reinterpret_cast(region) - page_size; + _data_capacity = initial_size + page_size; + if (_malloc_zone == nullptr) { + malloc_zone_t *zone = malloc_create_zone(0, 0); + _malloc_zone = zone; + malloc_set_zone_name(zone, "OpenGraph graph data"); + } +} void table::grow_region() OG_NOEXCEPT { uint32_t new_size = 4 * _region_capacity; @@ -91,34 +86,47 @@ void table::grow_region() OG_NOEXCEPT { _data_capacity = new_size + page_size; } -// FIXME -table::table() { - constexpr vm_size_t initial_size = 32 * pages_per_map * page_size; - _region_capacity = initial_size; - void *region = mmap(nullptr, initial_size, PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_ANON, -1, 0); - _region_base = reinterpret_cast(region); - OGGraphVMRegionBaseAddress = region; - if (region == MAP_FAILED) { - OG::precondition_failure("memory allocation failure (%u bytes, %u)", _region_capacity, errno); - } - _data_base = reinterpret_cast(region) - page_size; - _data_capacity = initial_size + page_size; - if (_malloc_zone == nullptr) { - malloc_zone_t *zone = malloc_create_zone(0, 0); - _malloc_zone = zone; - malloc_set_zone_name(zone, "OpenGraph graph data"); - } +void table::make_pages_reusable(uint32_t page_index, bool flag) OG_NOEXCEPT { + precondition_failure("TODO"); } -table &table::ensure_shared() { - static dispatch_once_t once; - dispatch_once_f(&once, nullptr, [](void *_Nullable context){ - new (_shared_table_bytes) table(); - }); - return shared(); +ptr table::alloc_page(zone *zone, uint32_t size) OG_NOEXCEPT { + precondition_failure("TODO"); } -table &table::shared() { return *reinterpret_cast(&_shared_table_bytes); } +void table::dealloc_page_locked(ptr page) OG_NOEXCEPT { + precondition_failure("TODO"); +} + +uint64_t table::raw_page_seed(ptr page) OG_NOEXCEPT { + precondition_failure("TODO"); +// page.assert_valid(); +// +// lock(); +// +// uint32_t page_index = (page / page_size) - 1; +// uint32_t map_index = page_index / pages_per_map; +// +// uint64_t result = 0; +// if (map_index < _page_metadata_maps.size() && _page_metadata_maps[map_index].test(page_index % page_size)) { +// auto raw_zone_info = page->zone->info().to_raw_value(); +// result = raw_zone_info | (1 < 8); +// } +// +// unlock(); +// +// return result; +} + +void table::print() const OG_NOEXCEPT { + os_unfair_lock_lock(&_lock); + fprintf(stderr, "data::table %p:\n %.2fKB allocated, %.2fKB used, %.2fKB reusable.\n", + this, + double(_region_capacity - page_size) / 1024.0, + double(this->used_pages_num()) / 1024.0, + double(_reusable_pages_num) / 1024.0); + os_unfair_lock_unlock(&_lock); +} } /* data */ } /* OG */ diff --git a/Sources/OpenGraph_SPI/Data/table.hpp b/Sources/OpenGraph_SPI/Data/table.hpp index dc7bc4a3..b2f3ddbc 100644 --- a/Sources/OpenGraph_SPI/Data/table.hpp +++ b/Sources/OpenGraph_SPI/Data/table.hpp @@ -25,9 +25,7 @@ class table { public: static table &ensure_shared(); static table &shared(); - - table(); - + OG_INLINE OG_CONSTEXPR vm_address_t data_base() const OG_NOEXCEPT { return _data_base; }; @@ -52,10 +50,25 @@ class table { OG_INLINE OG_CONSTEXPR uint32_t reusable_pages_num() const OG_NOEXCEPT { return _reusable_pages_num; }; - void print() const OG_NOEXCEPT; + OG_INLINE OG_CONSTEXPR + uint32_t make_zone_id() { + _zones_num += 1; + return _zones_num; + } + + table(); void grow_region() OG_NOEXCEPT; + void make_pages_reusable(uint32_t page_index, bool flag) OG_NOEXCEPT; + + ptr alloc_page(zone *zone, uint32_t size) OG_NOEXCEPT; + + void dealloc_page_locked(ptr page) OG_NOEXCEPT; + + uint64_t raw_page_seed(ptr page) OG_NOEXCEPT; + + void print() const OG_NOEXCEPT; private: /// _region_base - page_size vm_address_t _data_base; @@ -79,11 +92,12 @@ class table { using remapped_region = std::pair; vector _remapped_regions = {}; -// + constexpr static unsigned int pages_per_map = 64; -// using page_map_type = std::bitset; -// vector _page_maps = {}; -// vector _page_metadata_maps = {}; + + using page_map_type = std::bitset; + vector _page_maps = {}; + vector _page_metadata_maps = {}; }; /* table */ diff --git a/Sources/OpenGraph_SPI/Data/zone.cpp b/Sources/OpenGraph_SPI/Data/zone.cpp new file mode 100644 index 00000000..37ebe886 --- /dev/null +++ b/Sources/OpenGraph_SPI/Data/zone.cpp @@ -0,0 +1,121 @@ +// +// zone.cpp +// OpenGraph_SPI + +#include "zone.hpp" +#include "table.hpp" +#include "page.hpp" +#include "../Util/assert.hpp" + +namespace OG { +namespace data { + +void zone::clear() OG_NOEXCEPT { + table::shared().lock(); + while (last_page()) { + auto page = last_page(); + _last_page = page->previous; + table::shared().dealloc_page_locked(page); + } + table::shared().unlock(); +} + +ptr zone::alloc_slow(uint32_t size, uint32_t alignment_mask) OG_NOEXCEPT { + if (last_page()) { + // check if we can use remaining bytes in this page + ptr next_bytes = last_page() + last_page()->in_use; + if (next_bytes.page_ptr() == _last_page) { + ptr aligned_next_bytes = next_bytes.aligned(); + int32_t remaining_size = _last_page->total - _last_page->in_use + (next_bytes - aligned_next_bytes); + if (remaining_size >= sizeof(bytes_info)) { + bytes_info *remaining_bytes = aligned_next_bytes.get(); + remaining_bytes->next = _free_bytes; + remaining_bytes->size = remaining_size; + _free_bytes = aligned_next_bytes; + } + + // consume this entire page + _last_page->in_use = _last_page->total; + } + } + + ptr new_page; + if (size <= page_size / 2) { + new_page = table::shared().alloc_page(this, page_size); + new_page->previous = _last_page; + _last_page = new_page; + } else { + uint32_t aligned_size = ((sizeof(page) + size) + alignment_mask) & ~alignment_mask; + new_page = table::shared().alloc_page(this, aligned_size); + if (_last_page) { + // It's less likely we will be able to alloc unused bytes from this page, + // so insert it before the last page. + new_page->previous = _last_page->previous; + _last_page->previous = new_page; + } else { + _last_page = new_page; + } + } + + int32_t aligned_used_bytes = (new_page->in_use + alignment_mask) & ~alignment_mask; + + // Sanity check + if (aligned_used_bytes + size > new_page->total) { + precondition_failure("internal error"); + } + + new_page->in_use = aligned_used_bytes + size; + return new_page + aligned_used_bytes; +}; + +void zone::print() const OG_NOEXCEPT { + unsigned long num_pages = 0; + double pages_total_kb = 0.0; + double pages_in_use_kb = 0.0; + if (_last_page) { + int64_t pages_total = 0; + int64_t pages_in_use = 0; + for (auto page = _last_page; page; page = page->previous) { + num_pages++; + pages_total += page->total; + pages_in_use += page->in_use; + } + pages_total_kb = pages_total / 1024.0; + pages_in_use_kb = pages_in_use / 1024.0; + } + + unsigned long num_free_elements = 0; + unsigned long free_bytes = 0; + if (_free_bytes) { + for (auto bytes = _free_bytes; bytes; bytes = bytes->next) { + num_free_elements++; + free_bytes += bytes->size; + } + } + + unsigned long num_persistent_buffers = _malloc_buffers.size(); + size_t malloc_total_size = 0; + for (auto &element : _malloc_buffers) { + malloc_total_size += malloc_size(element.get()); + } + double malloc_total_size_kb = malloc_total_size / 1024.0; + + fprintf(stderr, "%-16p %6lu %8.2f %8.2f %6lu %6lu %6lu %8.2f\n", + this, // zone ptr + num_pages, // pages + pages_total_kb, // total + pages_in_use_kb, // in-use + num_free_elements, // free + free_bytes, // bytes + num_persistent_buffers, // malloc + malloc_total_size_kb // total + ); +} + +void zone::print_header() OG_NOEXCEPT { + fprintf(stderr, "Zones\n%-16s %6s %8s %8s %6s %6s %6s %8s\n", + "zone ptr", "pages", "total", "in-use", "free", "bytes", "malloc", "total"); +} + +} /* data */ +} /* OG */ diff --git a/Sources/OpenGraph_SPI/Data/zone.hpp b/Sources/OpenGraph_SPI/Data/zone.hpp new file mode 100644 index 00000000..5e5b5ca6 --- /dev/null +++ b/Sources/OpenGraph_SPI/Data/zone.hpp @@ -0,0 +1,70 @@ +// +// zone.hpp +// OpenGraph_SPI + +#ifndef zone_hpp +#define zone_hpp + +#include "OGBase.h" +#include "ptr.hpp" + +namespace OG { +namespace data { + +class zone { +public: + class info { + private: + constexpr static uint32_t zone_id_mask = 0x7fffffff; + uint32_t _value; + constexpr info(uint32_t value) : _value(value){}; + + public: + uint32_t zone_id() { return _value & zone_id_mask; }; + info with_zone_id(uint32_t zone_id) const { return info((_value & ~zone_id_mask) | (zone_id & zone_id_mask)); }; + + uint32_t to_raw_value() { return _value; }; + static info from_raw_value(uint32_t value) { return info(value); }; + }; /* info */ +public: + zone(); + + OG_INLINE OG_CONSTEXPR + ptr last_page() const OG_NOEXCEPT { return _last_page; }; + + OG_INLINE OG_CONSTEXPR + info info() const OG_NOEXCEPT { return _info; }; + + void clear() OG_NOEXCEPT; + + ptr alloc_slow(uint32_t size, uint32_t alignment_mask) OG_NOEXCEPT; + + void *alloc_persistent(size_t size) OG_NOEXCEPT; + + void realloc_bytes(ptr *buffer, uint32_t size, uint32_t new_size, uint32_t alignment_mask) OG_NOEXCEPT; + +// ptr alloc_bytes(uint32_t size, uint32_t alignment_mask); + ptr alloc_bytes_recycle(uint32_t size, uint32_t alignment_mask) OG_NOEXCEPT; + + // Printing + void print() const OG_NOEXCEPT; + + void print_header() OG_NOEXCEPT; + + ~zone(); +private: + typedef struct _bytes_info { + ptr next; + uint32_t size; + } bytes_info; + + vector, 0, uint32_t> _malloc_buffers; + ptr _last_page; + ptr _free_bytes; + class info _info; +}; /* zone */ + +} /* data */ +} /* OG */ + +#endif /* zone_hpp */ From 6b7c19cd0255d99fc1a00d544251ae6d29b9bf11 Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 17 Mar 2025 00:59:37 +0800 Subject: [PATCH 06/10] Update to dynamic framework --- Package.swift | 5 ++--- Sources/OpenGraph_SPI/Data/ptr.hpp | 4 ++-- Sources/OpenGraph_SPI/Data/table.cpp | 7 +------ Sources/OpenGraph_SPI/Data/table.hpp | 9 +++++++-- Sources/OpenGraph_SPI/Data/zone.cpp | 10 +++++----- 5 files changed, 17 insertions(+), 18 deletions(-) diff --git a/Package.swift b/Package.swift index 20111acf..7bc482aa 100644 --- a/Package.swift +++ b/Package.swift @@ -159,9 +159,8 @@ let openGraphSPICompatibilityTestTarget = Target.testTarget( let package = Package( name: "OpenGraph", products: [ - .library(name: "OpenGraph_SPI", targets: ["OpenGraph_SPI"]), - .library(name: "OpenGraph", targets: ["OpenGraph"]), - .library(name: "OpenGraphShims", targets: ["OpenGraphShims"]), + .library(name: "OpenGraph", type: .dynamic, targets: ["OpenGraph", "OpenGraph_SPI"]), + .library(name: "OpenGraphShims", type: .dynamic, targets: ["OpenGraph", "OpenGraph_SPI", "OpenGraphShims"]), ], dependencies: [ .package(url: "https://github.com/apple/swift-numerics", from: "1.0.2"), diff --git a/Sources/OpenGraph_SPI/Data/ptr.hpp b/Sources/OpenGraph_SPI/Data/ptr.hpp index 7d236ac9..777da5ef 100644 --- a/Sources/OpenGraph_SPI/Data/ptr.hpp +++ b/Sources/OpenGraph_SPI/Data/ptr.hpp @@ -38,7 +38,7 @@ template class ptr { OG_INLINE OG_CONSTEXPR void assert_valid() const { - if (_offset >= table::shared().data_capacity()) { + if (_offset >= shared_table().data_capacity()) { precondition_failure("invalid data offset: %u", _offset); } } @@ -46,7 +46,7 @@ template class ptr { OG_INLINE OG_CONSTEXPR element_type *_Nonnull get() const OG_NOEXCEPT { assert(_offset != 0); - return reinterpret_cast(table::shared().data_base() + _offset); + return reinterpret_cast(shared_table().data_base() + _offset); } OG_INLINE OG_CONSTEXPR diff --git a/Sources/OpenGraph_SPI/Data/table.cpp b/Sources/OpenGraph_SPI/Data/table.cpp index e2b8c138..1f1b996b 100644 --- a/Sources/OpenGraph_SPI/Data/table.cpp +++ b/Sources/OpenGraph_SPI/Data/table.cpp @@ -18,8 +18,6 @@ void *OGGraphVMRegionBaseAddress; namespace OG { namespace data { -uint8_t _shared_table_bytes[sizeof(table) / sizeof(uint8_t)] = {}; - malloc_zone_t *_Nullable _malloc_zone; table &table::ensure_shared() { @@ -27,12 +25,9 @@ table &table::ensure_shared() { dispatch_once_f(&once, nullptr, [](void *_Nullable context){ new (_shared_table_bytes) table(); }); - return shared(); + return shared_table(); } -table &table::shared() { return *reinterpret_cast(&_shared_table_bytes); } - -// FIXME table::table() { constexpr vm_size_t initial_size = 32 * pages_per_map * page_size; _region_capacity = initial_size; diff --git a/Sources/OpenGraph_SPI/Data/table.hpp b/Sources/OpenGraph_SPI/Data/table.hpp index b2f3ddbc..cfcae7c0 100644 --- a/Sources/OpenGraph_SPI/Data/table.hpp +++ b/Sources/OpenGraph_SPI/Data/table.hpp @@ -24,7 +24,6 @@ class table { public: static table &ensure_shared(); - static table &shared(); OG_INLINE OG_CONSTEXPR vm_address_t data_base() const OG_NOEXCEPT { return _data_base; }; @@ -98,9 +97,15 @@ class table { using page_map_type = std::bitset; vector _page_maps = {}; vector _page_metadata_maps = {}; - }; /* table */ +static uint8_t _shared_table_bytes[sizeof(table) / sizeof(uint8_t)] = {}; + +OG_INLINE +static table &shared_table() { + return *reinterpret_cast(&_shared_table_bytes); +} + } /* data */ } /* OG */ diff --git a/Sources/OpenGraph_SPI/Data/zone.cpp b/Sources/OpenGraph_SPI/Data/zone.cpp index 37ebe886..0f4a3e9d 100644 --- a/Sources/OpenGraph_SPI/Data/zone.cpp +++ b/Sources/OpenGraph_SPI/Data/zone.cpp @@ -11,13 +11,13 @@ namespace OG { namespace data { void zone::clear() OG_NOEXCEPT { - table::shared().lock(); + shared_table().lock(); while (last_page()) { auto page = last_page(); _last_page = page->previous; - table::shared().dealloc_page_locked(page); + shared_table().dealloc_page_locked(page); } - table::shared().unlock(); + shared_table().unlock(); } ptr zone::alloc_slow(uint32_t size, uint32_t alignment_mask) OG_NOEXCEPT { @@ -41,12 +41,12 @@ ptr zone::alloc_slow(uint32_t size, uint32_t alignment_mask) OG_NOEXCEPT { ptr new_page; if (size <= page_size / 2) { - new_page = table::shared().alloc_page(this, page_size); + new_page = shared_table().alloc_page(this, page_size); new_page->previous = _last_page; _last_page = new_page; } else { uint32_t aligned_size = ((sizeof(page) + size) + alignment_mask) & ~alignment_mask; - new_page = table::shared().alloc_page(this, aligned_size); + new_page = shared_table().alloc_page(this, aligned_size); if (_last_page) { // It's less likely we will be able to alloc unused bytes from this page, // so insert it before the last page. From 80b02bb5a6ec4b26d7c6b2eeac261e6efb79badd Mon Sep 17 00:00:00 2001 From: Kyle Date: Mon, 17 Mar 2025 01:37:43 +0800 Subject: [PATCH 07/10] Update table implementation --- README.md | 2 +- Sources/OpenGraph_SPI/Data/ptr.hpp | 6 +- Sources/OpenGraph_SPI/Data/table.cpp | 169 +++++++++++++++++++++++---- Sources/OpenGraph_SPI/Data/table.hpp | 2 +- 4 files changed, 151 insertions(+), 28 deletions(-) diff --git a/README.md b/README.md index 51e9ef90..3bf306df 100644 --- a/README.md +++ b/README.md @@ -27,7 +27,7 @@ Currently, this project is in early development. ## Credits -Part of the Graph implementation is from https://github.com/jcmosc/Compute +OpenGraph_SPI's Data, Graph, Vector and more is modified based on [Compute](https://github.com/jcmosc/Compute)'s implementations. ## License diff --git a/Sources/OpenGraph_SPI/Data/ptr.hpp b/Sources/OpenGraph_SPI/Data/ptr.hpp index 777da5ef..6dbfeb03 100644 --- a/Sources/OpenGraph_SPI/Data/ptr.hpp +++ b/Sources/OpenGraph_SPI/Data/ptr.hpp @@ -36,9 +36,9 @@ template class ptr { OG_INLINE OG_CONSTEXPR ptr(difference_type offset = 0) : _offset(offset){}; OG_INLINE OG_CONSTEXPR ptr(nullptr_t){}; - OG_INLINE OG_CONSTEXPR - void assert_valid() const { - if (_offset >= shared_table().data_capacity()) { + OG_INLINE + void assert_valid(table t = shared_table()) const { + if (t.data_capacity() <= _offset) { precondition_failure("invalid data offset: %u", _offset); } } diff --git a/Sources/OpenGraph_SPI/Data/table.cpp b/Sources/OpenGraph_SPI/Data/table.cpp index 1f1b996b..166ea53d 100644 --- a/Sources/OpenGraph_SPI/Data/table.cpp +++ b/Sources/OpenGraph_SPI/Data/table.cpp @@ -4,10 +4,12 @@ // // Audited for iOS 18.0 // Status: WIP +// Modified from https://github.com/jcmosc/Compute/blob/0a6b21a4cdeb9bbdd95e7e914c4e18bed37a2456/Sources/ComputeCxx/Data/Table.cpp [MIT License] #include "table.hpp" #include "page.hpp" -#include "page.hpp" +#include "page_const.hpp" +#include "zone.hpp" #include "../Util/assert.hpp" #include #include @@ -81,36 +83,157 @@ void table::grow_region() OG_NOEXCEPT { _data_capacity = new_size + page_size; } -void table::make_pages_reusable(uint32_t page_index, bool flag) OG_NOEXCEPT { - precondition_failure("TODO"); +void table::make_pages_reusable(uint32_t page_index, bool reusable) OG_NOEXCEPT { + static constexpr uint32_t mapped_pages_size = page_size * pages_per_map; // 64 * 512 = 0x8000 + void *mapped_pages_address = reinterpret_cast(region_base() + ((page_index * page_size) & ~(mapped_pages_size - 1))); + int advice = reusable ? MADV_FREE_REUSABLE : MADV_FREE_REUSE; + madvise(mapped_pages_address, mapped_pages_size, advice); + static bool unmap_reusable = []() -> bool { + char *result = getenv("OG_UNMAP_REUSABLE"); + if (result) { + return atoi(result) != 0; + } + return false; + }(); + if (unmap_reusable) { + int protection = reusable ? PROT_NONE : (PROT_READ | PROT_WRITE); + mprotect(mapped_pages_address, mapped_pages_size, protection); + } + _reusable_pages_num += reusable ? mapped_pages_size : -mapped_pages_size; } -ptr table::alloc_page(zone *zone, uint32_t size) OG_NOEXCEPT { - precondition_failure("TODO"); +// TO BE AUDITED +ptr table::alloc_page(zone *zone, uint32_t needed_size) OG_NOEXCEPT { + lock(); + + uint32_t needed_pages = (needed_size + page_mask) / page_size; + + // assume we'll have to append a new page + uint32_t new_page_index = _page_maps.size() * pages_per_map; + + // scan for consecutive free pages + if (!_page_maps.empty() && _used_pages_num <= _page_maps.size() * pages_per_map) { + + uint32_t start_map_index = _map_search_start; + for (int i = 0; i < _page_maps.size(); i++) { + int map_index = start_map_index + i; + if (map_index >= _page_maps.size()) { + map_index -= _page_maps.size(); // wrap around + } + + page_map_type free_pages_map = _page_maps[map_index].flip(); + while (free_pages_map.any()) { + + int candidate_bit = std::countr_zero(static_cast(free_pages_map.to_ullong())); + + // scan ahead to find enough consecutive free pages + bool found = false; + if (needed_pages > 1) { + for (int j = 1; j < needed_pages; j++) { + int next_page_index = (map_index * pages_per_map) + candidate_bit + j; + int next_map_index = next_page_index / pages_per_map; + if (next_map_index == _page_maps.size()) { + // There are not enough maps, but the trailing pages are contiguous so this page is + // usable + found = true; + break; + } + if (_page_maps[next_map_index].test(next_page_index % pages_per_map)) { + // next page is used, remove this page from free_pages_map + free_pages_map.reset(candidate_bit); + break; + } + } + found = true; + } else { + // only need one page + found = true; + } + + if (found) { + new_page_index = (map_index * pages_per_map) + candidate_bit; + _map_search_start = map_index; + break; + } + } + } + } + + // update maps + for (int i = 0; i < needed_pages; i++) { + uint32_t page_index = new_page_index + i; + uint32_t map_index = page_index / pages_per_map; + + if (map_index == _page_maps.size()) { + _page_maps.push_back(0); + _page_metadata_maps.push_back(0); + } else if (_page_maps[map_index] == 0) { + make_pages_reusable(page_index, false); + } + + _page_maps[map_index].set(page_index % pages_per_map); + if (i == 0) { + _page_metadata_maps[map_index].set(page_index % pages_per_map); + } + } + + _used_pages_num += needed_pages; + + uint32_t new_region_size = (new_page_index + needed_pages) * page_size; + while (region_capacity() < new_region_size) { + grow_region(); + } + + // ptr offsets are "one"-based, so that we can treat 0 as null. + ptr new_page = ptr((new_page_index + 1) * page_size); + new_page->zone = zone; + new_page->previous = nullptr; + new_page->total = (needed_size + page_mask) & page_alignment; + new_page->in_use = sizeof(page); + unlock(); + return new_page; } +// TO BE AUDITED void table::dealloc_page_locked(ptr page) OG_NOEXCEPT { - precondition_failure("TODO"); + int32_t total_bytes = page->total; + int32_t num_pages = total_bytes / page_size; + + _used_pages_num -= num_pages; + + // convert the page address (starts at 512) to an index (starts at 0) + int32_t page_index = (page / page_size) - 1; + for (int32_t i = 0; i != num_pages; i += 1) { + + int32_t next_page_index = page_index + i; + int32_t next_map_index = next_page_index / pages_per_map; + + _page_maps[next_map_index].reset(next_page_index % pages_per_map); + if (i == 0) { + _page_metadata_maps[next_map_index].reset(next_page_index % pages_per_map); + } + + if (_page_maps[next_map_index].none()) { + make_pages_reusable(next_page_index, true); + } + } } +// TO BE AUDITED uint64_t table::raw_page_seed(ptr page) OG_NOEXCEPT { - precondition_failure("TODO"); -// page.assert_valid(); -// -// lock(); -// -// uint32_t page_index = (page / page_size) - 1; -// uint32_t map_index = page_index / pages_per_map; -// -// uint64_t result = 0; -// if (map_index < _page_metadata_maps.size() && _page_metadata_maps[map_index].test(page_index % page_size)) { -// auto raw_zone_info = page->zone->info().to_raw_value(); -// result = raw_zone_info | (1 < 8); -// } -// -// unlock(); -// -// return result; + page.assert_valid(*this); + lock(); + uint32_t page_index = (page / page_size) - 1; + uint32_t map_index = page_index / pages_per_map; + + // FIXME + uint64_t result = 0; + if (map_index < _page_metadata_maps.size() && _page_metadata_maps[map_index].test(page_index % page_size)) { + auto raw_zone_info = page->zone->info().to_raw_value(); + result = raw_zone_info | (1 < 8); + } + unlock(); + return result; } void table::print() const OG_NOEXCEPT { diff --git a/Sources/OpenGraph_SPI/Data/table.hpp b/Sources/OpenGraph_SPI/Data/table.hpp index cfcae7c0..c3816d4c 100644 --- a/Sources/OpenGraph_SPI/Data/table.hpp +++ b/Sources/OpenGraph_SPI/Data/table.hpp @@ -59,7 +59,7 @@ class table { void grow_region() OG_NOEXCEPT; - void make_pages_reusable(uint32_t page_index, bool flag) OG_NOEXCEPT; + void make_pages_reusable(uint32_t page_index, bool reusable) OG_NOEXCEPT; ptr alloc_page(zone *zone, uint32_t size) OG_NOEXCEPT; From 7d460c893889ec7de2ba9abf589424bfd647d403 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 23 Mar 2025 14:59:17 +0800 Subject: [PATCH 08/10] Add openGraphSPITestTarget --- Package.swift | 60 +++++++++++++-------- Tests/OpenGraph_SPITests/table_test_case.mm | 20 +++++++ 2 files changed, 58 insertions(+), 22 deletions(-) create mode 100644 Tests/OpenGraph_SPITests/table_test_case.mm diff --git a/Package.swift b/Package.swift index 7bc482aa..239c7d2f 100644 --- a/Package.swift +++ b/Package.swift @@ -29,6 +29,7 @@ let includePath = SDKPath.appending("/usr/lib/swift") var sharedCSettings: [CSetting] = [ .unsafeFlags(["-I", includePath], .when(platforms: .nonDarwinPlatforms)), + .define("NDEBUG", .when(configuration: .release)), ] var sharedSwiftSettings: [SwiftSetting] = [ @@ -110,26 +111,53 @@ if warningsAsErrorsCondition { // MARK: - Targets +let openGraphTarget = Target.target( + name: "OpenGraph", + dependencies: ["OpenGraph_SPI"], + cSettings: sharedCSettings, + swiftSettings: sharedSwiftSettings +) +// FIXME: Merge into one target +// OpenGraph is a C++ & Swift mix target. +// The SwiftPM support for such usage is still in progress. +let openGraphSPITarget = Target.target( + name: "OpenGraph_SPI", + cSettings: sharedCSettings + [ + .define("__COREFOUNDATION_FORSWIFTFOUNDATIONONLY__", to: "1", .when(platforms: .nonDarwinPlatforms)), + ] +) let openGraphShimsTarget = Target.target( name: "OpenGraphShims", cSettings: sharedCSettings, swiftSettings: sharedSwiftSettings ) -let openGraphShimsTestTarget = Target.testTarget( - name: "OpenGraphShimsTests", +// MARK: - Test Targets + +let openGraphTestTarget = Target.testTarget( + name: "OpenGraphTests", dependencies: [ - "OpenGraphShims", + "OpenGraph", ], exclude: ["README.md"], cSettings: sharedCSettings, swiftSettings: sharedSwiftSettings ) - -let openGraphTestTarget = Target.testTarget( - name: "OpenGraphTests", +let openGraphSPITestTarget = Target.testTarget( + name: "OpenGraph_SPITests", dependencies: [ - "OpenGraph", + "OpenGraph_SPI", + ], + exclude: ["README.md"], + cSettings: sharedCSettings + [ + .headerSearchPath("../../Sources/OpenGraph_SPI"), + ], + swiftSettings: sharedSwiftSettings +) +let openGraphShimsTestTarget = Target.testTarget( + name: "OpenGraphShimsTests", + dependencies: [ + "OpenGraphShims", ], exclude: ["README.md"], cSettings: sharedCSettings, @@ -166,24 +194,12 @@ let package = Package( .package(url: "https://github.com/apple/swift-numerics", from: "1.0.2"), ], targets: [ - // FIXME: Merge into one target - // OpenGraph is a C++ & Swift mix target. - // The SwiftPM support for such usage is still in progress. - .target( - name: "OpenGraph_SPI", - cSettings: sharedCSettings + [ - .define("__COREFOUNDATION_FORSWIFTFOUNDATIONONLY__", to: "1", .when(platforms: .nonDarwinPlatforms)), - ] - ), - .target( - name: "OpenGraph", - dependencies: ["OpenGraph_SPI"], - cSettings: sharedCSettings, - swiftSettings: sharedSwiftSettings - ), + openGraphTarget, + openGraphSPITarget, openGraphShimsTarget, openGraphTestTarget, + openGraphSPITestTarget, openGraphShimsTestTarget, openGraphCompatibilityTestTarget, openGraphSPICompatibilityTestTarget, diff --git a/Tests/OpenGraph_SPITests/table_test_case.mm b/Tests/OpenGraph_SPITests/table_test_case.mm new file mode 100644 index 00000000..6a350f1d --- /dev/null +++ b/Tests/OpenGraph_SPITests/table_test_case.mm @@ -0,0 +1,20 @@ +// +// table_test_case.mm +// OpenGraph_SPITests + +#include +#include "Data/table.hpp" + +using namespace OG; + +@interface TableTestCase : XCTestCase +@end + +@implementation TableTestCase + +- (void)setUp { + [super setUp]; + data::table::ensure_shared(); +} + +@end From 513226092f59ad525a92bb150382a39038b998a0 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 23 Mar 2025 16:44:16 +0800 Subject: [PATCH 09/10] Fix ptr issue --- Sources/OpenGraph_SPI/Data/ptr.hpp | 13 ++++++++----- Sources/OpenGraph_SPI/Data/table.cpp | 25 +++++++++++++++---------- Sources/OpenGraph_SPI/Data/table.hpp | 8 +++++++- 3 files changed, 30 insertions(+), 16 deletions(-) diff --git a/Sources/OpenGraph_SPI/Data/ptr.hpp b/Sources/OpenGraph_SPI/Data/ptr.hpp index 6dbfeb03..2901ab83 100644 --- a/Sources/OpenGraph_SPI/Data/ptr.hpp +++ b/Sources/OpenGraph_SPI/Data/ptr.hpp @@ -37,21 +37,24 @@ template class ptr { OG_INLINE OG_CONSTEXPR ptr(nullptr_t){}; OG_INLINE - void assert_valid(table t = shared_table()) const { - if (t.data_capacity() <= _offset) { + void assert_valid(uint32_t capacity = shared_table().data_capacity()) const { + if (capacity <= _offset) { precondition_failure("invalid data offset: %u", _offset); } } - OG_INLINE OG_CONSTEXPR - element_type *_Nonnull get() const OG_NOEXCEPT { + OG_INLINE + element_type *_Nonnull get(vm_address_t base = shared_table().data_base()) const OG_NOEXCEPT { assert(_offset != 0); - return reinterpret_cast(shared_table().data_base() + _offset); + return reinterpret_cast(base + _offset); } OG_INLINE OG_CONSTEXPR ptr page_ptr() const OG_NOEXCEPT { return ptr(_offset & page_alignment); } + OG_INLINE OG_CONSTEXPR + uint32_t page_index() const OG_NOEXCEPT { return (_offset >> page_mask_bits) - 1; } + OG_INLINE OG_CONSTEXPR difference_type page_relative_offset() const OG_NOEXCEPT { return _offset & page_mask; } diff --git a/Sources/OpenGraph_SPI/Data/table.cpp b/Sources/OpenGraph_SPI/Data/table.cpp index 166ea53d..f81063fd 100644 --- a/Sources/OpenGraph_SPI/Data/table.cpp +++ b/Sources/OpenGraph_SPI/Data/table.cpp @@ -196,11 +196,12 @@ ptr table::alloc_page(zone *zone, uint32_t needed_size) OG_NOEXCEPT { // TO BE AUDITED void table::dealloc_page_locked(ptr page) OG_NOEXCEPT { - int32_t total_bytes = page->total; + int32_t total_bytes = page.get(_data_base)->total; int32_t num_pages = total_bytes / page_size; - _used_pages_num -= num_pages; - + if (total_bytes < page_size) { + return; + } // convert the page address (starts at 512) to an index (starts at 0) int32_t page_index = (page / page_size) - 1; for (int32_t i = 0; i != num_pages; i += 1) { @@ -221,19 +222,23 @@ void table::dealloc_page_locked(ptr page) OG_NOEXCEPT { // TO BE AUDITED uint64_t table::raw_page_seed(ptr page) OG_NOEXCEPT { - page.assert_valid(*this); + page.assert_valid(_data_capacity); lock(); - uint32_t page_index = (page / page_size) - 1; + uint32_t page_index = page.page_index(); uint32_t map_index = page_index / pages_per_map; - - // FIXME uint64_t result = 0; + uint32_t w21 = 0; + uint32_t w22 = 0; + // FIXME if (map_index < _page_metadata_maps.size() && _page_metadata_maps[map_index].test(page_index % page_size)) { - auto raw_zone_info = page->zone->info().to_raw_value(); - result = raw_zone_info | (1 < 8); + auto info = page->zone->info(); + // FIXME + w22 = info.to_raw_value() & 0xffffff00; + w21 = info.to_raw_value() & 0x000000ff; + result = uint64_t(1) << 32; } unlock(); - return result; + return result || uint64_t(w22 || w21); } void table::print() const OG_NOEXCEPT { diff --git a/Sources/OpenGraph_SPI/Data/table.hpp b/Sources/OpenGraph_SPI/Data/table.hpp index c3816d4c..b610a024 100644 --- a/Sources/OpenGraph_SPI/Data/table.hpp +++ b/Sources/OpenGraph_SPI/Data/table.hpp @@ -49,6 +49,12 @@ class table { OG_INLINE OG_CONSTEXPR uint32_t reusable_pages_num() const OG_NOEXCEPT { return _reusable_pages_num; }; + OG_INLINE OG_CONSTEXPR + uint32_t map_search_start() const OG_NOEXCEPT { return _map_search_start; }; + + OG_INLINE OG_CONSTEXPR + uint32_t zones_num() const OG_NOEXCEPT { return _zones_num; }; + OG_INLINE OG_CONSTEXPR uint32_t make_zone_id() { _zones_num += 1; @@ -92,7 +98,7 @@ class table { using remapped_region = std::pair; vector _remapped_regions = {}; - constexpr static unsigned int pages_per_map = 64; + OG_CONSTEXPR static unsigned int pages_per_map = 64; using page_map_type = std::bitset; vector _page_maps = {}; From 45db35989f3f1d7b15fdae6d0fe3dd7d9fbf9d39 Mon Sep 17 00:00:00 2001 From: Kyle Date: Sun, 23 Mar 2025 17:27:25 +0800 Subject: [PATCH 10/10] Fix Linux build issue --- Package.swift | 3 ++- Sources/OpenGraph_SPI/Data/ptr.hpp | 8 +++--- Sources/OpenGraph_SPI/Data/table.cpp | 26 +++++++++++++++++-- Sources/OpenGraph_SPI/Data/table.hpp | 22 ++++++++++++++-- Sources/OpenGraph_SPI/Data/zone.cpp | 9 +++++++ Sources/OpenGraph_SPI/Util/realloc_vector.hpp | 1 - Sources/OpenGraph_SPI/Vector/vector.tpp | 12 +++++++++ Tests/OpenGraph_SPITests/README.md | 3 +++ Tests/OpenGraph_SPITests/table_test_case.mm | 4 +++ 9 files changed, 77 insertions(+), 11 deletions(-) create mode 100644 Tests/OpenGraph_SPITests/README.md diff --git a/Package.swift b/Package.swift index 239c7d2f..aa86991c 100644 --- a/Package.swift +++ b/Package.swift @@ -152,7 +152,8 @@ let openGraphSPITestTarget = Target.testTarget( cSettings: sharedCSettings + [ .headerSearchPath("../../Sources/OpenGraph_SPI"), ], - swiftSettings: sharedSwiftSettings + swiftSettings: sharedSwiftSettings, + linkerSettings: [.linkedFramework("XCTest")] ) let openGraphShimsTestTarget = Target.testTarget( name: "OpenGraphShimsTests", diff --git a/Sources/OpenGraph_SPI/Data/ptr.hpp b/Sources/OpenGraph_SPI/Data/ptr.hpp index 2901ab83..b1b18322 100644 --- a/Sources/OpenGraph_SPI/Data/ptr.hpp +++ b/Sources/OpenGraph_SPI/Data/ptr.hpp @@ -10,9 +10,7 @@ #include "OGBase.h" #include "table.hpp" -#include #include -#include #include "page_const.hpp" OG_ASSUME_NONNULL_BEGIN @@ -34,7 +32,7 @@ template class ptr { public: OG_INLINE OG_CONSTEXPR ptr(difference_type offset = 0) : _offset(offset){}; - OG_INLINE OG_CONSTEXPR ptr(nullptr_t){}; + OG_INLINE OG_CONSTEXPR ptr(std::nullptr_t){}; OG_INLINE void assert_valid(uint32_t capacity = shared_table().data_capacity()) const { @@ -72,10 +70,10 @@ template class ptr { T *_Nonnull operator->() const OG_NOEXCEPT { return get(); }; OG_INLINE OG_CONSTEXPR - bool operator==(nullptr_t) const OG_NOEXCEPT { return _offset == 0; }; + bool operator==(std::nullptr_t) const OG_NOEXCEPT { return _offset == 0; }; OG_INLINE OG_CONSTEXPR - bool operator!=(nullptr_t) const OG_NOEXCEPT { return _offset != 0; }; + bool operator!=(std::nullptr_t) const OG_NOEXCEPT { return _offset != 0; }; OG_INLINE OG_CONSTEXPR bool operator<(difference_type offset) const OG_NOEXCEPT { return _offset < offset; }; diff --git a/Sources/OpenGraph_SPI/Data/table.cpp b/Sources/OpenGraph_SPI/Data/table.cpp index f81063fd..6a2877ac 100644 --- a/Sources/OpenGraph_SPI/Data/table.cpp +++ b/Sources/OpenGraph_SPI/Data/table.cpp @@ -12,15 +12,25 @@ #include "zone.hpp" #include "../Util/assert.hpp" #include +#include +#if OG_TARGET_OS_DARWIN #include +#else +#include +#endif + +#if OG_TARGET_OS_DARWIN #include +#endif void *OGGraphVMRegionBaseAddress; namespace OG { namespace data { +#if OG_TARGET_OS_DARWIN malloc_zone_t *_Nullable _malloc_zone; +#endif table &table::ensure_shared() { static dispatch_once_t once; @@ -41,14 +51,19 @@ table::table() { } _data_base = reinterpret_cast(region) - page_size; _data_capacity = initial_size + page_size; + #if OG_TARGET_OS_DARWIN if (_malloc_zone == nullptr) { malloc_zone_t *zone = malloc_create_zone(0, 0); _malloc_zone = zone; malloc_set_zone_name(zone, "OpenGraph graph data"); } + #else + precondition_failure("not implemented"); + #endif } void table::grow_region() OG_NOEXCEPT { + #if OG_TARGET_OS_DARWIN uint32_t new_size = 4 * _region_capacity; // Check size does not exceed 32 bits if (new_size <= _region_capacity) { @@ -81,9 +96,13 @@ void table::grow_region() OG_NOEXCEPT { _region_base = reinterpret_cast(new_region); _region_capacity = new_size; _data_capacity = new_size + page_size; + #else + precondition_failure("not implemented"); + #endif } void table::make_pages_reusable(uint32_t page_index, bool reusable) OG_NOEXCEPT { + #if OG_TARGET_OS_DARWIN static constexpr uint32_t mapped_pages_size = page_size * pages_per_map; // 64 * 512 = 0x8000 void *mapped_pages_address = reinterpret_cast(region_base() + ((page_index * page_size) & ~(mapped_pages_size - 1))); int advice = reusable ? MADV_FREE_REUSABLE : MADV_FREE_REUSE; @@ -100,6 +119,9 @@ void table::make_pages_reusable(uint32_t page_index, bool reusable) OG_NOEXCEPT mprotect(mapped_pages_address, mapped_pages_size, protection); } _reusable_pages_num += reusable ? mapped_pages_size : -mapped_pages_size; + #else + precondition_failure("not implemented"); + #endif } // TO BE AUDITED @@ -242,13 +264,13 @@ uint64_t table::raw_page_seed(ptr page) OG_NOEXCEPT { } void table::print() const OG_NOEXCEPT { - os_unfair_lock_lock(&_lock); + lock(); fprintf(stderr, "data::table %p:\n %.2fKB allocated, %.2fKB used, %.2fKB reusable.\n", this, double(_region_capacity - page_size) / 1024.0, double(this->used_pages_num()) / 1024.0, double(_reusable_pages_num) / 1024.0); - os_unfair_lock_unlock(&_lock); + unlock(); } } /* data */ diff --git a/Sources/OpenGraph_SPI/Data/table.hpp b/Sources/OpenGraph_SPI/Data/table.hpp index b610a024..de51d153 100644 --- a/Sources/OpenGraph_SPI/Data/table.hpp +++ b/Sources/OpenGraph_SPI/Data/table.hpp @@ -7,9 +7,17 @@ #include "OGBase.h" #include "../Vector/vector.hpp" +#if OG_TARGET_OS_DARWIN #include +#else +typedef uintptr_t vm_size_t; +typedef uintptr_t vm_offset_t; +typedef vm_offset_t vm_address_t; +#endif #include +#if OG_TARGET_OS_DARWIN #include +#endif namespace OG { namespace data { @@ -32,10 +40,18 @@ class table { vm_address_t region_base() const OG_NOEXCEPT { return _region_base; }; OG_INLINE OG_CONSTEXPR - void lock() const OG_NOEXCEPT { return os_unfair_lock_lock(&_lock); }; + void lock() const OG_NOEXCEPT { + #if OG_TARGET_OS_DARWIN + return os_unfair_lock_lock(&_lock); + #endif + }; OG_INLINE OG_CONSTEXPR - void unlock() const OG_NOEXCEPT { return os_unfair_lock_unlock(&_lock); }; + void unlock() const OG_NOEXCEPT { + #if OG_TARGET_OS_DARWIN + return os_unfair_lock_unlock(&_lock); + #endif + }; OG_INLINE OG_CONSTEXPR uint32_t region_capacity() const OG_NOEXCEPT { return _region_capacity; }; @@ -80,7 +96,9 @@ class table { vm_address_t _region_base; + #if OG_TARGET_OS_DARWIN mutable os_unfair_lock _lock = OS_UNFAIR_LOCK_INIT; + #endif uint32_t _region_capacity; diff --git a/Sources/OpenGraph_SPI/Data/zone.cpp b/Sources/OpenGraph_SPI/Data/zone.cpp index 0f4a3e9d..490f487d 100644 --- a/Sources/OpenGraph_SPI/Data/zone.cpp +++ b/Sources/OpenGraph_SPI/Data/zone.cpp @@ -6,6 +6,11 @@ #include "table.hpp" #include "page.hpp" #include "../Util/assert.hpp" +#if OG_TARGET_OS_DARWIN +#include +#else +#include +#endif namespace OG { namespace data { @@ -96,7 +101,11 @@ void zone::print() const OG_NOEXCEPT { unsigned long num_persistent_buffers = _malloc_buffers.size(); size_t malloc_total_size = 0; for (auto &element : _malloc_buffers) { + #if OG_TARGET_OS_DARWIN malloc_total_size += malloc_size(element.get()); + #else + malloc_total_size += malloc_usable_size(element.get()); + #endif } double malloc_total_size_kb = malloc_total_size / 1024.0; diff --git a/Sources/OpenGraph_SPI/Util/realloc_vector.hpp b/Sources/OpenGraph_SPI/Util/realloc_vector.hpp index 57ca0ddc..558067bf 100644 --- a/Sources/OpenGraph_SPI/Util/realloc_vector.hpp +++ b/Sources/OpenGraph_SPI/Util/realloc_vector.hpp @@ -9,7 +9,6 @@ #define realloc_vector_hpp #include "OGBase.h" -#include OG_ASSUME_NONNULL_BEGIN diff --git a/Sources/OpenGraph_SPI/Vector/vector.tpp b/Sources/OpenGraph_SPI/Vector/vector.tpp index 929ec39b..f11be1e3 100644 --- a/Sources/OpenGraph_SPI/Vector/vector.tpp +++ b/Sources/OpenGraph_SPI/Vector/vector.tpp @@ -9,7 +9,11 @@ #include "../Util/assert.hpp" #include +#if OG_TARGET_OS_DARWIN #include +#else +#include +#endif /* OG_TARGET_OS_DARWIN */ #include #include @@ -34,7 +38,11 @@ void *realloc_vector(void *buffer, void *stack_buffer, size_type stack_size, siz return nullptr; } + #if OG_TARGET_OS_DARWIN size_t new_size_bytes = malloc_good_size(preferred_new_size * element_size_bytes); + #else + size_t new_size_bytes = malloc_good_size(preferred_new_size * element_size_bytes); + #endif size_type new_size = new_size_bytes / element_size_bytes; if (new_size == *size) { // nothing to do @@ -172,7 +180,11 @@ void *realloc_vector(void *buffer, size_type *size, size_type preferred_new_size return nullptr; } + #if OG_TARGET_OS_DARWIN size_t new_size_bytes = malloc_good_size(preferred_new_size * element_size); + #else + size_t new_size_bytes = preferred_new_size * element_size; + #endif size_type new_size = (size_type)(new_size_bytes / element_size); if (new_size == *size) { // nothing to do diff --git a/Tests/OpenGraph_SPITests/README.md b/Tests/OpenGraph_SPITests/README.md new file mode 100644 index 00000000..4230328b --- /dev/null +++ b/Tests/OpenGraph_SPITests/README.md @@ -0,0 +1,3 @@ +## OpenGraph_SPITests + +Test C++ API of OpenGraph_SPI diff --git a/Tests/OpenGraph_SPITests/table_test_case.mm b/Tests/OpenGraph_SPITests/table_test_case.mm index 6a350f1d..aa6fd11c 100644 --- a/Tests/OpenGraph_SPITests/table_test_case.mm +++ b/Tests/OpenGraph_SPITests/table_test_case.mm @@ -2,6 +2,9 @@ // table_test_case.mm // OpenGraph_SPITests +#include "OGBase.h" + +#if OG_TARGET_OS_DARWIN #include #include "Data/table.hpp" @@ -18,3 +21,4 @@ - (void)setUp { } @end +#endif