Cleaned up the ballistica::Object class and its reference types to try and minimize ambiguity

This commit is contained in:
Eric 2023-10-05 11:56:14 -07:00
parent a3c4d0e07e
commit a2ea720bb9
No known key found for this signature in database
GPG Key ID: 89C93F0F8D6D5A98
20 changed files with 245 additions and 220 deletions

90
.efrocachemap generated
View File

@ -1,5 +1,5 @@
{
"ballisticakit-windows/Generic/BallisticaKit.ico": "0611a2b624f01b5e6939f2dd810add5b",
"ballisticakit-windows/Generic/BallisticaKit.ico": "be1b956dcd7f7a261b1afe5bce2a0336",
"build/assets/ba_data/audio/achievement.ogg": "079a366ce183b25a63550ef7072af605",
"build/assets/ba_data/audio/actionHero1.ogg": "f0f986f268f036a5ac2f940e07f2f27e",
"build/assets/ba_data/audio/actionHero2.ogg": "204a6735dc655f0975cf8308b585f2fd",
@ -4056,50 +4056,50 @@
"build/assets/windows/Win32/ucrtbased.dll": "2def5335207d41b21b9823f6805997f1",
"build/assets/windows/Win32/vc_redist.x86.exe": "b08a55e2e77623fe657bea24f223a3ae",
"build/assets/windows/Win32/vcruntime140d.dll": "865b2af4d1e26a1a8073c89acb06e599",
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "00df85426f2fd425284d788ad2001163",
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "ec7fd15e05dc966ed5fe2dc53082b8dc",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "5a07480211a13748414bccdb33ab50e0",
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "cee4f0b1f606e2cd4e0084821803bbda",
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "ec670868f9b49d8b300e7c096d45fccd",
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "55e11d3f9f2dafbe4a785ad8d53a5191",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "66a165dce9b2576796b61a0190ee2360",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "0973f550afc8dc1a966f0cf34119bdee",
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "be55036d49b2aac4f7fb34acda7ae46a",
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "0b5b2fcbe365f1465d1eaf6663efddef",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "198ab1ae413439560c94e7e70dccb8e1",
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "832d429448bf666876ecc2dfbdce6ac1",
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "42a60e06d573fd770bf085d1de1e8426",
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "4b3b7f626517f5b83973e23728182fa0",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "b7b82fe0bef26f414f952038982ba94c",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "99156961b81f9849e7055f5e73449735",
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "93ae112921fa541badb6844eb913b825",
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "08a27186747d3a1fe854014243d39550",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "10ec7da590f68e1cc1a6f9b9ed4abf25",
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "c76a8d161dae2b3ec3ae2898803e6387",
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "76d9f578bc7395af5ddef379a85e6354",
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "48dd3167591df4494852c6c3e9047f1b",
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "76d9f578bc7395af5ddef379a85e6354",
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "48dd3167591df4494852c6c3e9047f1b",
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "4a757f9ede607532cd5c8c2589f05bb4",
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "9a9e18d3856e343c3ca6ac136a64235a",
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "4a757f9ede607532cd5c8c2589f05bb4",
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "9a9e18d3856e343c3ca6ac136a64235a",
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "da8bef9f3989024b8f45b7c27d41ce06",
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "f2f9159cd08054e71ed87db479b18d21",
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "da8bef9f3989024b8f45b7c27d41ce06",
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "f2f9159cd08054e71ed87db479b18d21",
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "dfb64c08a34939df60bae54579cc662c",
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "0c0e93911fda8343f06b76a84b2331a3",
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "5414ebd032c5b437f0b6a6ea952667d0",
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "0c0e93911fda8343f06b76a84b2331a3",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "c376e54bfa43c7411464c86b7ebbe7d2",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "92509f7dbfdd5628f71a9f5e0453c1de",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "187084265adac8497ebd6f43b82c6a9f",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "bf66ac68f2d9deea5f310e3e8a40e4da",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "c570f55f73054b411dbaca428062c3d7",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "0fa9d0afbbe2fb2de1a19a6be66d04d2",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "c08bdaebba8bbbe2a92a6c17b11a8ccc",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "17809e9b9a2e62cb49d952ac41d79a13",
"build/prefab/full/linux_arm64_gui/debug/ballisticakit": "6cdefa5cd565abee912694fb28d828d3",
"build/prefab/full/linux_arm64_gui/release/ballisticakit": "c51444bf5d10839e45a347c3200a6055",
"build/prefab/full/linux_arm64_server/debug/dist/ballisticakit_headless": "0ab2bbf81b5a23d9cd0df2c8c71d1df8",
"build/prefab/full/linux_arm64_server/release/dist/ballisticakit_headless": "767696047eb3faa9dcab8edcef4e776b",
"build/prefab/full/linux_x86_64_gui/debug/ballisticakit": "18ef5fd23969bbd009bb1360a161fca4",
"build/prefab/full/linux_x86_64_gui/release/ballisticakit": "680935c4c7d3cfe1d74afdb5376c55a2",
"build/prefab/full/linux_x86_64_server/debug/dist/ballisticakit_headless": "7fd4da4a5ef6ed013fad3e5ab360cbae",
"build/prefab/full/linux_x86_64_server/release/dist/ballisticakit_headless": "65fa11a84646d483601ee37a0c1ba653",
"build/prefab/full/mac_arm64_gui/debug/ballisticakit": "530214ddb822998dfdb61107dded1802",
"build/prefab/full/mac_arm64_gui/release/ballisticakit": "52924ddffd34be9cb9b78ef4757a7f45",
"build/prefab/full/mac_arm64_server/debug/dist/ballisticakit_headless": "a9b3849992aa832e2265f626e46773f4",
"build/prefab/full/mac_arm64_server/release/dist/ballisticakit_headless": "e56702bd5e1fd7e5c613ea6dd4b8801a",
"build/prefab/full/mac_x86_64_gui/debug/ballisticakit": "c96db4026b4ff8d7b2f6fd189778db50",
"build/prefab/full/mac_x86_64_gui/release/ballisticakit": "de5638c952f8d71b26235f30bc957f2c",
"build/prefab/full/mac_x86_64_server/debug/dist/ballisticakit_headless": "17d898335005122c303ea1811dd06c77",
"build/prefab/full/mac_x86_64_server/release/dist/ballisticakit_headless": "0941c6dfb7b7a5ebfc0e4e8f93cb3fb7",
"build/prefab/full/windows_x86_gui/debug/BallisticaKit.exe": "cdcdb3a9fc357e025ce2ed6d864a0e80",
"build/prefab/full/windows_x86_gui/release/BallisticaKit.exe": "d68b729ed88d9eef64bc1a40cc34b67f",
"build/prefab/full/windows_x86_server/debug/dist/BallisticaKitHeadless.exe": "fa3cd09737f23271f66ca7d7bb1e629a",
"build/prefab/full/windows_x86_server/release/dist/BallisticaKitHeadless.exe": "4ea0a028f40afc4456135f34a95d652b",
"build/prefab/lib/linux_arm64_gui/debug/libballisticaplus.a": "dd14e0abacf5a27d9823b0a41127e3e3",
"build/prefab/lib/linux_arm64_gui/release/libballisticaplus.a": "bd994ca8a1896ada5c582be155db5c36",
"build/prefab/lib/linux_arm64_server/debug/libballisticaplus.a": "dd14e0abacf5a27d9823b0a41127e3e3",
"build/prefab/lib/linux_arm64_server/release/libballisticaplus.a": "bd994ca8a1896ada5c582be155db5c36",
"build/prefab/lib/linux_x86_64_gui/debug/libballisticaplus.a": "d855693f8342c4080ce0f452784e5cf9",
"build/prefab/lib/linux_x86_64_gui/release/libballisticaplus.a": "eeaf4e383752fdcdaaae1cb863208870",
"build/prefab/lib/linux_x86_64_server/debug/libballisticaplus.a": "d855693f8342c4080ce0f452784e5cf9",
"build/prefab/lib/linux_x86_64_server/release/libballisticaplus.a": "eeaf4e383752fdcdaaae1cb863208870",
"build/prefab/lib/mac_arm64_gui/debug/libballisticaplus.a": "ba391e47cc87b609ea794cdf9e693163",
"build/prefab/lib/mac_arm64_gui/release/libballisticaplus.a": "84e913835ae280a59045bed189c920b0",
"build/prefab/lib/mac_arm64_server/debug/libballisticaplus.a": "ba391e47cc87b609ea794cdf9e693163",
"build/prefab/lib/mac_arm64_server/release/libballisticaplus.a": "84e913835ae280a59045bed189c920b0",
"build/prefab/lib/mac_x86_64_gui/debug/libballisticaplus.a": "8f147ca53e6e261becb37d7ff5490b59",
"build/prefab/lib/mac_x86_64_gui/release/libballisticaplus.a": "7d386ab4fc78cc7598188df82bf4f04a",
"build/prefab/lib/mac_x86_64_server/debug/libballisticaplus.a": "5627e6b08b61024650420b849d41721b",
"build/prefab/lib/mac_x86_64_server/release/libballisticaplus.a": "7d386ab4fc78cc7598188df82bf4f04a",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.lib": "36dc4b524796e12a1bda3dd96cc5a102",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitGenericPlus.pdb": "6e97a4ada89c867ea6795b792a37091a",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.lib": "1aeee25b763b80b7f291e5adfd025557",
"build/prefab/lib/windows/Debug_Win32/BallisticaKitHeadlessPlus.pdb": "6903271f88d2a904fb0394e99098f746",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.lib": "c2888b185b9ac3ddae1db665839765b5",
"build/prefab/lib/windows/Release_Win32/BallisticaKitGenericPlus.pdb": "e7a19af8da2c3910080d411a11429723",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.lib": "9093de58a5aa33b8061057ac500a3f6d",
"build/prefab/lib/windows/Release_Win32/BallisticaKitHeadlessPlus.pdb": "93dcf1b0a3d140c51eb550e6d95128d1",
"src/assets/ba_data/python/babase/_mgen/__init__.py": "f885fed7f2ed98ff2ba271f9dbe3391c",
"src/assets/ba_data/python/babase/_mgen/enums.py": "f8cd3af311ac63147882590123b78318",
"src/ballistica/base/mgen/pyembed/binding_base.inc": "9f71f171464dc004dbaab87e9bb4b03b",

View File

@ -1,4 +1,4 @@
### 1.7.28 (build 21418, api 8, 2023-10-05)
### 1.7.28 (build 21421, api 8, 2023-10-05)
- Massively cleaned up code related to rendering and window systems (OpenGL,
SDL, etc). This code had been growing into a nasty tangle for 15 years
@ -101,6 +101,9 @@
- Now that all our compilers support it, updating from the C++17 standard to
C++20. This will allow a few useful things such as being able to pack 8 bools
into 1 byte.
- Created a custom icon for BallisticaKit (previously it was just the BombSquad
icon with an ugly 'C' on it). BombSquad itself will still have the BombSquad
icon.
### 1.7.27 (build 21282, api 8, 2023-08-30)

View File

@ -52,7 +52,7 @@ if TYPE_CHECKING:
# Build number and version of the ballistica binary we expect to be
# using.
TARGET_BALLISTICA_BUILD = 21418
TARGET_BALLISTICA_BUILD = 21421
TARGET_BALLISTICA_VERSION = '1.7.28'

View File

@ -473,7 +473,7 @@ auto Assets::GetAsset(const std::string& file_name,
MarkAssetForLoad(d.Get());
}
d->set_last_used_time(g_core->GetAppTimeMillisecs());
return d;
return Object::Ref<T>(d);
}
}
@ -485,7 +485,7 @@ auto Assets::GetTexture(TextPacker* packer) -> Object::Ref<TextureAsset> {
if (i != text_textures_.end()) {
return Object::Ref<TextureAsset>(i->second.Get());
} else {
auto d(Object::New<TextureAsset>(packer));
auto d{Object::New<TextureAsset>(packer)};
text_textures_[hash] = d;
{
Asset::LockGuard lock(d.Get());
@ -493,7 +493,7 @@ auto Assets::GetTexture(TextPacker* packer) -> Object::Ref<TextureAsset> {
MarkAssetForLoad(d.Get());
}
d->set_last_used_time(g_core->GetAppTimeMillisecs());
return d;
return Object::Ref<TextureAsset>(d);
}
}
@ -513,7 +513,7 @@ auto Assets::GetQRCodeTexture(const std::string& url)
MarkAssetForLoad(d.Get());
}
d->set_last_used_time(g_core->GetAppTimeMillisecs());
return d;
return Object::Ref<TextureAsset>(d);
}
}
@ -536,7 +536,7 @@ auto Assets::GetCubeMapTexture(const std::string& file_name)
MarkAssetForLoad(d.Get());
}
d->set_last_used_time(g_core->GetAppTimeMillisecs());
return d;
return Object::Ref<TextureAsset>(d);
}
}
@ -592,7 +592,7 @@ auto Assets::GetTexture(const std::string& file_name)
MarkAssetForLoad(d.Get());
}
d->set_last_used_time(g_core->GetAppTimeMillisecs());
return d;
return Object::Ref<TextureAsset>(d);
}
}

View File

@ -1002,7 +1002,7 @@ void TextGraphics::GetOSTextSpanBoundsAndWidth(const std::string& s, Rect* r,
// so let's use a cache of recent results.
auto i = text_span_bounds_cache_map_.find(s);
if (i != text_span_bounds_cache_map_.end()) {
Object::Ref<TextSpanBoundsCacheEntry> entry = i->second;
auto entry = Object::Ref<TextSpanBoundsCacheEntry>(i->second);
*r = entry->r;
*width = entry->width;

View File

@ -369,7 +369,7 @@ void Input::RemoveInputDevice(InputDevice* input, bool standard_message) {
if (input_device.Exists() && (input_device.Get() == input)) {
// Pull it off the list before killing it (in case it tries to trigger
// another kill itself).
Object::Ref<InputDevice> device = input_device;
auto device = Object::Ref<InputDevice>(input_device);
// Ok we cleared its slot in our vector; now we just have
// the local variable 'device' keeping it alive.

View File

@ -30,7 +30,7 @@ static auto GetAsset(std::unordered_map<std::string, Object::WeakRef<T> >* list,
// strong-ref to it.
auto t(Object::New<T>(name, scene));
(*list)[name] = t;
return t;
return Object::Ref<T>(t);
}
}

View File

@ -50,7 +50,7 @@ class FlagNode : public Node {
base::AreaOfInterest* area_of_interest_ = nullptr;
Part part_;
std::vector<float> color_ = {1.0f, 1.0f, 1.0f};
Object::Ref<RigidBody> body_{nullptr};
Object::Ref<RigidBody> body_;
Object::Ref<SceneTexture> color_texture_;
base::MeshIndexedObjectSplit mesh_;
Object::Ref<FullShadowSet> full_shadow_set_;

View File

@ -12,7 +12,8 @@ namespace ballistica::scene_v1 {
auto PythonClassSceneCollisionMesh::tp_repr(PythonClassSceneCollisionMesh* self)
-> PyObject* {
BA_PYTHON_TRY;
Object::Ref<SceneCollisionMesh> m = *self->collision_mesh_;
assert(self->collision_mesh_);
auto&& m = *self->collision_mesh_;
return Py_BuildValue(
"s", (std::string("<bascenev1.CollisionMesh ")
+ (m.Exists() ? ("\"" + m->name() + "\"") : "(empty ref)") + ">")

View File

@ -12,7 +12,7 @@ namespace ballistica::scene_v1 {
auto PythonClassSceneDataAsset::tp_repr(PythonClassSceneDataAsset* self)
-> PyObject* {
BA_PYTHON_TRY;
Object::Ref<SceneDataAsset> m = *self->data_;
auto&& m = *self->data_;
return Py_BuildValue(
"s", (std::string("<ba.Data ")
+ (m.Exists() ? ("\"" + m->name() + "\"") : "(empty ref)") + ">")

View File

@ -11,7 +11,7 @@ namespace ballistica::scene_v1 {
auto PythonClassSceneMesh::tp_repr(PythonClassSceneMesh* self) -> PyObject* {
BA_PYTHON_TRY;
Object::Ref<SceneMesh> m = *(self->mesh_);
auto&& m = *(self->mesh_);
return Py_BuildValue(
"s", (std::string("<bascenev1.Mesh ")
+ (m.Exists() ? ("\"" + m->name() + "\"") : "(empty ref)") + ">")

View File

@ -30,7 +30,7 @@ void PythonClassSceneSound::SetupType(PyTypeObject* cls) {
auto PythonClassSceneSound::tp_repr(PythonClassSceneSound* self) -> PyObject* {
BA_PYTHON_TRY;
Object::Ref<SceneSound> m = *(self->sound_);
auto&& m = *(self->sound_);
return Py_BuildValue(
"s", (std::string("<bascenev1.Sound ")
+ (m.Exists() ? ("\"" + m->name() + "\"") : "(empty ref)") + ">")

View File

@ -12,7 +12,7 @@ namespace ballistica::scene_v1 {
auto PythonClassSceneTexture::tp_repr(PythonClassSceneTexture* self)
-> PyObject* {
BA_PYTHON_TRY;
Object::Ref<SceneTexture> t = *(self->texture_);
auto&& t = *(self->texture_);
return Py_BuildValue(
"s", (std::string("<bascenev1.Texture ")
+ (t.Exists() ? ("\"" + t->name() + "\"") : "(empty ref)") + ">")

View File

@ -193,7 +193,7 @@ auto HostActivity::NewMaterial(const std::string& name)
auto m(Object::New<Material>(name, scene()));
materials_.emplace_back(m);
return m;
return Object::Ref<Material>(m);
}
auto HostActivity::GetTexture(const std::string& name)

View File

@ -275,7 +275,7 @@ void HostSession::RemovePlayer(Player* player) {
if (i->Get() == player) {
// Grab a ref to keep the player alive, pull him off the list, then call
// his leaving callback.
Object::Ref<Player> player2 = *i;
auto player2 = Object::Ref<Player>(*i);
players_.erase(i);
// Clear the player's attachment to its host-session so it doesn't

View File

@ -39,7 +39,7 @@ auto main(int argc, char** argv) -> int {
namespace ballistica {
// These are set automatically via script; don't modify them here.
const int kEngineBuildNumber = 21418;
const int kEngineBuildNumber = 21421;
const char* kEngineVersion = "1.7.28";
const int kEngineApiVersion = 8;

View File

@ -151,7 +151,7 @@ class Object {
friend class Object;
}; // WeakRefBase
/// Weak-reference to an instance of a specific Object subclass.
/// A weak-reference to an instance of a specific Object subclass.
template <typename T>
class WeakRef : public WeakRefBase {
public:
@ -179,11 +179,14 @@ class Object {
return reinterpret_cast<T*>(obj_);
}
// These operators throw exceptions if the object is dead.
// ----------------------------- Operators ---------------------------------
/// Access the referenced object; throws an Exception if ref is invalid.
auto operator*() const -> T& {
if (!obj_) {
throw Exception("Dereferencing invalid " + static_type_name<T>()
+ " ref.");
throw Exception(
"Dereferencing invalid " + static_type_name<T>() + " ref.",
PyExcType::kReference);
}
// Yes, reinterpret_cast is evil, but we make sure
@ -191,10 +194,13 @@ class Object {
// (see Acquire()).
return *reinterpret_cast<T*>(obj_);
}
/// Access the referenced object; throws an Exception if ref is invalid.
auto operator->() const -> T* {
if (!obj_) {
throw Exception("Dereferencing invalid " + static_type_name<T>()
+ " ref.");
throw Exception(
"Dereferencing invalid " + static_type_name<T>() + " ref.",
PyExcType::kReference);
}
// Yes, reinterpret_cast is evil, but we make sure we only operate
@ -202,7 +208,53 @@ class Object {
return reinterpret_cast<T*>(obj_);
}
// Assign/compare with any compatible pointer.
/// Compare to a pointer of any compatible type.
template <typename U>
auto operator==(U* ptr) -> bool {
return (Get() == ptr);
}
/// Compare to a pointer of any compatible type.
template <typename U>
auto operator!=(U* ptr) -> bool {
return (Get() != ptr);
}
/// Compare to a strong ref of any compatible type.
template <typename U>
auto operator==(const Ref<U>& ref) -> bool {
return (Get() == ref.Get());
}
/// Compare to a strong ref to a compatible type.
template <typename U>
auto operator!=(const Ref<U>& ref) -> bool {
return (Get() != ref.Get());
}
/// Compare to a weak ref of any compatible type.
template <typename U>
auto operator==(const WeakRef<U>& ref) -> bool {
return (Get() == ref.Get());
}
/// Compare to a weak ref of any compatible type.
template <typename U>
auto operator!=(const WeakRef<U>& ref) -> bool {
return (Get() != ref.Get());
}
/// Assign from our exact type. Note: it might seem like our template
/// assigment operator (taking typename U) would cover this case, but
/// that's not how it works. If we remove this, the default generated
/// piecewise assignment operator gets selected as the best match for
/// our exact type and we crash horrifically.
auto operator=(const WeakRef<T>& ref) -> WeakRef<T>& {
*this = ref.Get();
return *this;
}
/// Assign from a pointer of any compatible type.
template <typename U>
auto operator=(U* ptr) -> WeakRef<T>& {
Release();
@ -219,104 +271,60 @@ class Object {
return *this;
}
template <typename U>
auto operator==(U* ptr) -> bool {
return (Get() == ptr);
}
template <typename U>
auto operator!=(U* ptr) -> bool {
return (Get() != ptr);
}
// Assign/compare with same type ref (apparently the template below
// doesn't cover this case?).
//
// Update: Actually now getting errors that
// having both is ambiguous, so maybe can kill these now?..
// Update 2: Oops; we (still?) crash without this.
// re-enabling for now. Need to get to the bottom of this.
auto operator=(const WeakRef<T>& ref) -> WeakRef<T>& {
*this = ref.Get();
return *this;
}
// auto operator==(const WeakRef<T>& ref) -> bool {
// return (Get() == ref.Get());
// }
// auto operator!=(const WeakRef<T>& ref) -> bool {
// return (Get() != ref.Get());
// }
// Assign/compare with a compatible weak-ref.
template <typename U>
auto operator=(const WeakRef<U>& ref) -> WeakRef<T>& {
*this = ref.Get();
return *this;
}
template <typename U>
auto operator==(const WeakRef<U>& ref) -> bool {
return (Get() == ref.Get());
}
template <typename U>
auto operator!=(const WeakRef<U>& ref) -> bool {
return (Get() != ref.Get());
}
// Assign/compare with a compatible strong-ref.
/// Assign from a strong ref of any compatible type.
template <typename U>
auto operator=(const Ref<U>& ref) -> WeakRef<T>& {
*this = ref.Get();
return *this;
}
/// Assign from a weak ref of any compatible type (except our exact
/// type which has its own overload).
template <typename U>
auto operator==(const Ref<U>& ref) -> bool {
return (Get() == ref.Get());
auto operator=(const WeakRef<U>& ref) -> WeakRef<T>& {
*this = ref.Get();
return *this;
}
template <typename U>
auto operator!=(const Ref<U>& ref) -> bool {
return (Get() != ref.Get());
}
// ---------------------------- Constructors -------------------------------
// Various constructors:
// Empty.
// Default constructor.
WeakRef() = default;
// From our type pointer.
explicit WeakRef(T* obj) { *this = obj; }
/// Copy constructor. Note that, by making this explicit, we require code
/// to be a bit more verbose. For example, we can't just do 'return
/// some_ref;' from a function and instead have to do 'return
/// Object::WeakRef<SomeType>(some_ref)'. However I feel this extra
/// verbosity is good; we're tossing around a mix of pointers and
/// strong-refs and weak-refs so it's good to be aware exactly where refs
/// are being added/etc.
explicit WeakRef(const WeakRef<T>& ref) { *this = ref.Get(); }
// Copy constructor (only non-explicit one).
WeakRef(const WeakRef<T>& ref) { *this = ref.Get(); }
// From a compatible pointer.
/// Create from a pointer of any compatible type.
template <typename U>
explicit WeakRef(U* ptr) {
*this = ptr;
}
// From a compatible strong ref.
/// Create from a strong ref of any compatible type.
template <typename U>
explicit WeakRef(const Ref<U>& ref) {
*this = ref;
}
// From a compatible weak ref.
/// Create from a weak ref of any compatible type.
template <typename U>
explicit WeakRef(const WeakRef<U>& ref) {
*this = ref;
}
// -------------------------------------------------------------------------
private:
void Acquire(T* obj) {
if (obj == nullptr) {
throw Exception("Acquiring invalid ptr of " + static_type_name<T>());
throw Exception("Acquiring invalid ptr of " + static_type_name<T>(),
PyExcType::kReference);
}
#if BA_DEBUG_BUILD
@ -355,22 +363,8 @@ class Object {
~Ref() { Release(); }
auto Get() const -> T* { return obj_; }
// These operators throw an Exception if the object is dead.
auto operator*() const -> T& {
if (!obj_) {
throw Exception("Dereferencing invalid " + static_type_name<T>()
+ " ref.");
}
return *obj_;
}
auto operator->() const -> T* {
if (!obj_) {
throw Exception("Dereferencing invalid " + static_type_name<T>()
+ " ref.");
}
return obj_;
}
auto Exists() const -> bool { return (obj_ != nullptr); }
void Clear() { Release(); }
/// Convenience wrapper for Object::IsValidManagedObject.
@ -381,7 +375,67 @@ class Object {
return false;
}
// Assign/compare with any compatible pointer.
// ----------------------------- Operators ---------------------------------
/// Access the referenced object; throws an Exception if ref is invalid.
auto operator*() const -> T& {
if (!obj_) {
throw Exception(
"Dereferencing invalid " + static_type_name<T>() + " ref.",
PyExcType::kReference);
}
return *obj_;
}
/// Access the referenced object; throws an Exception if ref is invalid.
auto operator->() const -> T* {
if (!obj_) {
throw Exception(
"Dereferencing invalid " + static_type_name<T>() + " ref.",
PyExcType::kReference);
}
return obj_;
}
/// Compare to a pointer of any compatible type.
template <typename U>
auto operator==(U* ptr) -> bool {
return (Get() == ptr);
}
/// Compare to a pointer of any compatible type.
template <typename U>
auto operator!=(U* ptr) -> bool {
return (Get() != ptr);
}
/// Compare to a strong ref of any compatible type.
template <typename U>
auto operator==(const Ref<U>& ref) -> bool {
return (Get() == ref.Get());
}
/// Compare to a strong ref of any compatible type.
template <typename U>
auto operator!=(const Ref<U>& ref) -> bool {
return (Get() != ref.Get());
}
// Note: we don't need to include comparisons to weak-refs because that
// is handled on the weak-ref side (and we can get ambiguity errors if
// we handle them here too).
/// Assign from our exact type. Note: it might seem like our template
/// assigment operator (taking typename U) would cover this case, but
/// that's not how it works. If we remove this, the default generated
/// piecewise assignment operator gets selected as the best match for
/// our exact type and we crash horrifically.
auto operator=(const Ref<T>& ref) -> Ref<T>& {
*this = ref.Get();
return *this;
}
/// Assign from a pointer of any compatible type.
template <typename U>
auto operator=(U* ptr) -> Ref<T>& {
Release();
@ -390,98 +444,61 @@ class Object {
}
return *this;
}
template <typename U>
auto operator==(U* ptr) -> bool {
return (Get() == ptr);
}
template <typename U>
auto operator!=(U* ptr) -> bool {
return (Get() != ptr);
}
auto operator==(const Ref<T>& ref) -> bool { return (Get() == ref.Get()); }
auto operator!=(const Ref<T>& ref) -> bool { return (Get() != ref.Get()); }
// Assign/compare with same type ref (apparently the generic template below
// doesn't cover that case?..)
// DANGER: Seems to still compile if we comment this out, but crashes.
// Should get to the bottom of that.
auto operator=(const Ref<T>& ref) -> Ref<T>& {
assert(this != &ref); // Shouldn't be self-assigning.
*this = ref.Get();
return *this;
}
// Assign/compare with a compatible strong-ref.
/// Assign from a strong ref of any compatible type (except our exact
/// type which has its own overload).
template <typename U>
auto operator=(const Ref<U>& ref) -> Ref<T>& {
*this = ref.Get();
return *this;
}
template <typename U>
auto operator==(const Ref<U>& ref) -> bool {
return (Get() == ref.Get());
}
template <typename U>
auto operator!=(const Ref<U>& ref) -> bool {
return (Get() != ref.Get());
}
// Assign from a compatible weak-ref. Comparing to compatible weak-refs
// is covered by the operators on the weak-ref side.
/// Assign from a weak ref to any compatible type.
template <typename U>
auto operator=(const WeakRef<U>& ref) -> Ref<T>& {
*this = ref.Get();
return *this;
}
// These are already covered by the equivalent operators
// on the WeakRef side.
// template <typename U>
// auto operator==(const WeakRef<U>& ref) -> bool {
// return (Get() == ref.Get());
// }
// ---------------------------- Constructors -------------------------------
// template <typename U>
// auto operator!=(const WeakRef<U>& ref) -> bool {
// return (Get() != ref.Get());
// }
// Various constructors:
// Empty.
/// Default constructor.
Ref() = default;
// From our type pointer.
explicit Ref(T* obj) { *this = obj; }
/// Copy constructor. Note that, by making this explicit, we require code
/// to be a bit more verbose. For example, we can't just do 'return
/// some_ref;' from a function and instead have to do 'return
/// Object::Ref<SomeType>(some_ref)'. However I feel this extra verbosity
/// is good; we're tossing around a mix of pointers and strong-refs and
/// weak-refs so it's good to be aware exactly where refs are being
/// added/etc.
explicit Ref(const Ref<T>& ref) { *this = ref.Get(); }
// Copy constructor (only non-explicit one).
Ref(const Ref<T>& ref) { *this = ref.Get(); }
// From a compatible pointer.
/// Create from a compatible pointer.
template <typename U>
explicit Ref(U* ptr) {
*this = ptr;
}
// From a compatible strong ref.
/// Create from a compatible strong ref.
template <typename U>
explicit Ref(const Ref<U>& ref) {
*this = ref;
}
// From a compatible weak ref.
/// Create from a compatible weak ref.
template <typename U>
explicit Ref(const WeakRef<U>& ref) {
*this = ref;
}
// -------------------------------------------------------------------------
private:
void Acquire(T* obj) {
if (obj == nullptr) {
throw Exception("Acquiring invalid ptr of " + static_type_name<T>());
throw Exception("Acquiring invalid ptr of " + static_type_name<T>(),
PyExcType::kReference);
}
#if BA_DEBUG_BUILD
@ -549,13 +566,13 @@ class Object {
/// In some cases it may be handy to allocate an object for ref-counting
/// but not actually create references yet. An example is when creating an
/// object in one thread to be passed to another which will own said object.
/// For such cases, allocate using NewDeferred() and then create the initial
/// strong ref in the desired thread using CompleteDeferred().
/// Note that in debug builds, checks may be run to make sure deferred
/// objects wind up with references added to them at some point. If you
/// want to allocate an object for manual deallocation or permanent
/// existence, use NewUnmanaged() instead.
/// object in one thread to be passed to another which will own said
/// object. For such cases, allocate using NewDeferred() and then create
/// the initial strong ref in the desired thread using CompleteDeferred().
/// Note that, in debug builds, checks may be run to make sure deferred
/// objects wind up with references added to them at some point. For this
/// reason, if you want to allocate an object for manual deallocation or
/// permanent existence, use NewUnmanaged() instead.
template <typename T, typename... ARGS>
[[nodiscard]] static auto NewDeferred(ARGS&&... args) -> T* {
T* ptr = new T(std::forward<ARGS>(args)...);

View File

@ -273,6 +273,7 @@ enum class PyExcType {
kIndex,
kType,
kValue,
kReference,
kContext,
kNotFound,
kNodeNotFound,

View File

@ -49,6 +49,9 @@ void Python::SetPythonException(const Exception& exc) {
case PyExcType::kValue:
pytype = PyExc_ValueError;
break;
case PyExcType::kReference:
pytype = PyExc_ReferenceError;
break;
case PyExcType::kType:
pytype = PyExc_TypeError;
break;

View File

@ -1268,7 +1268,7 @@ void ContainerWidget::DeleteWidget(Widget* w) {
}
// Grab a ref until we clear it off the list to avoid funky recursion
// issues.
Object::Ref<Widget> w2 = *i;
auto w2 = Object::Ref<Widget>(*i);
widgets_.erase(i);
found = true;
break;