Added a godot's Reference class and a few smaller headers.

This commit is contained in:
Relintai 2021-08-21 13:47:58 +02:00
parent d75ecf0f23
commit f897b42b37
9 changed files with 1113 additions and 0 deletions

57
core/int_types.h Normal file
View File

@ -0,0 +1,57 @@
/*************************************************************************/
/* int_types.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifdef _MSC_VER
typedef signed __int8 int8_t;
typedef unsigned __int8 uint8_t;
typedef signed __int16 int16_t;
typedef unsigned __int16 uint16_t;
typedef signed __int32 int32_t;
typedef unsigned __int32 uint32_t;
typedef signed __int64 int64_t;
typedef unsigned __int64 uint64_t;
#else
#ifdef NO_STDINT_H
typedef unsigned char uint8_t;
typedef signed char int8_t;
typedef unsigned short uint16_t;
typedef signed short int16_t;
typedef unsigned int uint32_t;
typedef signed int int32_t;
typedef long long int64_t;
typedef unsigned long long uint64_t;
#else
#include <stdint.h>
#endif
#endif

12
core/memory.h Normal file
View File

@ -0,0 +1,12 @@
#ifndef MEMORY_H
#define MEMORY_H
//Simple memnew and memdelete macros so stuff that I took from the godotengine can use it.
//Not yet sure whether to use their allocator or not.
//This will be here until I decide.
#define memnew(m_class) new m_class
#define memdelete(instance) delete instance
#endif

View File

@ -75,6 +75,26 @@ public:
Object();
virtual ~Object();
template <class T>
static T *cast_to(Object *p_object) {
if (!p_object)
return NULL;
if (p_object->is_class_ptr(T::get_class_ptr_static()))
return static_cast<T *>(p_object);
else
return NULL;
}
template <class T>
static const T *cast_to(const Object *p_object) {
if (!p_object)
return NULL;
if (p_object->is_class_ptr(T::get_class_ptr_static()))
return static_cast<const T *>(p_object);
else
return NULL;
}
};
#endif

38
core/object_id.h Normal file
View File

@ -0,0 +1,38 @@
/*************************************************************************/
/* object_id.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef OBJECTID_H
#define OBJECTID_H
#include "core/int_types.h"
typedef uint64_t ObjectID;
#endif

53
core/reference.cpp Normal file
View File

@ -0,0 +1,53 @@
#include "reference.h"
bool Reference::init_ref() {
if (reference()) {
if (!is_referenced() && refcount_init.unref()) {
unreference(); // first referencing is already 1, so compensate for the ref above
}
return true;
} else {
return false;
}
}
int Reference::reference_get_count() const {
return refcount.get();
}
bool Reference::reference() {
uint32_t rc_val = refcount.refval();
bool success = rc_val != 0;
return success;
}
bool Reference::unreference() {
uint32_t rc_val = refcount.unrefval();
bool die = rc_val == 0;
return die;
}
Reference::Reference() {
refcount.init();
refcount_init.init();
}
Reference::~Reference() {
}
/*
void WeakRef::set_obj(Object *p_object) {
//ref = p_object ? p_object->get_instance_id() : 0;
}
void WeakRef::set_ref(const REF &p_ref) {
//ref = p_ref.is_valid() ? p_ref->get_instance_id() : 0;
}
WeakRef::WeakRef() :
ref(0) {
}
*/

201
core/reference.h Normal file
View File

@ -0,0 +1,201 @@
#ifndef REFERENCE_H
#define REFERENCE_H
// Most of the code is from the godot engine's reference.h
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
#include "safe_refcount.h"
#include "object.h"
#include "object_id.h"
#include "memory.h"
class Reference : public Object {
RCPP_OBJECT(Reference, Object);
public:
/*_FORCE_INLINE_*/ bool is_referenced() const { return refcount_init.get() != 1; }
bool init_ref();
bool reference(); // returns false if refcount is at zero and didn't get increased
bool unreference();
int reference_get_count() const;
Reference();
virtual ~Reference();
private:
SafeRefCount refcount;
SafeRefCount refcount_init;
};
template <class T>
class Ref {
T *reference;
void ref(const Ref &p_from) {
if (p_from.reference == reference) {
return;
}
unref();
reference = p_from.reference;
if (reference) {
reference->reference();
}
}
void ref_pointer(T *p_ref) {
ERR_FAIL_COND(!p_ref);
if (p_ref->init_ref()) {
reference = p_ref;
}
}
//virtual Reference * get_reference() const { return reference; }
public:
_FORCE_INLINE_ bool operator==(const T *p_ptr) const {
return reference == p_ptr;
}
_FORCE_INLINE_ bool operator!=(const T *p_ptr) const {
return reference != p_ptr;
}
_FORCE_INLINE_ bool operator<(const Ref<T> &p_r) const {
return reference < p_r.reference;
}
_FORCE_INLINE_ bool operator==(const Ref<T> &p_r) const {
return reference == p_r.reference;
}
_FORCE_INLINE_ bool operator!=(const Ref<T> &p_r) const {
return reference != p_r.reference;
}
_FORCE_INLINE_ T *operator->() {
return reference;
}
_FORCE_INLINE_ T *operator*() {
return reference;
}
_FORCE_INLINE_ const T *operator->() const {
return reference;
}
_FORCE_INLINE_ const T *ptr() const {
return reference;
}
_FORCE_INLINE_ T *ptr() {
return reference;
}
_FORCE_INLINE_ const T *operator*() const {
return reference;
}
void operator=(const Ref &p_from) {
ref(p_from);
}
template <class T_Other>
void operator=(const Ref<T_Other> &p_from) {
Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr()));
if (!refb) {
unref();
return;
}
Ref r;
r.reference = Object::cast_to<T>(refb);
ref(r);
r.reference = nullptr;
}
template <class T_Other>
void reference_ptr(T_Other *p_ptr) {
if (reference == p_ptr) {
return;
}
unref();
T *r = Object::cast_to<T>(p_ptr);
if (r) {
ref_pointer(r);
}
}
Ref(const Ref &p_from) {
reference = nullptr;
ref(p_from);
}
template <class T_Other>
Ref(const Ref<T_Other> &p_from) {
reference = nullptr;
Reference *refb = const_cast<Reference *>(static_cast<const Reference *>(p_from.ptr()));
if (!refb) {
unref();
return;
}
Ref r;
r.reference = Object::cast_to<T>(refb);
ref(r);
r.reference = nullptr;
}
Ref(T *p_reference) {
reference = nullptr;
if (p_reference) {
ref_pointer(p_reference);
}
}
inline bool is_valid() const { return reference != nullptr; }
inline bool is_null() const { return reference == nullptr; }
void unref() {
//TODO this should be moved to mutexes, since this engine does not really
// do a lot of referencing on references and stuff
// mutexes will avoid more crashes?
if (reference && reference->unreference()) {
memdelete(reference);
}
reference = nullptr;
}
void instance() {
ref(memnew(T));
}
Ref() {
reference = nullptr;
}
~Ref() {
unref();
}
};
typedef Ref<Reference> REF;
/*
class WeakRef : public Reference {
RCPP_OBJECT(WeakRef, Reference);
ObjectID ref;
protected:
static void _bind_methods();
public:
void set_obj(Object *p_object);
void set_ref(const REF &p_ref);
WeakRef();
};
*/
#endif

45
core/safe_refcount.cpp Normal file
View File

@ -0,0 +1,45 @@
/*************************************************************************/
/* safe_refcount.cpp */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#if defined(DEBUG_ENABLED) && !defined(NO_THREADS)
#include "safe_refcount.h"
#include "core/error_macros.h"
// On C++14 we don't have std::atomic::is_always_lockfree, so this is the best we can do
void check_lockless_atomics() {
// Doing the check for the types we actually care about
if (!std::atomic<uint32_t>{}.is_lock_free() || !std::atomic<uint64_t>{}.is_lock_free() || !std::atomic_bool{}.is_lock_free()) {
WARN_PRINT("Your compiler doesn't seem to support lockless atomics. Performance will be degraded. Please consider upgrading to a different or newer compiler.");
}
}
#endif

333
core/safe_refcount.h Normal file
View File

@ -0,0 +1,333 @@
/*************************************************************************/
/* safe_refcount.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef SAFE_REFCOUNT_H
#define SAFE_REFCOUNT_H
#include "core/typedefs.h"
#if !defined(NO_THREADS)
#include <atomic>
#include <type_traits>
// Design goals for these classes:
// - No automatic conversions or arithmetic operators,
// to keep explicit the use of atomics everywhere.
// - Using acquire-release semantics, even to set the first value.
// The first value may be set relaxedly in many cases, but adding the distinction
// between relaxed and unrelaxed operation to the interface would make it needlessly
// flexible. There's negligible waste in having release semantics for the initial
// value and, as an important benefit, you can be sure the value is properly synchronized
// even with threads that are already running.
// This is used in very specific areas of the engine where it's critical that these guarantees are held
#define SAFE_NUMERIC_TYPE_PUN_GUARANTEES(m_type) \
static_assert(sizeof(SafeNumeric<m_type>) == sizeof(m_type), ""); \
static_assert(alignof(SafeNumeric<m_type>) == alignof(m_type), ""); \
static_assert(std::is_trivially_destructible<std::atomic<m_type>>::value, "");
#if defined(DEBUG_ENABLED)
void check_lockless_atomics();
#endif
template <class T>
class SafeNumeric {
std::atomic<T> value;
public:
_ALWAYS_INLINE_ void set(T p_value) {
value.store(p_value, std::memory_order_release);
}
_ALWAYS_INLINE_ T get() const {
return value.load(std::memory_order_acquire);
}
_ALWAYS_INLINE_ T increment() {
return value.fetch_add(1, std::memory_order_acq_rel) + 1;
}
// Returns the original value instead of the new one
_ALWAYS_INLINE_ T postincrement() {
return value.fetch_add(1, std::memory_order_acq_rel);
}
_ALWAYS_INLINE_ T decrement() {
return value.fetch_sub(1, std::memory_order_acq_rel) - 1;
}
// Returns the original value instead of the new one
_ALWAYS_INLINE_ T postdecrement() {
return value.fetch_sub(1, std::memory_order_acq_rel);
}
_ALWAYS_INLINE_ T add(T p_value) {
return value.fetch_add(p_value, std::memory_order_acq_rel) + p_value;
}
// Returns the original value instead of the new one
_ALWAYS_INLINE_ T postadd(T p_value) {
return value.fetch_add(p_value, std::memory_order_acq_rel);
}
_ALWAYS_INLINE_ T sub(T p_value) {
return value.fetch_sub(p_value, std::memory_order_acq_rel) - p_value;
}
// Returns the original value instead of the new one
_ALWAYS_INLINE_ T postsub(T p_value) {
return value.fetch_sub(p_value, std::memory_order_acq_rel);
}
_ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
while (true) {
T tmp = value.load(std::memory_order_acquire);
if (tmp >= p_value) {
return tmp; // already greater, or equal
}
if (value.compare_exchange_weak(tmp, p_value, std::memory_order_release)) {
return p_value;
}
}
}
_ALWAYS_INLINE_ T conditional_increment() {
while (true) {
T c = value.load(std::memory_order_acquire);
if (c == 0) {
return 0;
}
if (value.compare_exchange_weak(c, c + 1, std::memory_order_release)) {
return c + 1;
}
}
}
_ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) {
set(p_value);
}
};
class SafeFlag {
std::atomic_bool flag;
public:
_ALWAYS_INLINE_ bool is_set() const {
return flag.load(std::memory_order_acquire);
}
_ALWAYS_INLINE_ void set() {
flag.store(true, std::memory_order_release);
}
_ALWAYS_INLINE_ void clear() {
flag.store(false, std::memory_order_release);
}
_ALWAYS_INLINE_ void set_to(bool p_value) {
flag.store(p_value, std::memory_order_release);
}
_ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) {
set_to(p_value);
}
};
class SafeRefCount {
SafeNumeric<uint32_t> count;
public:
_ALWAYS_INLINE_ bool ref() { // true on success
return count.conditional_increment() != 0;
}
_ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
return count.conditional_increment();
}
_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
return count.decrement() == 0;
}
_ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
return count.decrement();
}
_ALWAYS_INLINE_ uint32_t get() const {
return count.get();
}
_ALWAYS_INLINE_ void init(uint32_t p_value = 1) {
count.set(p_value);
}
};
#else
template <class T>
class SafeNumeric {
protected:
T value;
public:
_ALWAYS_INLINE_ void set(T p_value) {
value = p_value;
}
_ALWAYS_INLINE_ T get() const {
return value;
}
_ALWAYS_INLINE_ T increment() {
return ++value;
}
_ALWAYS_INLINE_ T postincrement() {
return value++;
}
_ALWAYS_INLINE_ T decrement() {
return --value;
}
_ALWAYS_INLINE_ T postdecrement() {
return value--;
}
_ALWAYS_INLINE_ T add(T p_value) {
return value += p_value;
}
_ALWAYS_INLINE_ T postadd(T p_value) {
T old = value;
value += p_value;
return old;
}
_ALWAYS_INLINE_ T sub(T p_value) {
return value -= p_value;
}
_ALWAYS_INLINE_ T postsub(T p_value) {
T old = value;
value -= p_value;
return old;
}
_ALWAYS_INLINE_ T exchange_if_greater(T p_value) {
if (value < p_value) {
value = p_value;
}
return value;
}
_ALWAYS_INLINE_ T conditional_increment() {
if (value == 0) {
return 0;
} else {
return ++value;
}
}
_ALWAYS_INLINE_ explicit SafeNumeric<T>(T p_value = static_cast<T>(0)) :
value(p_value) {
}
};
class SafeFlag {
protected:
bool flag;
public:
_ALWAYS_INLINE_ bool is_set() const {
return flag;
}
_ALWAYS_INLINE_ void set() {
flag = true;
}
_ALWAYS_INLINE_ void clear() {
flag = false;
}
_ALWAYS_INLINE_ void set_to(bool p_value) {
flag = p_value;
}
_ALWAYS_INLINE_ explicit SafeFlag(bool p_value = false) :
flag(p_value) {}
};
class SafeRefCount {
uint32_t count;
public:
_ALWAYS_INLINE_ bool ref() { // true on success
if (count != 0) {
++count;
return true;
} else {
return false;
}
}
_ALWAYS_INLINE_ uint32_t refval() { // none-zero on success
if (count != 0) {
return ++count;
} else {
return 0;
}
}
_ALWAYS_INLINE_ bool unref() { // true if must be disposed of
return --count == 0;
}
_ALWAYS_INLINE_ uint32_t unrefval() { // 0 if must be disposed of
return --count;
}
_ALWAYS_INLINE_ uint32_t get() const {
return count;
}
_ALWAYS_INLINE_ void init(uint32_t p_value = 1) {
count = p_value;
}
SafeRefCount() :
count(0) {}
};
#endif
#endif // SAFE_REFCOUNT_H

354
core/typedefs.h Normal file
View File

@ -0,0 +1,354 @@
/*************************************************************************/
/* typedefs.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
/* "Software"), to deal in the Software without restriction, including */
/* without limitation the rights to use, copy, modify, merge, publish, */
/* distribute, sublicense, and/or sell copies of the Software, and to */
/* permit persons to whom the Software is furnished to do so, subject to */
/* the following conditions: */
/* */
/* The above copyright notice and this permission notice shall be */
/* included in all copies or substantial portions of the Software. */
/* */
/* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, */
/* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF */
/* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.*/
/* IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY */
/* CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, */
/* TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE */
/* SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. */
/*************************************************************************/
#ifndef TYPEDEFS_H
#define TYPEDEFS_H
#include <stddef.h>
/**
* Basic definitions and simple functions to be used everywhere.
*/
//#include "platform_config.h"
#ifndef _STR
#define _STR(m_x) #m_x
#define _MKSTR(m_x) _STR(m_x)
#endif
//should always inline no matter what
#ifndef _ALWAYS_INLINE_
#if defined(__GNUC__) && (__GNUC__ >= 4)
#define _ALWAYS_INLINE_ __attribute__((always_inline)) inline
#elif defined(__llvm__)
#define _ALWAYS_INLINE_ __attribute__((always_inline)) inline
#elif defined(_MSC_VER)
#define _ALWAYS_INLINE_ __forceinline
#else
#define _ALWAYS_INLINE_ inline
#endif
#endif
//should always inline, except in some cases because it makes debugging harder
#ifndef _FORCE_INLINE_
#ifdef DISABLE_FORCED_INLINE
#define _FORCE_INLINE_ inline
#else
#define _FORCE_INLINE_ _ALWAYS_INLINE_
#endif
#endif
//custom, gcc-safe offsetof, because gcc complains a lot.
template <class T>
T *_nullptr() {
T *t = NULL;
return t;
}
#define OFFSET_OF(st, m) \
((size_t)((char *)&(_nullptr<st>()->m) - (char *)0))
/**
* Some platforms (devices) don't define NULL
*/
#ifndef NULL
#define NULL 0
#endif
/**
* Windows badly defines a lot of stuff we'll never use. Undefine it.
*/
#ifdef _WIN32
#undef min // override standard definition
#undef max // override standard definition
#undef ERROR // override (really stupid) wingdi.h standard definition
#undef DELETE // override (another really stupid) winnt.h standard definition
#undef MessageBox // override winuser.h standard definition
#undef MIN // override standard definition
#undef MAX // override standard definition
#undef CLAMP // override standard definition
#undef Error
#undef OK
#undef CONNECT_DEFERRED // override from Windows SDK, clashes with Object enum
#endif
#include "int_types.h"
//#include "core/error_list.h"
/** Generic ABS function, for math uses please use Math::abs */
#ifndef ABS
#define ABS(m_v) (((m_v) < 0) ? (-(m_v)) : (m_v))
#endif
#define ABSDIFF(x, y) (((x) < (y)) ? ((y) - (x)) : ((x) - (y)))
#ifndef SGN
#define SGN(m_v) (((m_v) < 0) ? (-1.0) : (+1.0))
#endif
#ifndef MIN
#define MIN(m_a, m_b) (((m_a) < (m_b)) ? (m_a) : (m_b))
#endif
#ifndef MAX
#define MAX(m_a, m_b) (((m_a) > (m_b)) ? (m_a) : (m_b))
#endif
#ifndef CLAMP
#define CLAMP(m_a, m_min, m_max) (((m_a) < (m_min)) ? (m_min) : (((m_a) > (m_max)) ? m_max : m_a))
#endif
/** Generic swap template */
#ifndef SWAP
#define SWAP(m_x, m_y) __swap_tmpl((m_x), (m_y))
template <class T>
inline void __swap_tmpl(T &x, T &y) {
T aux = x;
x = y;
y = aux;
}
#endif //swap
/* clang-format off */
#define HEX2CHR(m_hex) \
((m_hex >= '0' && m_hex <= '9') ? (m_hex - '0') : \
((m_hex >= 'A' && m_hex <= 'F') ? (10 + m_hex - 'A') : \
((m_hex >= 'a' && m_hex <= 'f') ? (10 + m_hex - 'a') : 0)))
/* clang-format on */
// Macro to check whether we are compiled by clang
// and we have a specific builtin
#if defined(__llvm__) && defined(__has_builtin)
#define _llvm_has_builtin(x) __has_builtin(x)
#else
#define _llvm_has_builtin(x) 0
#endif
#if (defined(__GNUC__) && (__GNUC__ >= 5)) || _llvm_has_builtin(__builtin_mul_overflow)
#define _mul_overflow __builtin_mul_overflow
#endif
#if (defined(__GNUC__) && (__GNUC__ >= 5)) || _llvm_has_builtin(__builtin_add_overflow)
#define _add_overflow __builtin_add_overflow
#endif
/** Function to find the next power of 2 to an integer */
static _FORCE_INLINE_ unsigned int next_power_of_2(unsigned int x) {
if (x == 0) {
return 0;
}
--x;
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return ++x;
}
static _FORCE_INLINE_ unsigned int previous_power_of_2(unsigned int x) {
x |= x >> 1;
x |= x >> 2;
x |= x >> 4;
x |= x >> 8;
x |= x >> 16;
return x - (x >> 1);
}
static _FORCE_INLINE_ unsigned int closest_power_of_2(unsigned int x) {
unsigned int nx = next_power_of_2(x);
unsigned int px = previous_power_of_2(x);
return (nx - x) > (x - px) ? px : nx;
}
// We need this definition inside the function below.
static inline int get_shift_from_power_of_2(unsigned int p_pixel);
template <class T>
static _FORCE_INLINE_ T nearest_power_of_2_templated(T x) {
--x;
// The number of operations on x is the base two logarithm
// of the p_number of bits in the type. Add three to account
// for sizeof(T) being in bytes.
size_t num = get_shift_from_power_of_2(sizeof(T)) + 3;
// If the compiler is smart, it unrolls this loop
// If its dumb, this is a bit slow.
for (size_t i = 0; i < num; i++) {
x |= x >> (1 << i);
}
return ++x;
}
/** Function to find the nearest (bigger) power of 2 to an integer */
static inline unsigned int nearest_shift(unsigned int p_number) {
for (int i = 30; i >= 0; i--) {
if (p_number & (1 << i)) {
return i + 1;
}
}
return 0;
}
/** get a shift value from a power of 2 */
static inline int get_shift_from_power_of_2(unsigned int p_pixel) {
// return a GL_TEXTURE_SIZE_ENUM
for (unsigned int i = 0; i < 32; i++) {
if (p_pixel == (unsigned int)(1 << i)) {
return i;
}
}
return -1;
}
/** Swap 16 bits value for endianness */
#if defined(__GNUC__) || _llvm_has_builtin(__builtin_bswap16)
#define BSWAP16(x) __builtin_bswap16(x)
#else
static inline uint16_t BSWAP16(uint16_t x) {
return (x >> 8) | (x << 8);
}
#endif
/** Swap 32 bits value for endianness */
#if defined(__GNUC__) || _llvm_has_builtin(__builtin_bswap32)
#define BSWAP32(x) __builtin_bswap32(x)
#else
static inline uint32_t BSWAP32(uint32_t x) {
return ((x << 24) | ((x << 8) & 0x00FF0000) | ((x >> 8) & 0x0000FF00) | (x >> 24));
}
#endif
/** Swap 64 bits value for endianness */
#if defined(__GNUC__) || _llvm_has_builtin(__builtin_bswap64)
#define BSWAP64(x) __builtin_bswap64(x)
#else
static inline uint64_t BSWAP64(uint64_t x) {
x = (x & 0x00000000FFFFFFFF) << 32 | (x & 0xFFFFFFFF00000000) >> 32;
x = (x & 0x0000FFFF0000FFFF) << 16 | (x & 0xFFFF0000FFFF0000) >> 16;
x = (x & 0x00FF00FF00FF00FF) << 8 | (x & 0xFF00FF00FF00FF00) >> 8;
return x;
}
#endif
/** When compiling with RTTI, we can add an "extra"
* layer of safeness in many operations, so dynamic_cast
* is used besides casting by enum.
*/
template <class T>
struct Comparator {
_ALWAYS_INLINE_ bool operator()(const T &p_a, const T &p_b) const { return (p_a < p_b); }
};
void _global_lock();
void _global_unlock();
struct _GlobalLock {
_GlobalLock() { _global_lock(); }
~_GlobalLock() { _global_unlock(); }
};
#define GLOBAL_LOCK_FUNCTION _GlobalLock _global_lock_;
#ifdef NO_SAFE_CAST
#define SAFE_CAST static_cast
#else
#define SAFE_CAST dynamic_cast
#endif
#define MT_SAFE
#define __STRX(m_index) #m_index
#define __STR(m_index) __STRX(m_index)
#ifdef __GNUC__
#define likely(x) __builtin_expect(!!(x), 1)
#define unlikely(x) __builtin_expect(!!(x), 0)
#else
#define likely(x) x
#define unlikely(x) x
#endif
#if defined(__GNUC__)
#define _PRINTF_FORMAT_ATTRIBUTE_2_0 __attribute__((format(printf, 2, 0)))
#define _PRINTF_FORMAT_ATTRIBUTE_2_3 __attribute__((format(printf, 2, 3)))
#else
#define _PRINTF_FORMAT_ATTRIBUTE_2_0
#define _PRINTF_FORMAT_ATTRIBUTE_2_3
#endif
/** This is needed due to a strange OpenGL API that expects a pointer
* type for an argument that is actually an offset.
*/
#define CAST_INT_TO_UCHAR_PTR(ptr) ((uint8_t *)(uintptr_t)(ptr))
/** Hint for compilers that this fallthrough in a switch is intentional.
* Can be replaced by [[fallthrough]] annotation if we move to C++17.
* Including conditional support for it for people who set -std=c++17
* themselves.
* Requires a trailing semicolon when used.
*/
#if __cplusplus >= 201703L
#define FALLTHROUGH [[fallthrough]]
#elif defined(__GNUC__) && __GNUC__ >= 7
#define FALLTHROUGH __attribute__((fallthrough))
#elif defined(__llvm__) && __cplusplus >= 201103L && defined(__has_feature)
#if __has_feature(cxx_attributes) && defined(__has_warning)
#if __has_warning("-Wimplicit-fallthrough")
#define FALLTHROUGH [[clang::fallthrough]]
#endif
#endif
#endif
#ifndef FALLTHROUGH
#define FALLTHROUGH
#endif
#endif // TYPEDEFS_H