Skip to content

Commit

Permalink
Remove the juce RefcountedObject from public access (#95)
Browse files Browse the repository at this point in the history
  • Loading branch information
kunitoki authored May 3, 2023
1 parent 12cf047 commit c1729d5
Show file tree
Hide file tree
Showing 5 changed files with 18 additions and 48 deletions.
41 changes: 9 additions & 32 deletions Manual.md
Original file line number Diff line number Diff line change
Expand Up @@ -48,10 +48,9 @@ Contents
* [3.2 - Lua Lifetime](#32---lua-lifetime)
* [3.3 - Pointers, References, and Pass by Value](#33---pointers-references-and-pass-by-value)
* [3.4 - Shared Lifetime](#34---shared-lifetime)
* [3.4.1 - Class RefCountedObjectPtr](#341---class-refcountedobjectptr)
* [3.4.2 - User-defined Containers](#342---user-defined-containers)
* [3.4.3 - shared_ptr As Container](#343---shared_ptr-as-container)
* [3.4.4 - Container Constructors](#344---container-constructors)
* [3.4.1 - User-defined Containers](#341---user-defined-containers)
* [3.4.2 - shared_ptr As Container](#342---shared_ptr-as-container)
* [3.4.3 - Container Constructors](#343---container-constructors)
* [3.5 - Mixing Lifetimes](#35---mixing-lifetimes)
* [3.6 - Convenience Functions](#36---convenience-functions)

Expand Down Expand Up @@ -1238,29 +1237,7 @@ When a pointer or pointer to const is passed to Lua and the pointer is null (zer

LuaBridge supports a _shared lifetime_ model: dynamically allocated and reference counted objects whose ownership is shared by both Lua and C++. The object remains in existence until there are no remaining C++ or Lua references, and Lua performs its usual garbage collection cycle. A container is recognized by a specialization of the `ContainerTraits` template class. LuaBridge will automatically recognize when a data type is a container when the corresponding specialization is present. Two styles of containers come with LuaBridge, including the necessary specializations.

### 3.4.1 - Class RefCountedObjectPtr

This is an intrusive style container. Your existing class declaration must be changed to be also derived from `RefCountedObject`. Given `class T`, derived from `RefCountedObject`, the container `RefCountedObjectPtr <T>` may be used. In order for reference counts to be maintained properly, all C++ code must store a container instead of the pointer. This is similar in style to `std::shared_ptr` although there are slight differences. For example:

```cpp
// A is reference counted.
struct A : public luabridge::RefCountedObject
{
void foo () { }
};

struct B
{
RefCountedObjectPtr<A> a; // holds a reference to A
};

void bar (luabridge::RefCountedObjectPtr<A> a)
{
a->foo ();
}
```
### 3.4.2 - User-defined Containers
### 3.4.1 - User-defined Containers

If you have your own container, you must provide a specialization of `ContainerTraits` in the `luabridge` namespace for your type before it will be recognized by LuaBridge (or else the code will not compile):

Expand Down Expand Up @@ -1288,14 +1265,14 @@ struct ContainerTraits<CustomContainer<T>>

Containers must be safely constructible from raw pointers to objects that are already referenced by other instances of the container (such as is the case for the provided containers or for example `boost::intrusive_ptr` but not `std::shared_ptr` or `boost::shared_ptr`).

### 3.4.3 - shared_ptr As Container
### 3.4.2 - shared_ptr As Container

Standard containers like `std::shared_ptr` or `boost::shared_ptr` will work in LuaBridge3, but they require special care. This is because of type erasure; when the object goes from C++ to Lua and back to C++, constructing a new shared_ptr from the raw pointer will create another reference count and result in undefined behavior, unless it could intrusively reconstruct the container from a raw pointer.

To overcome this issue classes that should be managed by `shared_ptr` have to provide a way to correctly reconstruct a `shared_ptr` which can be done only if type hold it is deriving publicly from `std::enable_shared_from_this` or `boost::enable_shared_from_this`. No additional specialization of traits is needed in this case.

```cpp
struct A : public std::enable_shared_from_this
struct A : public std::enable_shared_from_this<A>
{
A () { }
A (int) { }
Expand Down Expand Up @@ -1326,12 +1303,12 @@ anotherA2 = A (1)
anotherA2.foo ()
```

### 3.4.4 - Container Constructors
### 3.4.3 - Container Constructors

When a constructor is registered for a class, there is an additional optional second template parameter describing the type of container to use. If this parameter is specified, calls to the constructor will create the object dynamically, via operator new, and place it a container of that type. The container must have been previously specialized in `ContainerTraits`, or else a compile error will result. This code will register two objects, each using a constructor that creates an object with Lua lifetime using the specified container:

```cpp
class C : public luabridge::RefCountedObject
class C : public std::enable_shared_from_this<C>
{
C () { }
C (int) { }
Expand All @@ -1340,7 +1317,7 @@ class C : public luabridge::RefCountedObject
luabridge::getGlobalNamespace (L)
.beginNamespace ("test")
.beginClass <C> ("C")
.addConstructorFrom<luabridge::RefCountedObjectPtr<C>, void(), void(int)> ()
.addConstructorFrom<std::shared_ptr<C>, void(), void(int)> ()
.endClass ()
.endNamespace ()
```
Expand Down
1 change: 0 additions & 1 deletion Source/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ set (LUABRIDGE_HEADERS
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/List.h
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/LuaBridge.h
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/Map.h
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/RefCountedObject.h
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/Set.h
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/UnorderedMap.h
${CMAKE_CURRENT_SOURCE_DIR}/LuaBridge/Vector.h)
Expand Down
2 changes: 0 additions & 2 deletions Tests/Source/LegacyTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,8 +9,6 @@
#include "TestBase.h"
#include "LegacyTests.h"

#include "LuaBridge/RefCountedObject.h"

#include <cstring>
#include <iostream>
#include <memory>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,13 +39,10 @@

#pragma once

#include "detail/Config.h"
#include "detail/TypeTraits.h"
#include "TestBase.h"

#include <utility>

namespace luabridge {

//==============================================================================
/**
Adds reference-counting to an object.
Expand Down Expand Up @@ -355,6 +352,7 @@ bool operator!=(ReferenceCountedObjectClass* object1,
}

//==============================================================================
namespace luabridge {

template<class T>
struct ContainerTraits<RefCountedObjectPtr<T>>
Expand All @@ -366,6 +364,4 @@ struct ContainerTraits<RefCountedObjectPtr<T>>
static T* get(RefCountedObjectPtr<T> const& c) { return c.getObject(); }
};

//==============================================================================

} // namespace luabridge
14 changes: 7 additions & 7 deletions Tests/Source/RefCountedPtrTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@

#include "TestBase.h"

#include "LuaBridge/RefCountedObject.h"
#include "RefCountedObject.h"

struct RefCountedPtrTests : TestBase
{
Expand All @@ -18,7 +18,7 @@ struct RefCountedPtrTests : TestBase

namespace {

struct RefCounted : luabridge::RefCountedObject
struct RefCounted : RefCountedObject
{
explicit RefCounted(bool& deleted) : deleted(deleted) { deleted = false; }

Expand All @@ -29,7 +29,7 @@ struct RefCounted : luabridge::RefCountedObject
bool& deleted;
};

struct RefCountedStatic : luabridge::RefCountedObject
struct RefCountedStatic : RefCountedObject
{
explicit RefCountedStatic() { constructed = true; }

Expand All @@ -48,11 +48,11 @@ TEST_F(RefCountedPtrTests, Operators)
{
bool deleted1 = false;
auto* raw_ptr1 = new RefCounted(deleted1);
luabridge::RefCountedObjectPtr<RefCounted> ptr1(raw_ptr1);
RefCountedObjectPtr<RefCounted> ptr1(raw_ptr1);

bool deleted2 = false;
auto* raw_ptr2 = new RefCounted(deleted2);
luabridge::RefCountedObjectPtr<RefCounted> ptr2(raw_ptr2);
RefCountedObjectPtr<RefCounted> ptr2(raw_ptr2);

ASSERT_TRUE(raw_ptr1 == ptr1.getObject());
ASSERT_TRUE(ptr1.getObject() == raw_ptr1);
Expand All @@ -67,7 +67,7 @@ TEST_F(RefCountedPtrTests, LastReferenceInLua)

bool deleted = false;

luabridge::RefCountedObjectPtr<RefCounted> object(new RefCounted(deleted));
RefCountedObjectPtr<RefCounted> object(new RefCounted(deleted));

luabridge::setGlobal(L, object, "object");
runLua("result = object.deleted");
Expand Down Expand Up @@ -95,7 +95,7 @@ TEST_F(RefCountedPtrTests, LastReferenceInCpp)

bool deleted = false;

luabridge::RefCountedObjectPtr<RefCounted> object(new RefCounted(deleted));
RefCountedObjectPtr<RefCounted> object(new RefCounted(deleted));

luabridge::setGlobal(L, object, "object");
runLua("result = object.deleted");
Expand Down

0 comments on commit c1729d5

Please sign in to comment.