Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
51 commits
Select commit Hold shift + click to select a range
e85418b
issue-2282: PL changes
shewitt-au May 31, 2025
bbace8d
Remove debugging code
shewitt-au May 31, 2025
9d63054
Hard to get every one. time...
shewitt-au May 31, 2025
db3c947
Hard to get every one
shewitt-au May 31, 2025
1b5c8f6
WIP
shewitt-au Jun 1, 2025
e1b869d
WIP
shewitt-au Jun 1, 2025
fdf3df4
WIP
shewitt-au Jun 1, 2025
ad24e44
WIP
shewitt-au Jun 1, 2025
c004860
WIP
shewitt-au Jun 1, 2025
b2606d8
WIP
shewitt-au Jun 1, 2025
1214cd8
WIP
shewitt-au Jun 1, 2025
4295ce6
WIP
shewitt-au Jun 1, 2025
5e0b38b
WIP
shewitt-au Jun 1, 2025
ab9a3a9
WIP
shewitt-au Jun 1, 2025
f7d6fc0
WIP
shewitt-au Jun 1, 2025
2ac6ba9
WIP
shewitt-au Jun 1, 2025
c5496e1
WIP
shewitt-au Jun 1, 2025
29be2d2
WIP
shewitt-au Jun 2, 2025
4e07ab2
Taking a slightly different approach
shewitt-au Jun 2, 2025
8ea5dc4
Add 'construct_shared_object.hpp'
shewitt-au Jun 2, 2025
324a136
WIP
shewitt-au Jun 2, 2025
3ec6ae2
WIP
shewitt-au Jun 2, 2025
9489b3c
It builds
shewitt-au Jun 2, 2025
c6095e6
Change comment
shewitt-au Jun 2, 2025
830d0ee
fix: post_construct not being called on some compilers
shewitt-au Jun 3, 2025
ce784c4
Attempt and strange problem casuing build isssues
shewitt-au Jun 3, 2025
32037d1
Attempt and strange problem casuing build isssues
shewitt-au Jun 3, 2025
8a008a2
Attempt and strange problem casuing build isssues
shewitt-au Jun 3, 2025
7c0884b
Replace more make_shared calls
shewitt-au Jun 3, 2025
a47cc5f
Work on unit tests
shewitt-au Jun 3, 2025
e1fd97a
Work on unit tests
shewitt-au Jun 3, 2025
b17db3f
Work on unit tests
shewitt-au Jun 3, 2025
093a4e1
Work on unit tests
shewitt-au Jun 3, 2025
c40fbe3
Work on unit tests
shewitt-au Jun 3, 2025
ab43e67
Work on unit tests
shewitt-au Jun 3, 2025
bb5bc62
Work on unit tests
shewitt-au Jun 3, 2025
36deb13
Fixing tests
shewitt-au Jun 4, 2025
3eb2833
Fixing tests
shewitt-au Jun 4, 2025
cab951b
Fixing tests
shewitt-au Jun 4, 2025
8e82fdd
Fixing tests
shewitt-au Jun 4, 2025
6173dfc
Fixing tests
shewitt-au Jun 4, 2025
21fa172
Make all patterns I could find have protected constructors
shewitt-au Jun 4, 2025
3291051
Change static cast to dynamic
shewitt-au Jun 5, 2025
29b7486
Moved friend declations to end of class
shewitt-au Jun 5, 2025
c308e82
New allocation method (WIP)
shewitt-au Jun 6, 2025
1fd2401
It's looking like it may actually buid. We'll soon know
shewitt-au Jun 6, 2025
e380aeb
Last claims premature
shewitt-au Jun 6, 2025
aaae498
Move stuff around
shewitt-au Jun 6, 2025
9694a1c
New allocation method. Other small changes
shewitt-au Jun 7, 2025
13ec0b8
Renamed some stuff
shewitt-au Jun 8, 2025
cbd3f62
Renamed some stuff
shewitt-au Jun 8, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion lib/include/pl/api.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -126,7 +126,7 @@ namespace pl::api {
/**
* @brief A function callback called when a custom built-in type is being instantiated
*/
using TypeCallback = std::function<std::unique_ptr<ptrn::Pattern>(core::Evaluator *, const std::vector<core::Token::Literal> &)>;
using TypeCallback = std::function<std::shared_ptr<ptrn::Pattern>(core::Evaluator *, const std::vector<core::Token::Literal> &)>;

/**
* @brief A type representing a function.
Expand Down
131 changes: 131 additions & 0 deletions lib/include/pl/helpers/create_shared_object.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
// create_shared_object.hpp
//
// Written by Stephen Hewitt in 2025
// GitHub repo: https://github.com/shewitt-au/std-enable_shared_from_this-and-constructors

#pragma once
/*
The motivation for this code is issues with std::shared_ptr and
std::enable_shared_from_this.

Consider code like this:
std::shared<SomeClass> ptr = std::make_shared<SomeClass>();

Assume that SomeClass's constructor uses shared_from_this. In this case, since
SomeClass is not yet owned by a std::shared_ptr, the shared_from_this call will
not work as expected. There seems to no way around this that I can find.
I wasn't aware of this issue. It was a real kick in the pants.

The solution implemented here is two-stage construction. First the object is
constructed and assigned to a std::shared_ptr; then, if present, a
post_construct method is called with the same arguments. All code that uses
shared_from_this in the constructors should be moved to a post_construct method.
The intent of the "if present" is to enable incremental migration to two-stage
construction on demand.

Another issue addressed is with std::make_shared. This function requires that
the constructor be public. If we're making factory methods for creation, we may
want to make the constructors non-public to stop misuse. The solution to this
problem I can't take credit for.

The code for enable_shared_with_nonpublic_constructor is based on code found here
(called safe_enable_shared_from_this):
https://stackoverflow.com/questions/8147027/how-do-i-call-stdmake-shared-on-a-class-with-only-protected-or-private-const
Posted by stackoverflow member Carsten.
He adapted old code from stackoverflow member Zsolt Rizsányi,
who in turn says it was invented by Jonathan Wakely (GCC developer).

I have made minor modifications to suit and added comments.

Requires C++23
*/

#include <memory>
#include <utility>

// Used to enable create_shared_object to access non-public constructors.
#define BEFRIEND_CREATE_SHARED_OBJECT(T) \
friend struct shared_object_creator::enable_shared_with_nonpublic_constructor::Allocator<T>;

namespace shared_object_creator {

// enable_shared_with_nonpublic_constructor was found here:
// https://stackoverflow.com/questions/8147027/how-do-i-call-stdmake-shared-on-a-class-with-only-protected-or-private-const
//
// Posted by stackoverflow member Carsten.
// He adapted old code from stackoverflow member Zsolt Rizsányi,
// who in turn says it was invented by Jonathan Wakely (GCC developer).
class enable_shared_with_nonpublic_constructor : public std::enable_shared_from_this<enable_shared_with_nonpublic_constructor> {
// Our friends. They're not from around here and have long hard to pronounce names.
template<typename T, typename... Args>
requires requires(T t, Args&&... args) {
t.post_construct(std::forward<Args>(args)...);
}
friend std::shared_ptr<T> create_shared_object(Args&&... args);

template<typename T, typename... Args>
friend std::shared_ptr<T> create_shared_object(Args&&... args);

public:
virtual ~enable_shared_with_nonpublic_constructor() noexcept = default;

// The next two functions use C++23's "explicit object parameter"
// syntax to make shared_from_this and weak_from_this, when called
// from derived classes, return a std::shared_ptr<T> with T being
// the derived type.
template <typename TSelf>
auto inline shared_from_this(this TSelf&& self) noexcept
{
return std::static_pointer_cast<std::remove_reference_t<TSelf>>(
std::forward<TSelf>(self).std::template enable_shared_from_this<enable_shared_with_nonpublic_constructor>::shared_from_this());
}

template <typename TSelf>
auto inline weak_from_this(this TSelf&& self) noexcept -> ::std::weak_ptr<std::remove_reference_t<TSelf>>
{
return std::static_pointer_cast<std::remove_reference_t<TSelf>>(
std::forward<TSelf>(self).std::template enable_shared_from_this<enable_shared_with_nonpublic_constructor>::weak_from_this().lock());
}

protected:
enable_shared_with_nonpublic_constructor() noexcept = default;
enable_shared_with_nonpublic_constructor(enable_shared_with_nonpublic_constructor&&) noexcept = default;
enable_shared_with_nonpublic_constructor(const enable_shared_with_nonpublic_constructor&) noexcept = default;
enable_shared_with_nonpublic_constructor& operator=(enable_shared_with_nonpublic_constructor&&) noexcept = default;
enable_shared_with_nonpublic_constructor& operator=(const enable_shared_with_nonpublic_constructor&) noexcept = delete;

template <typename T>
struct Allocator : public std::allocator<T>
{
template<typename TParent, typename... TArgs>
void construct(TParent* parent, TArgs&&... args)
{ ::new((void *)parent) TParent(std::forward<TArgs>(args)...); }
};

private:
// std::allocate_share, like std::make_shared, allocates both the object
// and the control block using only a single allocation.
template <typename T, typename... TArgs>
static inline auto create(TArgs&&... args) -> std::shared_ptr<T> {
return std::allocate_shared<T>(Allocator<T>{}, std::forward<TArgs>(args)...);
}
};

// The actual creation functions.

template<typename T, typename... Args>
requires requires(T t, Args&&... args) {
t.post_construct(std::forward<Args>(args)...);
}
std::shared_ptr<T> create_shared_object(Args&&... args) {
auto p = enable_shared_with_nonpublic_constructor::create<T>(std::forward<Args>(args)...);
p->post_construct(std::forward<Args>(args)...);
return p;
}

template<typename T, typename... Args>
std::shared_ptr<T> create_shared_object(Args&&... args) {
return enable_shared_with_nonpublic_constructor::create<T>(std::forward<Args>(args)...);
}

} // namespace shared_object_creator
24 changes: 16 additions & 8 deletions lib/include/pl/patterns/pattern.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
#include <pl/pattern_visitor.hpp>
#include <pl/helpers/types.hpp>
#include <pl/helpers/utils.hpp>
#include <pl/helpers/create_shared_object.hpp>

#include <fmt/core.h>

Expand All @@ -14,6 +15,8 @@
#include <concepts>
#include <string>

using namespace shared_object_creator;

namespace pl::ptrn {
using namespace ::std::literals::string_literals;

Expand Down Expand Up @@ -61,13 +64,14 @@ namespace pl::ptrn {
friend class core::Evaluator;
};

class Pattern : public std::enable_shared_from_this<Pattern> {
class Pattern : public enable_shared_with_nonpublic_constructor {
public:
constexpr static u64 MainSectionId = 0x0000'0000'0000'0000;
constexpr static u64 HeapSectionId = 0xFFFF'FFFF'FFFF'FFFF;
constexpr static u64 PatternLocalSectionId = 0xFFFF'FFFF'FFFF'FFFE;
constexpr static u64 InstantiationSectionId = 0xFFFF'FFFF'FFFF'FFFD;

protected:
Pattern(core::Evaluator *evaluator, u64 offset, size_t size, u32 line)
: m_evaluator(evaluator), m_line(line), m_offset(offset), m_size(size) {

Expand All @@ -82,7 +86,7 @@ namespace pl::ptrn {

}

Pattern(const Pattern &other) : std::enable_shared_from_this<Pattern>(other) {
Pattern(const Pattern &other) : enable_shared_with_nonpublic_constructor(other) {
this->m_evaluator = other.m_evaluator;
this->m_offset = other.m_offset;
this->m_endian = other.m_endian;
Expand All @@ -109,13 +113,15 @@ namespace pl::ptrn {
}
}

public:
virtual ~Pattern() {
if (this->m_evaluator != nullptr) {
this->m_evaluator->patternDestroyed(this);
}
}

virtual std::shared_ptr<Pattern> clone() const = 0;
std::shared_ptr<const Pattern> reference() const { return shared_from_this(); }
std::shared_ptr<Pattern> reference() { return shared_from_this(); }

[[nodiscard]] u64 getOffset() const { return this->m_offset; }
Expand Down Expand Up @@ -537,15 +543,15 @@ namespace pl::ptrn {
this->m_initialized = initialized;
}

[[nodiscard]] const Pattern* getParent() const {
return m_parent;
[[nodiscard]] const std::shared_ptr<Pattern> getParent() const {
return m_parent.lock();
}

[[nodiscard]] Pattern* getParent() {
return m_parent;
[[nodiscard]] std::shared_ptr<Pattern> getParent() {
return m_parent.lock();
}

void setParent(Pattern *parent) {
void setParent(std::shared_ptr<Pattern> parent) {
m_parent = parent;
}

Expand Down Expand Up @@ -623,7 +629,7 @@ namespace pl::ptrn {
core::Evaluator *m_evaluator;

std::unique_ptr<std::map<std::string, std::vector<core::Token::Literal>>> m_attributes;
Pattern *m_parent = nullptr;
std::weak_ptr<Pattern> m_parent;
u32 m_line = 0;

std::set<std::string>::const_iterator m_variableName;
Expand All @@ -641,6 +647,8 @@ namespace pl::ptrn {
bool m_initialized = false;

bool m_manualColor = false;

BEFRIEND_CREATE_SHARED_OBJECT(Pattern)
};

}
13 changes: 9 additions & 4 deletions lib/include/pl/patterns/pattern_array_dynamic.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,11 +7,14 @@ namespace pl::ptrn {
class PatternArrayDynamic : public Pattern,
public IInlinable,
public IIndexable {
public:
protected:
PatternArrayDynamic(core::Evaluator *evaluator, u64 offset, size_t size, u32 line)
: Pattern(evaluator, offset, size, line) { }

PatternArrayDynamic(const PatternArrayDynamic &other) : Pattern(other) {
PatternArrayDynamic(const PatternArrayDynamic &other) : Pattern(other) {}

public:
void post_construct(const PatternArrayDynamic &other) {
std::vector<std::shared_ptr<Pattern>> entries;
for (const auto &entry : other.m_entries)
entries.push_back(entry->clone());
Expand All @@ -20,7 +23,7 @@ namespace pl::ptrn {
}

[[nodiscard]] std::shared_ptr<Pattern> clone() const override {
return std::unique_ptr<Pattern>(new PatternArrayDynamic(*this));
return create_shared_object<PatternArrayDynamic>(*this);
}

void setColor(u32 color) override {
Expand Down Expand Up @@ -133,7 +136,7 @@ namespace pl::ptrn {

if (!entry->hasOverriddenColor())
entry->setBaseColor(this->getColor());
entry->setParent(this);
entry->setParent(this->reference());

this->m_entries.emplace_back(entry);
}
Expand Down Expand Up @@ -237,6 +240,8 @@ namespace pl::ptrn {

private:
std::vector<std::shared_ptr<Pattern>> m_entries;

BEFRIEND_CREATE_SHARED_OBJECT(PatternArrayDynamic)
};

}
13 changes: 9 additions & 4 deletions lib/include/pl/patterns/pattern_array_static.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,16 +7,19 @@ namespace pl::ptrn {
class PatternArrayStatic : public Pattern,
public IInlinable,
public IIndexable {
public:
protected:
PatternArrayStatic(core::Evaluator *evaluator, u64 offset, size_t size, u32 line)
: Pattern(evaluator, offset, size, line) { }

PatternArrayStatic(const PatternArrayStatic &other) : Pattern(other) {
PatternArrayStatic(const PatternArrayStatic &other) : Pattern(other) {}

public:
void post_construct(const PatternArrayStatic &other) {
this->setEntries(other.getTemplate()->clone(), other.getEntryCount());
}

[[nodiscard]] std::shared_ptr<Pattern> clone() const override {
return std::unique_ptr<Pattern>(new PatternArrayStatic(*this));
return create_shared_object<PatternArrayStatic>(*this);
}

[[nodiscard]] std::shared_ptr<Pattern> getEntry(size_t index) const override {
Expand Down Expand Up @@ -153,7 +156,7 @@ namespace pl::ptrn {

void setEntries(std::shared_ptr<Pattern> &&templatePattern, size_t count) {
this->m_template = std::move(templatePattern);
this->m_template->setParent(this);
this->m_template->setParent(this->reference());
this->m_highlightTemplates.push_back(this->m_template->clone());
this->m_entryCount = count;

Expand Down Expand Up @@ -252,6 +255,8 @@ namespace pl::ptrn {
std::shared_ptr<Pattern> m_template = nullptr;
mutable std::vector<std::shared_ptr<Pattern>> m_highlightTemplates;
size_t m_entryCount = 0;

BEFRIEND_CREATE_SHARED_OBJECT(PatternArrayStatic)
};

}
Loading
Loading