Skip to content

Commit

Permalink
Unify tag and tagged into top and binder
Browse files Browse the repository at this point in the history
Signed-off-by: yamacir-kit <[email protected]>
  • Loading branch information
yamacir-kit committed Mar 20, 2024
1 parent 71598d9 commit b385305
Show file tree
Hide file tree
Showing 6 changed files with 104 additions and 115 deletions.
6 changes: 3 additions & 3 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -91,7 +91,7 @@ Procedures for each standard are provided by the following R7RS-style libraries:
cmake -B build -DCMAKE_BUILD_TYPE=Release
cd build
make package
sudo apt install build/meevax_0.5.149_amd64.deb
sudo apt install build/meevax_0.5.150_amd64.deb
```

or
Expand Down Expand Up @@ -123,9 +123,9 @@ sudo rm -rf /usr/local/share/meevax

| Target Name | Description
|-------------|-------------
| `all` | Build shared-library `libmeevax.0.5.149.so` and executable `meevax`
| `all` | Build shared-library `libmeevax.0.5.150.so` and executable `meevax`
| `test` | Test executable `meevax`
| `package` | Generate debian package `meevax_0.5.149_amd64.deb`
| `package` | Generate debian package `meevax_0.5.150_amd64.deb`
| `install` | Copy files into `/usr/local` directly

## Usage
Expand Down
2 changes: 1 addition & 1 deletion VERSION
Original file line number Diff line number Diff line change
@@ -1 +1 @@
0.5.149
0.5.150
26 changes: 19 additions & 7 deletions include/meevax/kernel/pair.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -68,7 +68,7 @@ inline namespace kernel
return make<typename Traits<Ts...>::type, Allocator>(std::forward<decltype(xs)>(xs)...);
}

struct pair : public collector::top
struct pair : public virtual collector::top
, public std::pair<object, object>
{
template <auto Const>
Expand Down Expand Up @@ -150,38 +150,50 @@ inline namespace kernel
: std::pair<object, object> { std::forward<decltype(x)>(x), std::forward<decltype(y)>(y) }
{}

~pair() override = default;

auto compare(top const*) const -> bool override;

auto type() const noexcept -> std::type_info const& override;

auto write(std::ostream &) const -> std::ostream & override;

constexpr auto begin() noexcept
auto lower() const noexcept -> std::uintptr_t override
{
return reinterpret_cast<std::uintptr_t>(this);
}

auto upper() const noexcept -> std::uintptr_t override
{
return reinterpret_cast<std::uintptr_t>(this) + sizeof(*this);
}

auto begin() noexcept
{
return iterator(this);
}

constexpr auto begin() const noexcept
auto begin() const noexcept
{
return const_iterator(this);
}

constexpr auto end() noexcept
auto end() noexcept
{
return iterator(nullptr);
}

constexpr auto end() const noexcept
auto end() const noexcept
{
return const_iterator(nullptr);
}

constexpr auto cbegin() const -> const_iterator
auto cbegin() const -> const_iterator
{
return std::as_const(*this).begin();
}

constexpr auto cend() const noexcept
auto cend() const noexcept
{
return std::as_const(*this).end();
}
Expand Down
126 changes: 52 additions & 74 deletions include/meevax/memory/collector.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -44,24 +44,57 @@ inline namespace memory
public:
struct top
{
virtual ~top() = default;

virtual auto compare(top const*) const -> bool = 0;

virtual auto type() const noexcept -> std::type_info const& = 0;

virtual auto write(std::ostream &) const -> std::ostream & = 0;

virtual auto lower() const noexcept -> std::uintptr_t = 0;

virtual auto upper() const noexcept -> std::uintptr_t = 0;

auto contains(void const* const data) const noexcept
{
return reinterpret_cast<void const*>(lower()) <= data and data < reinterpret_cast<void const*>(upper());
}
};

template <typename Top, typename Bound>
struct binder : public virtual Top
static inline auto cleared = false;

template <typename Top, typename Bound, typename AllocatorTraits = std::allocator_traits<std::allocator<void>>>
struct binder : public virtual std::conditional_t<std::is_same_v<Top, Bound>, top, Top>
, public Bound
{
struct allocator_type : public AllocatorTraits::template rebind_alloc<binder<Top, Bound, AllocatorTraits>>
{
~allocator_type()
{
/*
Execute clear before any static allocator is destroyed. Otherwise,
when the destructor of the collector executes clear, the collector
may touch the freed memory of the stateful allocator.
*/
if (not std::exchange(cleared, true))
{
clear();
}
}
};

static inline auto allocator = allocator_type();

template <typename... Us>
explicit constexpr binder(Us&&... xs)
: std::conditional_t<std::is_base_of_v<Top, Bound> and std::is_constructible_v<Top, Us...>, Top, Bound> {
std::forward<decltype(xs)>(xs)...
}
{}

~binder() override = default;

auto compare([[maybe_unused]] top const* other) const -> bool override
{
if constexpr (is_equality_comparable_v<Bound const&>)
Expand Down Expand Up @@ -97,71 +130,16 @@ inline namespace memory
return os << magenta("#,(") << green(typeid(Bound).name()) << faint(" #;", static_cast<Bound const*>(this)) << magenta(")");
}
}
};

struct tag
{
std::size_t size : 16;

std::uintptr_t address : 48;

explicit tag(void const* const address, std::size_t size)
: size { size }
, address { reinterpret_cast<std::uintptr_t>(address) }
{
assert(size < (1u << 16));
}

virtual ~tag() = default;

auto begin() const
{
return mutators.lower_bound(reinterpret_cast<mutator const*>(address));
}

auto end() const
auto lower() const noexcept -> std::uintptr_t override
{
return mutators.lower_bound(reinterpret_cast<mutator const*>(address + size));
return reinterpret_cast<std::uintptr_t>(this);
}

auto contains(void const* const data) const noexcept
auto upper() const noexcept -> std::uintptr_t override
{
return reinterpret_cast<void const*>(address) <= data and data < reinterpret_cast<void const*>(address + size);
return reinterpret_cast<std::uintptr_t>(this) + sizeof(*this);
}
};

static inline auto cleared = false;

template <typename T, typename AllocatorTraits>
struct tagged : public tag
{
struct allocator_type : public AllocatorTraits::template rebind_alloc<tagged<T, AllocatorTraits>>
{
~allocator_type()
{
/*
Execute clear before any static allocator is destroyed. Otherwise,
when the destructor of the collector executes clear, the collector
may touch the freed memory of the stateful allocator.
*/
if (not std::exchange(cleared, true))
{
clear();
}
}
};

static inline auto allocator = allocator_type();

T value;

template <typename... Ts>
explicit tagged(Ts&&... xs)
: tag { std::addressof(value), sizeof(T) }
, value { std::forward<decltype(xs)>(xs)... }
{}

~tagged() override = default;

auto operator new(std::size_t) -> void *
{
Expand All @@ -180,11 +158,11 @@ inline namespace memory
friend class collector;

protected:
tag const* object = nullptr;
top const* object = nullptr;

constexpr mutator() = default;

explicit mutator(tag const* object) noexcept
explicit mutator(top const* object) noexcept
: object { object }
{
if (object)
Expand All @@ -201,7 +179,7 @@ inline namespace memory
}
}

auto reset(tag const* after = nullptr) noexcept -> void
auto reset(top const* after = nullptr) noexcept -> void
{
if (auto before = std::exchange(object, after); not before and after)
{
Expand All @@ -213,7 +191,7 @@ inline namespace memory
}
}

static auto locate(void const* const data) noexcept -> tag const*
static auto locate(void const* const data) noexcept -> top const*
{
if (not data)
{
Expand All @@ -223,7 +201,7 @@ inline namespace memory
{
return cache;
}
else if (auto iter = tags.lower_bound(reinterpret_cast<tag const*>(data)); iter != tags.begin() and (*--iter)->contains(data))
else if (auto iter = objects.lower_bound(reinterpret_cast<top const*>(data)); iter != objects.begin() and (*--iter)->contains(data))
{
return *iter;
}
Expand All @@ -244,9 +222,9 @@ inline namespace memory
using pointer_set = integer_set<T const*, 15, 16, 16>;

private:
static inline tag * cache = nullptr;
static inline top * cache = nullptr;

static inline pointer_set<tag> tags {};
static inline pointer_set<top> objects {};

static inline pointer_set<mutator> mutators {};

Expand Down Expand Up @@ -279,11 +257,11 @@ inline namespace memory
collect();
}

if (auto data = new tagged<T, std::allocator_traits<Allocator>>(std::forward<decltype(xs)>(xs)...); data)
if (auto data = new T(std::forward<decltype(xs)>(xs)...); data)
{
tags.insert(cache = data);
objects.insert(cache = data);

return std::addressof(data->value);
return data;
}
else
{
Expand All @@ -303,11 +281,11 @@ inline namespace memory

static auto dlsym(std::string const&, void * const) -> void *;

static auto mark() noexcept -> pointer_set<tag>;
static auto mark() noexcept -> pointer_set<top>;

static auto mark(tag const* const, pointer_set<tag> &) noexcept -> void;
static auto mark(top const* const, pointer_set<top> &) noexcept -> void;

static auto sweep(pointer_set<tag> &&) -> void;
static auto sweep(pointer_set<top> &&) -> void;
};

static collector default_collector {};
Expand Down
8 changes: 2 additions & 6 deletions include/meevax/memory/gc_pointer.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -97,13 +97,9 @@ inline namespace memory
template <typename Bound, typename Allocator, typename... Us>
static auto make(Us&&... xs) -> gc_pointer
{
if constexpr (std::is_same_v<Bound, Top>)
if constexpr (std::is_class_v<Bound>)
{
return collector::make<Top, Allocator>(std::forward<decltype(xs)>(xs)...);
}
else if constexpr (std::is_class_v<Bound>)
{
return collector::make<collector::binder<Top, Bound>, Allocator>(std::forward<decltype(xs)>(xs)...);
return collector::make<collector::binder<Top, Bound, std::allocator_traits<Allocator>>, Allocator>(std::forward<decltype(xs)>(xs)...);
}
else
{
Expand Down
Loading

0 comments on commit b385305

Please sign in to comment.