Added some of the utils from rcpp_fw.

This commit is contained in:
Relintai 2023-12-18 17:36:43 +01:00
parent b22a755150
commit eeb4e7dba0
32 changed files with 10584 additions and 0 deletions

19
core/SCsub Normal file
View File

@ -0,0 +1,19 @@
#!/usr/bin/env python
Import("env")
env.core_sources = []
env.add_source_files(env.core_sources, "*.cpp")
env.add_source_files(env.core_sources, "./math/*.cpp")
env.add_source_files(env.core_sources, "./containers/*.cpp")
env.add_source_files(env.core_sources, "./log/*.cpp")
env.add_source_files(env.core_sources, "./os/*.cpp")
env.add_source_files(env.core_sources, "./image/*.cpp")
env.add_source_files(env.core_sources, "./threading/*.cpp")
env.add_source_files(env.core_sources, "./settings/*.cpp")
env.add_source_files(env.core_sources, "./nodes/*.cpp")
# Build it all as a library
lib = env.add_library("core", env.core_sources)
env.Prepend(LIBS=[lib])

229
core/containers/queue.h Normal file
View File

@ -0,0 +1,229 @@
#ifndef QUEUE_H
#define QUEUE_H
#include "core/error_macros.h"
#include "vector.h"
template<class T>
class Queue
{
public:
void enqueue(const T &job);
T dequeue();
const T &peek() const;
bool is_empty() const;
bool is_full() const;
int size() const;
int capacity() const;
void ensure_capacity(const int capacity);
void resize(const int s);
void pack();
Queue();
Queue(int prealloc);
Queue(int prealloc, int grow_by);
~Queue();
private:
T* _data;
int _head;
int _tail;
int _capacity;
int _grow_size;
};
template <class T>
void Queue<T>::pack()
{
if (_head == _tail)
{
_head = 0;
_tail = 0;
return;
}
if (_head == 0 && _tail == _capacity)
{
resize(_capacity + _grow_size);
return;
}
int j = 0;
for (int i = _head; i < _tail; ++i)
{
_data[j++] = _data[i];
}
_head = 0;
_tail = j;
}
template <class T>
void Queue<T>::enqueue(const T &job)
{
if (_tail == _capacity)
{
pack();
}
_data[_tail++] = job;
}
template <class T>
T Queue<T>::dequeue()
{
CRASH_COND(is_empty());
return _data[_head++];
}
template <class T>
const T &Queue<T>::peek() const
{
CRASH_COND(is_empty());
return _data[_head];
}
template <class T>
bool Queue<T>::is_empty() const
{
return _head == _tail;
}
template <class T>
bool Queue<T>::is_full() const
{
return (_head == 0) && (_tail == _capacity);
}
template <class T>
int Queue<T>::size() const
{
return _tail - _head;
}
template <class T>
int Queue<T>::capacity() const
{
return _capacity;
}
template <class T>
void Queue<T>::ensure_capacity(const int capacity)
{
if (_capacity < capacity)
{
resize(capacity);
}
}
template <class T>
void Queue<T>::resize(const int s)
{
if (s == 0 && _data)
{
delete[] _data;
_data = nullptr;
_capacity = s;
return;
}
if (!_data)
{
_data = new T[s];
_capacity = s;
return;
}
if (is_empty())
{
delete[] _data;
_data = new T[s];
_capacity = s;
return;
}
if (!is_full())
{
pack();
}
T* nd = new T[s];
int to = s > _tail ? _tail : s;
for (int i = 0; i < to; ++i)
{
nd[i] = _data[i];
}
delete[] _data;
_data = nd;
_capacity = s;
}
template <class T>
Queue<T>::Queue()
{
_data = nullptr;
_head = 0;
_tail = 0;
_capacity = 20;
_grow_size = 10;
resize(_capacity);
}
template <class T>
Queue<T>::Queue(int prealloc)
{
_data = nullptr;
_head = 0;
_tail = 0;
_capacity = prealloc;
_grow_size = 10;
resize(_capacity);
}
template <class T>
Queue<T>::Queue(int prealloc, int grow_by)
{
_data = nullptr;
_head = 0;
_tail = 0;
_capacity = prealloc;
_grow_size = grow_by;
resize(_capacity);
}
template <class T>
Queue<T>::~Queue()
{
if (_data)
{
delete[] _data;
_data = nullptr;
}
}
#endif

287
core/containers/vector.h Normal file
View File

@ -0,0 +1,287 @@
#ifndef VECTOR_H
#define VECTOR_H
#include "core/error_macros.h"
template <class T>
class Vector {
public:
void push_back(const T &element);
void pop_back();
void remove(const int index);
void remove_keep_order(const int index);
void erase(const T &element);
void clear();
bool empty() const;
T get(const int index);
const T &get(const int index) const;
void set(const int index, const T &value);
void swap(const int index1, const int index2);
void sort_inc();
void sort_dec();
int size() const;
int capacity() const;
void ensure_capacity(const int capacity);
void resize(const int s);
void append_array(const Vector<T> &other);
int find(const T &val) const;
T *dataw();
const T *data() const;
const T &operator[](const int index) const;
T &operator[](const int index);
Vector &operator=(const Vector &other);
Vector();
Vector(int prealloc);
Vector(int prealloc, int grow_by);
Vector(const Vector &other);
~Vector();
private:
T *_data;
int _actual_size;
int _size;
int _grow_by;
};
template <class T>
void Vector<T>::push_back(const T &element) {
ensure_capacity(_size + 1);
_data[_size++] = element;
}
template <class T>
void Vector<T>::pop_back() {
if (_size == 0) {
return;
}
--_size;
}
template <class T>
void Vector<T>::remove(const int index) {
_data[index] = _data[_size - 1];
--_size;
}
template <class T>
void Vector<T>::remove_keep_order(const int index) {
--_size;
for (int i = index; i < _size; ++i) {
_data[i] = _data[i + 1];
}
}
template <class T>
void Vector<T>::erase(const T &element) {
int index = find(element);
if (index != -1) {
remove(index);
}
}
template <class T>
void Vector<T>::clear() {
_size = 0;
}
template <class T>
bool Vector<T>::empty() const {
return _size == 0;
}
template <class T>
T Vector<T>::get(const int index) {
return _data[index];
}
template <class T>
const T &Vector<T>::get(const int index) const {
return _data[index];
}
template <class T>
void Vector<T>::set(const int index, const T &value) {
_data[index] = value;
}
template <class T>
void Vector<T>::swap(const int index1, const int index2) {
T e = _data[index1];
_data[index1] = _data[index2];
_data[index2] = e;
}
template <class T>
void Vector<T>::sort_inc() {
for (int i = 0; i < _size; ++i) {
for (int j = i + 1; j < _size; ++j) {
if (_data[j] < _data[i]) {
swap(i, j);
}
}
}
}
template <class T>
void Vector<T>::sort_dec() {
for (int i = 0; i < _size; ++i) {
for (int j = i + 1; j < _size; ++j) {
if (_data[j] > _data[i]) {
swap(i, j);
}
}
}
}
template <class T>
int Vector<T>::size() const {
return _size;
}
template <class T>
int Vector<T>::capacity() const {
return _actual_size;
}
template <class T>
void Vector<T>::ensure_capacity(const int capacity) {
if (capacity <= _actual_size) {
return;
}
int tsize = capacity + _grow_by;
T *nd = new T[tsize];
if (_data) {
for (int i = 0; i < _size; ++i) {
nd[i] = _data[i];
}
delete[] _data;
}
_data = nd;
_actual_size = tsize;
}
template <class T>
void Vector<T>::resize(const int s) {
ensure_capacity(s);
_size = s;
}
template <class T>
void Vector<T>::append_array(const Vector<T> &other) {
ensure_capacity(_size + other._size);
for (int i = 0; i < other._size; ++i) {
_data[_size++] = other._data[i];
}
}
template <class T>
int Vector<T>::find(const T &val) const {
for (int i = 0; i < _size; ++i) {
if (_data[i] == val) {
return i;
}
}
return -1;
}
template <class T>
T *Vector<T>::dataw() {
return _data;
}
template <class T>
const T *Vector<T>::data() const {
return _data;
}
template <class T>
const T &Vector<T>::operator[](const int index) const {
return _data[index];
}
template <class T>
T &Vector<T>::operator[](const int index) {
return _data[index];
}
template <class T>
Vector<T> &Vector<T>::operator=(const Vector<T> &other) {
resize(0);
ensure_capacity(other.size());
append_array(other);
return *this;
}
template <class T>
Vector<T>::Vector() {
_data = nullptr;
_actual_size = 0;
_size = 0;
_grow_by = 100;
}
template <class T>
Vector<T>::Vector(int prealloc) {
_data = nullptr;
_actual_size = 0;
_size = 0;
_grow_by = 100;
ensure_capacity(prealloc);
}
template <class T>
Vector<T>::Vector(int prealloc, int grow_by) {
_data = nullptr;
_actual_size = 0;
_size = 0;
_grow_by = grow_by;
ensure_capacity(prealloc);
}
template <class T>
Vector<T>::Vector(const Vector<T> &other) {
_actual_size = other._actual_size;
_size = other._size;
_grow_by = other._grow_by;
if (other._data) {
_data = new T[_actual_size];
for (int i = 0; i < _size; ++i) {
_data[i] = other._data[i];
}
}
}
template <class T>
Vector<T>::~Vector() {
if (_data) {
delete[] _data;
_data = nullptr;
}
}
#endif

93
core/error_list.h Normal file
View File

@ -0,0 +1,93 @@
/*************************************************************************/
/* error_list.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 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 ERROR_LIST_H
#define ERROR_LIST_H
/** Error List. Please never compare an error against FAILED
* Either do result != OK , or !result. This way, Error fail
* values can be more detailed in the future.
*
* This is a generic error list, mainly for organizing a language of returning errors.
*/
enum Error {
OK, // (0)
FAILED, ///< Generic fail error
ERR_UNAVAILABLE, ///< What is requested is unsupported/unavailable
ERR_UNCONFIGURED, ///< The object being used hasn't been properly set up yet
ERR_UNAUTHORIZED, ///< Missing credentials for requested resource
ERR_PARAMETER_RANGE_ERROR, ///< Parameter given out of range (5)
ERR_OUT_OF_MEMORY, ///< Out of memory
ERR_FILE_NOT_FOUND,
ERR_FILE_BAD_DRIVE,
ERR_FILE_BAD_PATH,
ERR_FILE_NO_PERMISSION, // (10)
ERR_FILE_ALREADY_IN_USE,
ERR_FILE_CANT_OPEN,
ERR_FILE_CANT_WRITE,
ERR_FILE_CANT_READ,
ERR_FILE_UNRECOGNIZED, // (15)
ERR_FILE_CORRUPT,
ERR_FILE_MISSING_DEPENDENCIES,
ERR_FILE_EOF,
ERR_CANT_OPEN, ///< Can't open a resource/socket/file
ERR_CANT_CREATE, // (20)
ERR_QUERY_FAILED,
ERR_ALREADY_IN_USE,
ERR_LOCKED, ///< resource is locked
ERR_TIMEOUT,
ERR_CANT_CONNECT, // (25)
ERR_CANT_RESOLVE,
ERR_CONNECTION_ERROR,
ERR_CANT_ACQUIRE_RESOURCE,
ERR_CANT_FORK,
ERR_INVALID_DATA, ///< Data passed is invalid (30)
ERR_INVALID_PARAMETER, ///< Parameter passed is invalid
ERR_ALREADY_EXISTS, ///< When adding, item already exists
ERR_DOES_NOT_EXIST, ///< When retrieving/erasing, if item does not exist
ERR_DATABASE_CANT_READ, ///< database is full
ERR_DATABASE_CANT_WRITE, ///< database is full (35)
ERR_COMPILATION_FAILED,
ERR_METHOD_NOT_FOUND,
ERR_LINK_FAILED,
ERR_SCRIPT_FAILED,
ERR_CYCLIC_LINK, // (40)
ERR_INVALID_DECLARATION,
ERR_DUPLICATE_SYMBOL,
ERR_PARSE_ERROR,
ERR_BUSY,
ERR_SKIP, // (45)
ERR_HELP, ///< user requested help!!
ERR_BUG, ///< a bug in the software certainly happened, due to a double check failing or unexpected behavior.
ERR_PRINTER_ON_FIRE, /// the parallel port printer is engulfed in flames
};
#endif

216
core/error_macros.h Normal file
View File

@ -0,0 +1,216 @@
#ifndef ERROR_MACROS_H
#define ERROR_MACROS_H
#include "core/log/logger.h"
#include "typedefs.h"
// Based on Godot Engine's error_macros.h
// MIT License
// Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.
// Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).
#ifdef _MSC_VER
#define GENERATE_TRAP \
__debugbreak(); \
/* Avoid warning about control paths */ \
for (;;) { \
}
#else
#define GENERATE_TRAP __builtin_trap();
#endif
// template methods for the variadic log macros. Add more as needed.
template <class STR, class A>
_FORCE_INLINE_ void _RLOG_MACRO_TEMPLATE_FUNC(STR str, A p0) {
str->append(p0);
}
template <class STR, class A, class B>
_FORCE_INLINE_ void _RLOG_MACRO_TEMPLATE_FUNC(STR str, A p0, B p1) {
str->append(p0);
str->push_back(' ');
str->append(p1);
}
template <class STR, class A, class B, class C>
_FORCE_INLINE_ void _RLOG_MACRO_TEMPLATE_FUNC(STR str, A p0, B p1, C p2) {
str->append(p0);
str->push_back(' ');
str->append(p1);
str->push_back(' ');
str->append(p2);
}
template <class STR, class A, class B, class C, class D>
_FORCE_INLINE_ void _RLOG_MACRO_TEMPLATE_FUNC(STR str, A p0, B p1, C p2, D p3) {
str->append(p0);
str->push_back(' ');
str->append(p1);
str->push_back(' ');
str->append(p2);
str->push_back(' ');
str->append(p3);
}
template <class STR, class A, class B, class C, class D, class E>
_FORCE_INLINE_ void _RLOG_MACRO_TEMPLATE_FUNC(STR str, A p0, B p1, C p2, D p3, E p4) {
str->append(p0);
str->push_back(' ');
str->append(p1);
str->push_back(' ');
str->append(p2);
str->push_back(' ');
str->append(p3);
str->push_back(' ');
str->append(p4);
}
#define RPRINT_TRACE(str) \
RLogger::print_trace(__FUNCTION__, __FILE__, __LINE__, str);
#define RLOG_TRACE(...) \
{ \
String *_rlogger_string_ptr = RLogger::get_trace_string_ptr(__FUNCTION__, __FILE__, __LINE__); \
_RLOG_MACRO_TEMPLATE_FUNC(_rlogger_string_ptr, __VA_ARGS__); \
RLogger::log_ret_ptr(_rlogger_string_ptr); \
}
#define RPRINT_MSG(str) \
RLogger::print_message(__FUNCTION__, __FILE__, __LINE__, str);
#define RLOG_MSG(...) \
{ \
String *_rlogger_string_ptr = RLogger::get_message_string_ptr(__FUNCTION__, __FILE__, __LINE__); \
_RLOG_MACRO_TEMPLATE_FUNC(_rlogger_string_ptr, __VA_ARGS__); \
RLogger::log_ret_ptr(_rlogger_string_ptr); \
}
#define RPRINT_WARN(str) \
RLogger::print_warning(__FUNCTION__, __FILE__, __LINE__, str);
#define RLOG_WARN(...) \
{ \
String *_rlogger_string_ptr = RLogger::get_warning_string_ptr(__FUNCTION__, __FILE__, __LINE__); \
_RLOG_MACRO_TEMPLATE_FUNC(_rlogger_string_ptr, __VA_ARGS__); \
RLogger::log_ret_ptr(_rlogger_string_ptr); \
}
#define RPRINT_ERR(str) \
RLogger::print_error(__FUNCTION__, __FILE__, __LINE__, str);
#define RLOG_ERR(...) \
{ \
String *_rlogger_string_ptr = RLogger::get_error_string_ptr(__FUNCTION__, __FILE__, __LINE__); \
_RLOG_MACRO_TEMPLATE_FUNC(_rlogger_string_ptr, __VA_ARGS__); \
RLogger::log_ret_ptr(_rlogger_string_ptr); \
}
#define ERR_FAIL_MSG(msg) \
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, msg); \
return;
#define ERR_FAIL_V_MSG(val, msg) \
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, msg); \
return val;
#define ERR_FAIL_INDEX(index, size) \
if ((index < 0) || (index >= size)) { \
RLogger::log_index_error(__FUNCTION__, __FILE__, __LINE__, index, size, ""); \
return; \
} else \
((void)0)
#define ERR_FAIL_INDEX_MSG(index, size, msg) \
if ((index < 0) || (index >= size)) { \
RLogger::log_index_error(__FUNCTION__, __FILE__, __LINE__, index, size, msg); \
return; \
} else \
((void)0)
#define ERR_FAIL_INDEX_V(index, size, val) \
if ((index < 0) || (index >= size)) { \
RLogger::log_index_error(__FUNCTION__, __FILE__, __LINE__, index, size, ""); \
return val; \
} else \
((void)0)
#define ERR_FAIL_INDEX_V_MSG(index, size, val, msg) \
if ((index < 0) || (index >= size)) { \
RLogger::log_index_error(__FUNCTION__, __FILE__, __LINE__, index, size, msg); \
return val; \
} else \
((void)0)
#define ERR_FAIL_COND(cond) \
if (cond) { \
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, "ERR_FAIL_COND: \"" #cond "\" is true!"); \
return; \
} else \
((void)0)
#define ERR_FAIL_COND_MSG(cond, msg) \
if (cond) { \
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, msg); \
return; \
} else \
((void)0)
#define ERR_FAIL_COND_V(cond, val) \
if (cond) { \
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, "ERR_FAIL_COND: \"" #cond "\" is true!"); \
return val; \
} else \
((void)0)
#define ERR_FAIL_COND_V_MSG(cond, val, msg) \
if (cond) { \
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, msg); \
return val; \
} else \
((void)0)
#define ERR_CONTINUE(cond) \
if (cond) { \
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, "ERR_CONTINUE: \"" #cond "\" is true!"); \
continue; \
} else \
((void)0)
#define ERR_CONTINUE_MSG(cond, msg) \
if (cond) { \
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, msg); \
continue; \
} else \
((void)0)
#define ERR_CONTINUE_ACTION(cond, action) \
if (cond) { \
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, "ERR_CONTINUE: \"" #cond "\" is true!"); \
action; \
continue; \
} else \
((void)0)
#define ERR_CONTINUE_ACTION_MSG(cond, action, msg) \
if (cond) { \
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, msg); \
action; \
continue; \
} else \
((void)0)
#define CRASH_INDEX(index, size) \
if ((index < 0) || (index >= size)) { \
RLogger::log_index_error(__FUNCTION__, __FILE__, __LINE__, index, size, "CRASH!"); \
GENERATE_TRAP \
} else \
((void)0)
#define CRASH_COND(cond) \
if (cond) { \
RLogger::log_error(__FUNCTION__, __FILE__, __LINE__, "CRASH_COND: \"" #cond "\" is true!"); \
GENERATE_TRAP \
} else \
((void)0)
#endif

3005
core/image/image.cpp Normal file

File diff suppressed because it is too large Load Diff

310
core/image/image.h Normal file
View File

@ -0,0 +1,310 @@
/*************************************************************************/
/* image.h */
/*************************************************************************/
/* This file is part of: */
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
/* Copyright (c) 2014-2022 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 IMAGE_H
#define IMAGE_H
#include "core/math/color.h"
#include "core/math/rect2.h"
#include "core/containers/vector.h"
#include "core/resource.h"
#include "core/math/rect2i.h"
#include "core/math/vector2i.h"
class Image : public Resource {
RCPP_OBJECT(Image, Resource);
public:
enum {
MAX_WIDTH = 16384, // force a limit somehow
MAX_HEIGHT = 16384 // force a limit somehow
};
enum Format {
FORMAT_L8, //luminance
FORMAT_LA8, //luminance-alpha
FORMAT_R8,
FORMAT_RG8,
FORMAT_RGB8,
FORMAT_RGBA8,
FORMAT_RGBA4444,
FORMAT_RGBA5551,
FORMAT_RF, //float
FORMAT_RGF,
FORMAT_RGBF,
FORMAT_RGBAF,
FORMAT_RH, //half float
FORMAT_RGH,
FORMAT_RGBH,
FORMAT_RGBAH,
FORMAT_RGBE9995,
FORMAT_DXT1, //s3tc bc1
FORMAT_DXT3, //bc2
FORMAT_DXT5, //bc3
FORMAT_RGTC_R,
FORMAT_RGTC_RG,
FORMAT_BPTC_RGBA, //btpc bc7
FORMAT_BPTC_RGBF, //float bc6h
FORMAT_BPTC_RGBFU, //unsigned float bc6hu
FORMAT_PVRTC2, //pvrtc
FORMAT_PVRTC2A,
FORMAT_PVRTC4,
FORMAT_PVRTC4A,
FORMAT_ETC, //etc1
FORMAT_ETC2_R11, //etc2
FORMAT_ETC2_R11S, //signed, NOT srgb.
FORMAT_ETC2_RG11,
FORMAT_ETC2_RG11S,
FORMAT_ETC2_RGB8,
FORMAT_ETC2_RGBA8,
FORMAT_ETC2_RGB8A1,
FORMAT_MAX
};
static const char *format_names[FORMAT_MAX];
enum Interpolation {
INTERPOLATE_NEAREST,
INTERPOLATE_BILINEAR,
INTERPOLATE_CUBIC,
INTERPOLATE_TRILINEAR,
INTERPOLATE_LANCZOS,
/* INTERPOLATE_TRICUBIC, */
/* INTERPOLATE GAUSS */
};
enum CompressSource {
COMPRESS_SOURCE_GENERIC,
COMPRESS_SOURCE_SRGB,
COMPRESS_SOURCE_NORMAL,
COMPRESS_SOURCE_LAYERED,
COMPRESS_SOURCE_MAX,
};
bool write_lock;
private:
void _create_empty(int p_width, int p_height, bool p_use_mipmaps, Format p_format) {
create(p_width, p_height, p_use_mipmaps, p_format);
}
void _create_from_data(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data) {
create(p_width, p_height, p_use_mipmaps, p_format, p_data);
}
Format format;
Vector<uint8_t> data;
int width, height;
bool mipmaps;
void _copy_internals_from(const Image &p_image) {
format = p_image.format;
width = p_image.width;
height = p_image.height;
mipmaps = p_image.mipmaps;
data = p_image.data;
}
_FORCE_INLINE_ void _get_mipmap_offset_and_size(int p_mipmap, int &r_offset, int &r_width, int &r_height) const; //get where the mipmap begins in data
static int _get_dst_image_size(int p_width, int p_height, Format p_format, int &r_mipmaps, int p_mipmaps = -1);
bool _can_modify(Format p_format) const;
_FORCE_INLINE_ void _put_pixelb(int p_x, int p_y, uint32_t p_pixel_size, uint8_t *p_data, const uint8_t *p_pixel);
_FORCE_INLINE_ void _get_pixelb(int p_x, int p_y, uint32_t p_pixel_size, const uint8_t *p_data, uint8_t *p_pixel);
_FORCE_INLINE_ void _repeat_pixel_over_subsequent_memory(uint8_t *p_pixel, int p_pixel_size, int p_count);
static void average_4_uint8(uint8_t &p_out, const uint8_t &p_a, const uint8_t &p_b, const uint8_t &p_c, const uint8_t &p_d);
static void average_4_float(float &p_out, const float &p_a, const float &p_b, const float &p_c, const float &p_d);
static void average_4_half(uint16_t &p_out, const uint16_t &p_a, const uint16_t &p_b, const uint16_t &p_c, const uint16_t &p_d);
static void average_4_rgbe9995(uint32_t &p_out, const uint32_t &p_a, const uint32_t &p_b, const uint32_t &p_c, const uint32_t &p_d);
static void renormalize_uint8(uint8_t *p_rgb);
static void renormalize_float(float *p_rgb);
static void renormalize_half(uint16_t *p_rgb);
static void renormalize_rgbe9995(uint32_t *p_rgb);
public:
int get_width() const; ///< Get image width
int get_height() const; ///< Get image height
Vector2 get_size() const;
bool has_mipmaps() const;
int get_mipmap_count() const;
/**
* Convert the image to another format, conversion only to raw byte format
*/
void convert(Format p_new_format);
/**
* Get the current image format.
*/
Format get_format() const;
int get_mipmap_offset(int p_mipmap) const; //get where the mipmap begins in data
void get_mipmap_offset_and_size(int p_mipmap, int &r_ofs, int &r_size) const; //get where the mipmap begins in data
void get_mipmap_offset_size_and_dimensions(int p_mipmap, int &r_ofs, int &r_size, int &w, int &h) const; //get where the mipmap begins in data
/**
* Resize the image, using the preferred interpolation method.
*/
void resize_to_po2(bool p_square = false, Interpolation p_interpolation = INTERPOLATE_BILINEAR);
void resize(int p_width, int p_height, Interpolation p_interpolation = INTERPOLATE_BILINEAR);
void shrink_x2();
bool is_size_po2() const;
/**
* Crop the image to a specific size, if larger, then the image is filled by black
*/
void crop_from_point(int p_x, int p_y, int p_width, int p_height);
void crop(int p_width, int p_height);
void flip_x();
void flip_y();
/**
* Generate a mipmap to an image (creates an image 1/4 the size, with averaging of 4->1)
*/
int generate_mipmaps(bool p_renormalize = false);
void clear_mipmaps();
void normalize(); //for normal maps
/**
* Create a new image of a given size and format. Current image will be lost
*/
void create(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
void create(int p_width, int p_height, bool p_use_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
void create(const char **p_xpm);
/**
* returns true when the image is empty (0,0) in size
*/
bool empty() const;
Vector<uint8_t> get_data() const;
const uint8_t* datar() const;
uint8_t* dataw();
int get_data_size() const;
Image();
Image(int p_width, int p_height, bool p_use_mipmaps, Format p_format);
Image(int p_width, int p_height, bool p_mipmaps, Format p_format, const Vector<uint8_t> &p_data);
enum AlphaMode {
ALPHA_NONE,
ALPHA_BIT,
ALPHA_BLEND
};
AlphaMode detect_alpha() const;
bool is_invisible() const;
static int get_format_pixel_size(Format p_format);
static int get_format_pixel_rshift(Format p_format);
static int get_format_block_size(Format p_format);
static void get_format_min_pixel_size(Format p_format, int &r_w, int &r_h);
static int get_image_data_size(int p_width, int p_height, Format p_format, bool p_mipmaps = false);
static int get_image_required_mipmaps(int p_width, int p_height, Format p_format);
static int get_image_mipmap_offset(int p_width, int p_height, Format p_format, int p_mipmap);
enum CompressMode {
COMPRESS_S3TC,
COMPRESS_PVRTC2,
COMPRESS_PVRTC4,
COMPRESS_ETC,
COMPRESS_ETC2,
COMPRESS_BPTC,
COMPRESS_MAX,
};
bool is_compressed() const;
void fix_alpha_edges();
void premultiply_alpha();
void srgb_to_linear();
void normalmap_to_xy();
Ref<Image> rgbe_to_srgb();
void bumpmap_to_normalmap(float bump_scale = 1.0);
void blit_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Vector2 &p_dest);
void blit_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Vector2 &p_dest);
void blend_rect(const Ref<Image> &p_src, const Rect2 &p_src_rect, const Vector2 &p_dest);
void blend_rect_mask(const Ref<Image> &p_src, const Ref<Image> &p_mask, const Rect2 &p_src_rect, const Vector2 &p_dest);
void fill(const Color &p_color);
void fill_rect(const Rect2 &p_rect, const Color &p_color);
Rect2 get_used_rect() const;
Ref<Image> get_rect(const Rect2 &p_area) const;
static void set_compress_bc_func(void (*p_compress_func)(Image *, float, CompressSource));
static void set_compress_bptc_func(void (*p_compress_func)(Image *, float, CompressSource));
static String get_format_name(Format p_format);
Image(const char **p_xpm);
virtual Ref<Resource> duplicate(bool p_subresources = false) const;
void lock();
void unlock();
//this is used for compression
enum DetectChannels {
DETECTED_L,
DETECTED_LA,
DETECTED_R,
DETECTED_RG,
DETECTED_RGB,
DETECTED_RGBA,
};
DetectChannels get_detected_channels();
void optimize_channels();
Color get_pixelv(const Vector2 &p_src) const;
Color get_pixel(int p_x, int p_y) const;
void set_pixelv(const Vector2 &p_dst, const Color &p_color);
void set_pixel(int p_x, int p_y, const Color &p_color);
void copy_internals_from(const Ref<Image> &p_image) {
ERR_FAIL_COND(p_image.is_null());
format = p_image->format;
width = p_image->width;
height = p_image->height;
mipmaps = p_image->mipmaps;
data = p_image->data;
}
~Image();
};
#endif

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

205
core/log/logger.cpp Normal file
View File

@ -0,0 +1,205 @@
#include "logger.h"
#include "core/string.h"
#include <cstdio>
#include "logger.h"
#include <stdio.h>
#include <thread>
void RLogger::print_trace(const String &str) {
print_trace(str.data());
}
void RLogger::print_trace(const char *str) {
printf("T %s\n", str);
}
void RLogger::print_trace(const char *p_function, const char *p_file, int p_line, const char *str) {
printf("T | %s::%s:%d | %s\n", p_file, p_function, p_line, str);
}
void RLogger::print_trace(const char *p_function, const char *p_file, int p_line, const String &str) {
printf("T | %s::%s:%d | %s\n", p_file, p_function, p_line, str.c_str());
}
void RLogger::print_message(const String &str) {
print_message(str.data());
}
void RLogger::print_message(const char *str) {
printf("M %s\n", str);
}
void RLogger::print_message(const char *p_function, const char *p_file, int p_line, const char *str) {
printf("M | %s::%s:%d | %s\n", p_file, p_function, p_line, str);
}
void RLogger::print_message(const char *p_function, const char *p_file, int p_line, const String &str) {
printf("M | %s::%s:%d | %s\n", p_file, p_function, p_line, str.c_str());
}
void RLogger::print_warning(const String &str) {
print_warning(str.data());
}
void RLogger::print_warning(const char *str) {
printf("W %s\n", str);
}
void RLogger::print_warning(const char *p_function, const char *p_file, int p_line, const char *str) {
printf("W | %s::%s:%d | %s\n", p_file, p_function, p_line, str);
}
void RLogger::print_warning(const char *p_function, const char *p_file, int p_line, const String &str) {
printf("W | %s::%s:%d | %s\n", p_file, p_function, p_line, str.c_str());
}
void RLogger::print_error(const String &str) {
print_error(str.data());
}
void RLogger::print_error(const char *str) {
printf("E %s\n", str);
}
void RLogger::print_error(const char *p_function, const char *p_file, int p_line, const char *str) {
printf("E | %s::%s:%d | %s\n", p_file, p_function, p_line, str);
}
void RLogger::print_error(const char *p_function, const char *p_file, int p_line, const String &str) {
printf("E | %s::%s:%d | %s\n", p_file, p_function, p_line, str.c_str());
}
void RLogger::print_msg_error(const char *p_function, const char *p_file, int p_line, const char *p_msg, const char *str) {
printf("E | %s::%s:%d | :: %s. %s\n", p_file, p_function, p_line, str, p_msg);
}
void RLogger::print_index_error(const char *p_function, const char *p_file, int p_line, const int index, const int size, const char *str) {
printf("E (INDEX) | %s::%s:%d | :: index: %d/%d. %s\n", p_file, p_function, p_line, index, size, str);
}
void RLogger::log_trace(const String &str) {
log_trace(str.data());
}
void RLogger::log_trace(const char *str) {
printf("T %s\n", str);
}
void RLogger::log_trace(const char *p_function, const char *p_file, int p_line, const char *str) {
printf("T | %s::%s:%d | %s\n", p_file, p_function, p_line, str);
}
void RLogger::log_trace(const char *p_function, const char *p_file, int p_line, const String &str) {
printf("T | %s::%s:%d | %s\n", p_file, p_function, p_line, str.c_str());
}
void RLogger::log_message(const String &str) {
log_message(str.data());
}
void RLogger::log_message(const char *str) {
printf("M %s\n", str);
}
void RLogger::log_message(const char *p_function, const char *p_file, int p_line, const char *str) {
printf("M | %s::%s:%d | %s\n", p_file, p_function, p_line, str);
}
void RLogger::log_message(const char *p_function, const char *p_file, int p_line, const String &str) {
printf("M | %s::%s:%d | %s\n", p_file, p_function, p_line, str.c_str());
}
void RLogger::log_warning(const String &str) {
log_warning(str.data());
}
void RLogger::log_warning(const char *str) {
printf("W %s\n", str);
}
void RLogger::log_warning(const char *p_function, const char *p_file, int p_line, const char *str) {
printf("W | %s::%s:%d | %s\n", p_file, p_function, p_line, str);
}
void RLogger::log_warning(const char *p_function, const char *p_file, int p_line, const String &str) {
printf("W | %s::%s:%d | %s\n", p_file, p_function, p_line, str.c_str());
}
void RLogger::log_error(const String &str) {
log_error(str.data());
}
void RLogger::log_error(const char *str) {
printf("E %s\n", str);
}
void RLogger::log_error(const char *p_function, const char *p_file, int p_line, const char *str) {
printf("E | %s::%s:%d | %s\n", p_file, p_function, p_line, str);
}
void RLogger::log_error(const char *p_function, const char *p_file, int p_line, const String &str) {
printf("E | %s::%s:%d | %s\n", p_file, p_function, p_line, str.c_str());
}
void RLogger::log_msg_error(const char *p_function, const char *p_file, int p_line, const char *p_msg, const char *str) {
printf("E | %s::%s:%d | :: %s. %s\n", p_file, p_function, p_line, str, p_msg);
}
void RLogger::log_index_error(const char *p_function, const char *p_file, int p_line, const int index, const int size, const char *str) {
printf("E (INDEX) | %s::%s:%d | :: index: %d/%d. %s\n", p_file, p_function, p_line, index, size, str);
}
String *RLogger::get_string_ptr(const int p_default_size) {
return new String(p_default_size);
}
String *RLogger::get_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size) {
String *s = new String(p_default_size);
s->append_str(p_function);
s->append_str("::");
s->append_str(p_file);
s->append_str(":");
s->append_str(String::num(p_line));
s->append_str(" | ");
return s;
}
String *RLogger::get_string_ptr(const char *p_prefix, const char *p_function, const char *p_file, int p_line, const int p_default_size) {
String *s = new String(p_default_size);
s->append_str(p_prefix);
s->append_str(" | ");
s->append_str(p_function);
s->append_str("::");
s->append_str(p_file);
s->append_str(":");
s->append_str(String::num(p_line));
s->append_str(" | ");
return s;
}
void RLogger::return_string_ptr(String *str) {
delete str;
}
String *RLogger::get_trace_string_ptr(const int p_default_size) {
String *str = get_string_ptr(p_default_size);
str->append_str("T ");
return str;
}
String *RLogger::get_message_string_ptr(const int p_default_size) {
String *str = get_string_ptr(p_default_size);
str->append_str("M ");
return str;
}
String *RLogger::get_warning_string_ptr(const int p_default_size) {
String *str = get_string_ptr(p_default_size);
str->append_str("W ");
return str;
}
String *RLogger::get_error_string_ptr(const int p_default_size) {
String *str = get_string_ptr(p_default_size);
str->append_str("E ");
return str;
}
String *RLogger::get_trace_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size) {
return get_string_ptr("T", p_function, p_file, p_line, p_default_size);
}
String *RLogger::get_message_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size) {
return get_string_ptr("M", p_function, p_file, p_line, p_default_size);
}
String *RLogger::get_warning_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size) {
return get_string_ptr("W", p_function, p_file, p_line, p_default_size);
}
String *RLogger::get_error_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size) {
return get_string_ptr("E", p_function, p_file, p_line, p_default_size);
}
void RLogger::log_ptr(String *str) {
printf("%s\n", str->data());
}
void RLogger::log_ret_ptr(String *str) {
log_ptr(str);
return_string_ptr(str);
}

77
core/log/logger.h Normal file
View File

@ -0,0 +1,77 @@
#ifndef LOGGER_H
#define LOGGER_H
#include <cstring>
#include <functional>
#include <iostream>
#include <vector>
class String;
class RLogger {
public:
static void print_trace(const String &str);
static void print_trace(const char *str);
static void print_trace(const char *p_function, const char *p_file, int p_line, const String &str);
static void print_trace(const char *p_function, const char *p_file, int p_line, const char *str);
static void print_message(const String &str);
static void print_message(const char *str);
static void print_message(const char *p_function, const char *p_file, int p_line, const String &str);
static void print_message(const char *p_function, const char *p_file, int p_line, const char *str);
static void print_warning(const String &str);
static void print_warning(const char *str);
static void print_warning(const char *p_function, const char *p_file, int p_line, const String &str);
static void print_warning(const char *p_function, const char *p_file, int p_line, const char *str);
static void print_error(const String &str);
static void print_error(const char *str);
static void print_error(const char *p_function, const char *p_file, int p_line, const char *str);
static void print_error(const char *p_function, const char *p_file, int p_line, const String &str);
static void print_msg_error(const char *p_function, const char *p_file, int p_line, const char *p_msg, const char *str);
static void print_index_error(const char *p_function, const char *p_file, int p_line, const int index, const int size, const char *str);
static void log_trace(const String &str);
static void log_trace(const char *str);
static void log_trace(const char *p_function, const char *p_file, int p_line, const String &str);
static void log_trace(const char *p_function, const char *p_file, int p_line, const char *str);
static void log_message(const String &str);
static void log_message(const char *str);
static void log_message(const char *p_function, const char *p_file, int p_line, const String &str);
static void log_message(const char *p_function, const char *p_file, int p_line, const char *str);
static void log_warning(const String &str);
static void log_warning(const char *str);
static void log_warning(const char *p_function, const char *p_file, int p_line, const String &str);
static void log_warning(const char *p_function, const char *p_file, int p_line, const char *str);
static void log_error(const String &str);
static void log_error(const char *str);
static void log_error(const char *p_function, const char *p_file, int p_line, const char *str);
static void log_error(const char *p_function, const char *p_file, int p_line, const String &str);
static void log_msg_error(const char *p_function, const char *p_file, int p_line, const char *p_msg, const char *str);
static void log_index_error(const char *p_function, const char *p_file, int p_line, const int index, const int size, const char *str);
static String *get_string_ptr(const int p_default_size = 100);
static String *get_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size = 300);
static String *get_string_ptr(const char *p_prefix, const char *p_function, const char *p_file, int p_line, const int p_default_size = 300);
static void return_string_ptr(String *str);
static String *get_trace_string_ptr(const int p_default_size = 100);
static String *get_message_string_ptr(const int p_default_size = 100);
static String *get_warning_string_ptr(const int p_default_size = 100);
static String *get_error_string_ptr(const int p_default_size = 100);
static String *get_trace_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size = 300);
static String *get_message_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size = 300);
static String *get_warning_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size = 300);
static String *get_error_string_ptr(const char *p_function, const char *p_file, int p_line, const int p_default_size = 300);
static void log_ptr(String *str);
static void log_ret_ptr(String *str);
};
#endif

14
core/memory.h Normal file
View File

@ -0,0 +1,14 @@
#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
#define memnew_arr(m_class, size) new m_class[size]
#define memdelete_arr(instance) delete[] instance
#endif

122
core/nodes/node.cpp Normal file
View File

@ -0,0 +1,122 @@
#include "node.h"
#include "node_tree.h"
bool Node::is_in_tree() const {
return _in_tree;
}
Node *Node::get_parent() {
return _parent;
}
void Node::set_parent(Node *parent) {
if (_parent == parent) {
return;
}
if (_parent) {
notification(NOTIFICATION_UNPARENTED);
}
_parent = parent;
if (_parent) {
notification(NOTIFICATION_PARENTED);
}
}
int Node::get_child_count() {
return _children.size();
}
Node *Node::get_child(int index) {
return _children[index];
}
void Node::add_child(Node *child) {
ERR_FAIL_COND(!child);
ERR_FAIL_COND(child->get_parent());
_children.push_back(child);
child->set_parent(this);
if (_in_tree) {
child->set_tree(_tree);
child->notification(NOTIFICATION_EXIT_TREE);
}
notification(NOTIFICATION_CHILD_ADDED);
}
void Node::remove_child_index(int index) {
Node *c = _children[index];
_children.remove_keep_order(index);
c->set_parent(nullptr);
notification(NOTIFICATION_CHILD_REMOVED);
}
void Node::remove_child(Node *child) {
ERR_FAIL_COND(!child);
for (int i = 0; i < _children.size(); ++i) {
Node *c = _children[i];
if (c == child) {
_children.remove_keep_order(i);
child->set_parent(nullptr);
notification(NOTIFICATION_CHILD_REMOVED);
return;
}
}
}
NodeTree *Node::get_tree() {
return _tree;
}
void Node::set_tree(NodeTree *tree) {
if (_tree) {
_in_tree = false;
_notification(NOTIFICATION_EXIT_TREE);
}
_tree = tree;
if (_tree) {
_in_tree = true;
}
for (int i = 0; i < _children.size(); ++i) {
_children[i]->set_tree(tree);
}
if (_tree) {
_notification(NOTIFICATION_ENTER_TREE);
}
}
void Node::notification(const int what) {
_notification(what);
for (int i = 0; i < _children.size(); ++i) {
_children[i]->notification(what);
}
}
void Node::_notification(const int what) {
}
Node::Node() :
Object() {
_in_tree = false;
_parent = nullptr;
_tree = nullptr;
}
Node::~Node() {
for (int i = 0; i < _children.size(); ++i) {
delete _children[i];
}
_children.clear();
}

52
core/nodes/node.h Normal file
View File

@ -0,0 +1,52 @@
#ifndef NODE_H
#define NODE_H
#include "core/object.h"
#include "core/containers/vector.h"
class NodeTree;
class Node : public Object {
RCPP_OBJECT(Node, Object);
public:
enum {
NOTIFICATION_ENTER_TREE = 0,
NOTIFICATION_EXIT_TREE = 1,
NOTIFICATION_PARENTED = 2,
NOTIFICATION_UNPARENTED = 3,
NOTIFICATION_CHILD_ADDED = 4,
NOTIFICATION_CHILD_REMOVED = 5,
NOTIFICATION_CHILD_MOVED = 6,
NOTIFICATION_UPDATE = 7,
NOTIFICATION_TREE_WRITE_LOCKED = 8,
};
bool is_in_tree() const;
Node *get_parent();
void set_parent(Node *parent);
int get_child_count();
Node *get_child(int index);
void add_child(Node *child);
void remove_child_index(int index);
void remove_child(Node *child);
NodeTree *get_tree();
void set_tree(NodeTree *tree);
virtual void notification(const int what);
virtual void _notification(const int what);
Node();
~Node();
protected:
bool _in_tree;
Node * _parent;
Vector<Node *> _children;
NodeTree *_tree;
};
#endif

60
core/nodes/node_tree.cpp Normal file
View File

@ -0,0 +1,60 @@
#include "node_tree.h"
#include "node.h"
Node *NodeTree::get_root() {
return _root_node;
}
void NodeTree::set_root(Node *root) {
if (_root_node) {
_root_node->set_tree(nullptr);
}
_root_node = root;
if (_root_node) {
_root_node->set_tree(this);
}
}
void NodeTree::update() {
if (!_root_node) {
return;
}
_root_node->notification(Node::NOTIFICATION_UPDATE);
if (_write_lock_requested) {
_rw_lock.write_lock();
_root_node->notification(Node::NOTIFICATION_TREE_WRITE_LOCKED);
_rw_lock.write_unlock();
_write_lock_requested = false;
}
}
void NodeTree::_send_update() {
if (_root_node) {
_root_node->notification(Node::NOTIFICATION_UPDATE);
}
}
float NodeTree::get_update_delta_time() {
return 0;
}
NodeTree::NodeTree() :
Object() {
_root_node = nullptr;
_update_interval = 0;
}
NodeTree::~NodeTree() {
if (_root_node) {
delete _root_node;
_root_node = nullptr;
}
}

35
core/nodes/node_tree.h Normal file
View File

@ -0,0 +1,35 @@
#ifndef NODE_TREE_H
#define NODE_TREE_H
#include "core/object.h"
#include "core/threading/rw_lock.h"
class Node;
class NodeTree : public Object {
RCPP_OBJECT(NodeTree, Object);
public:
Node *get_root();
virtual void set_root(Node *root);
virtual void update();
void request_write_lock();
virtual float get_update_delta_time();
NodeTree();
~NodeTree();
protected:
virtual void _send_update();
Node *_root_node;
float _update_interval;
bool _write_lock_requested;
RWLock _rw_lock;
};
#endif

11
core/object.cpp Normal file
View File

@ -0,0 +1,11 @@
#include "object.h"
#include "database/database.h"
Object::Object() {
db = nullptr;
}
Object::~Object() {
}

93
core/object.h Normal file
View File

@ -0,0 +1,93 @@
#ifndef OBJECT_H
#define OBJECT_H
#include "core/string.h"
#include "core/containers/vector.h"
class Database;
//taken from GodotEngine's object.h
#define RCPP_OBJECT(m_class, m_inherits) \
private: \
void operator=(const m_class &p_rval) {} \
\
public: \
virtual String get_class() const override { \
return String(#m_class); \
} \
static void *get_class_ptr_static() { \
static int ptr; \
return &ptr; \
} \
static String get_class_static() { \
return String(#m_class); \
} \
static String get_parent_class_static() { \
return m_inherits::get_class_static(); \
} \
static void get_inheritance_list_static(Vector<String> *p_inheritance_list) { \
m_inherits::get_inheritance_list_static(p_inheritance_list); \
p_inheritance_list->push_back(String(#m_class)); \
} \
static String inherits_static() { \
return String(#m_inherits); \
} \
virtual bool is_class(const String &p_class) const override { return (p_class == (#m_class)) ? true : m_inherits::is_class(p_class); } \
virtual bool is_class_ptr(void *p_ptr) const override { return (p_ptr == get_class_ptr_static()) ? true : m_inherits::is_class_ptr(p_ptr); } \
\
static void get_valid_parents_static(Vector<String> *p_parents) { \
if (m_class::_get_valid_parents_static != m_inherits::_get_valid_parents_static) { \
m_class::_get_valid_parents_static(p_parents); \
} \
\
m_inherits::get_valid_parents_static(p_parents); \
} \
\
private:
class Object {
public:
Database *db;
virtual String get_class() const { return "Object"; }
static void *get_class_ptr_static() {
static int ptr;
return &ptr;
}
static String get_class_static() { return "Object"; }
static String get_parent_class_static() { return String(); }
static void get_inheritance_list_static(Vector<String> *p_inheritance_list) { p_inheritance_list->push_back("Object"); }
virtual bool is_class(const String &p_class) const { return (p_class == "Object"); }
virtual bool is_class_ptr(void *p_ptr) const { return get_class_ptr_static() == p_ptr; }
static void get_valid_parents_static(Vector<String> *p_parents) {}
static void _get_valid_parents_static(Vector<String> *p_parents) {}
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

240
core/os/directory.cpp Normal file
View File

@ -0,0 +1,240 @@
#include "directory.h"
Error Directory::open_dir(const String &path, bool skip_specials) {
if (_dir_open) {
return ERR_CANT_ACQUIRE_RESOURCE;
}
_skip_specials = skip_specials;
if (tinydir_open(&_dir, path.c_str()) == -1) {
return FAILED;
}
_dir_open = true;
return OK;
}
Error Directory::open_dir(const char *path, bool skip_specials) {
if (_dir_open) {
return ERR_CANT_ACQUIRE_RESOURCE;
}
_skip_specials = skip_specials;
if (tinydir_open(&_dir, path) == -1) {
return FAILED;
}
_dir_open = true;
return OK;
}
void Directory::close_dir() {
if (!_dir_open) {
return;
}
tinydir_close(&_dir);
_dir_open = false;
}
bool Directory::has_next() {
return _dir.has_next;
}
bool Directory::read() {
_read_file_result = tinydir_readfile(&_dir, &_file);
return _read_file_result != -1;
}
bool Directory::next() {
if (!_dir.has_next) {
return false;
}
bool rres = read();
while (!rres && _dir.has_next) {
tinydir_next(&_dir);
rres = read();
}
if (!rres) {
return false;
}
if (_dir.has_next) {
tinydir_next(&_dir);
}
if (_skip_specials && current_is_dir() && current_is_special_dir()) {
return next();
}
return true;
}
bool Directory::current_is_ok() {
return _read_file_result == 01;
}
String Directory::current_get_name() {
return String(_file.name);
}
String Directory::current_get_path() {
return String(_file.path);
}
String Directory::current_get_extension() {
return String(_file.extension);
}
const char *Directory::current_get_name_cstr() {
return _file.name;
}
const char *Directory::current_get_path_cstr() {
return _file.path;
}
const char *Directory::current_get_extension_cstr() {
return _file.extension;
}
bool Directory::current_is_file() {
return !_file.is_dir;
}
bool Directory::current_is_dir() {
return _file.is_dir;
}
bool Directory::current_is_special_dir() {
if (_file.name[0] == '.' && _file.name[1] == '\0' || _file.name[0] == '.' && _file.name[1] == '.') {
return true;
}
return false;
}
String Directory::read_file(const String &path) {
FILE *f = fopen(path.c_str(), "r");
String fd;
ERR_FAIL_COND_V_MSG(!f, fd, "Error opening file! " + path);
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET); /* same as rewind(f); */
fd.resize(fsize);
fread(fd.dataw(), 1, fsize, f);
fclose(f);
return fd;
}
Error Directory::read_file_into(const String &path, String *str) {
if (!str) {
return ERR_PARAMETER_RANGE_ERROR;
}
FILE *f = fopen(path.c_str(), "r");
if (!f) {
return ERR_FILE_CANT_OPEN;
}
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET); /* same as rewind(f); */
str->resize(fsize);
fread(str->dataw(), 1, fsize, f);
fclose(f);
return OK;
}
Vector<uint8_t> Directory::read_file_bin(const String &path) {
FILE *f = fopen(path.c_str(), "rb");
Vector<uint8_t> fd;
ERR_FAIL_COND_V_MSG(!f, fd, "Error opening file! " + path);
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET); /* same as rewind(f); */
fd.resize(fsize);
fread(fd.dataw(), 1, fsize, f);
fclose(f);
return fd;
}
Error Directory::read_file_into_bin(const String &path, Vector<uint8_t> *data) {
if (!data) {
return ERR_PARAMETER_RANGE_ERROR;
}
FILE *f = fopen(path.c_str(), "rb");
if (!f) {
return ERR_FILE_CANT_OPEN;
}
fseek(f, 0, SEEK_END);
long fsize = ftell(f);
fseek(f, 0, SEEK_SET); /* same as rewind(f); */
data->resize(fsize);
fread(data->dataw(), 1, fsize, f);
fclose(f);
return OK;
}
Error Directory::write_file(const String &path, const String &str) {
FILE *f = fopen(path.c_str(), "w");
if (!f) {
return ERR_FILE_CANT_OPEN;
}
fwrite(str.data(), sizeof(char), str.size(), f);
fclose(f);
return OK;
}
Error Directory::write_file_bin(const String &path, const Vector<uint8_t> &data) {
FILE *f = fopen(path.c_str(), "wb");
if (!f) {
return ERR_FILE_CANT_OPEN;
}
fwrite(data.data(), sizeof(uint8_t), data.size(), f);
fclose(f);
return OK;
}
bool Directory::is_dir_open() {
return _dir_open;
}
bool Directory::is_dir_closed() {
return !_dir_open;
}
Directory::Directory() {
_skip_specials = true;
_read_file_result = 0;
_dir_open = false;
}
Directory::~Directory() {
if (is_dir_open()) {
close_dir();
}
}

55
core/os/directory.h Normal file
View File

@ -0,0 +1,55 @@
#ifndef DIRECTORY_H
#define DIRECTORY_H
#include "core/string.h"
#include "core/error_list.h"
#include <tinydir/tinydir.h>
#include "core/reference.h"
class Directory : public Reference {
RCPP_OBJECT(Directory, Reference);
public:
Error open_dir(const String &path, bool skip_specials = true);
Error open_dir(const char *path, bool skip_specials = true);
void close_dir();
bool has_next();
bool read();
bool next();
bool current_is_ok();
String current_get_name();
String current_get_path();
String current_get_extension();
const char *current_get_name_cstr();
const char *current_get_path_cstr();
const char *current_get_extension_cstr();
bool current_is_file();
bool current_is_dir();
bool current_is_special_dir();
String read_file(const String &path);
Error read_file_into(const String &path, String *str);
Vector<uint8_t> read_file_bin(const String &path);
Error read_file_into_bin(const String &path, Vector<uint8_t> *data);
Error write_file(const String &path, const String &str);
Error write_file_bin(const String &path, const Vector<uint8_t> &data);
bool is_dir_open();
bool is_dir_closed();
Directory();
virtual ~Directory();
private:
bool _skip_specials;
int _read_file_result;
tinydir_dir _dir;
tinydir_file _file;
bool _dir_open;
};
#endif

26
core/os/tinydir/COPYING Normal file
View File

@ -0,0 +1,26 @@
Copyright (c) 2013-2016, tinydir authors:
- Cong Xu
- Lautis Sun
- Baudouin Feildel
- Andargor <andargor@yahoo.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

79
core/os/tinydir/README.md Normal file
View File

@ -0,0 +1,79 @@
TinyDir
=======
[![Build Status](https://travis-ci.org/cxong/tinydir.svg?branch=master)](https://travis-ci.org/cxong/tinydir)
[![Release](http://img.shields.io/github/release/cxong/tinydir.svg)](https://github.com/cxong/tinydir/releases/latest)
Lightweight, portable and easy to integrate C directory and file reader. TinyDir wraps dirent for POSIX and FindFirstFile for Windows.
Windows unicode is supported by defining `UNICODE` and `_UNICODE` before including `tinydir.h`.
Example
=======
There are two methods. Error checking omitted:
```C
tinydir_dir dir;
tinydir_open(&dir, "/path/to/dir");
while (dir.has_next)
{
tinydir_file file;
tinydir_readfile(&dir, &file);
printf("%s", file.name);
if (file.is_dir)
{
printf("/");
}
printf("\n");
tinydir_next(&dir);
}
tinydir_close(&dir);
```
```C
tinydir_dir dir;
int i;
tinydir_open_sorted(&dir, "/path/to/dir");
for (i = 0; i < dir.n_files; i++)
{
tinydir_file file;
tinydir_readfile_n(&dir, &file, i);
printf("%s", file.name);
if (file.is_dir)
{
printf("/");
}
printf("\n");
}
tinydir_close(&dir);
```
See the `/samples` folder for more examples, including an interactive command-line directory navigator.
Language
========
ANSI C, or C90.
Platforms
=========
POSIX and Windows supported. Open to the possibility of supporting other platforms.
License
=======
Simplified BSD; if you use tinydir you can comply by including `tinydir.h` or `COPYING` somewhere in your package.
Known Limitations
=================
- Limited path and filename sizes
- [Possible race condition bug if folder being read has changing content](https://github.com/cxong/tinydir/issues/13)

View File

@ -0,0 +1,17 @@
{
"name": "tinydir",
"description": "Lightweight, portable and easy to integrate C directory and file reader",
"license": "BSD-2-Clause",
"keywords": [
"dir",
"directory",
"file",
"reader",
"filesystem"
],
"src": [
"tinydir.h"
],
"version": "1.2.4",
"repo": "cxong/tinydir"
}

831
core/os/tinydir/tinydir.h Normal file
View File

@ -0,0 +1,831 @@
/*
Copyright (c) 2013-2019, tinydir authors:
- Cong Xu
- Lautis Sun
- Baudouin Feildel
- Andargor <andargor@yahoo.com>
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions are met:
1. Redistributions of source code must retain the above copyright notice, this
list of conditions and the following disclaimer.
2. Redistributions in binary form must reproduce the above copyright notice,
this list of conditions and the following disclaimer in the documentation
and/or other materials provided with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*/
#ifndef TINYDIR_H
#define TINYDIR_H
#ifdef __cplusplus
extern "C" {
#endif
#if ((defined _UNICODE) && !(defined UNICODE))
#define UNICODE
#endif
#if ((defined UNICODE) && !(defined _UNICODE))
#define _UNICODE
#endif
#include <errno.h>
#include <stdlib.h>
#include <string.h>
#ifdef _MSC_VER
# ifndef WIN32_LEAN_AND_MEAN
# define WIN32_LEAN_AND_MEAN
# endif
# include <windows.h>
# include <tchar.h>
# pragma warning(push)
# pragma warning (disable : 4996)
#else
# include <dirent.h>
# include <libgen.h>
# include <sys/stat.h>
# include <stddef.h>
#endif
#ifdef __MINGW32__
# include <tchar.h>
#endif
/* types */
/* Windows UNICODE wide character support */
#if defined _MSC_VER || defined __MINGW32__
# define _tinydir_char_t TCHAR
# define TINYDIR_STRING(s) _TEXT(s)
# define _tinydir_strlen _tcslen
# define _tinydir_strcpy _tcscpy
# define _tinydir_strcat _tcscat
# define _tinydir_strcmp _tcscmp
# define _tinydir_strrchr _tcsrchr
# define _tinydir_strncmp _tcsncmp
#else
# define _tinydir_char_t char
# define TINYDIR_STRING(s) s
# define _tinydir_strlen strlen
# define _tinydir_strcpy strcpy
# define _tinydir_strcat strcat
# define _tinydir_strcmp strcmp
# define _tinydir_strrchr strrchr
# define _tinydir_strncmp strncmp
#endif
#if (defined _MSC_VER || defined __MINGW32__)
# include <windows.h>
# define _TINYDIR_PATH_MAX MAX_PATH
#elif defined __linux__
# include <limits.h>
# ifdef PATH_MAX
# define _TINYDIR_PATH_MAX PATH_MAX
# endif
#elif defined(__unix__) || (defined(__APPLE__) && defined(__MACH__))
# include <sys/param.h>
# if defined(BSD)
# include <limits.h>
# ifdef PATH_MAX
# define _TINYDIR_PATH_MAX PATH_MAX
# endif
# endif
#endif
#ifndef _TINYDIR_PATH_MAX
#define _TINYDIR_PATH_MAX 4096
#endif
#ifdef _MSC_VER
/* extra chars for the "\\*" mask */
# define _TINYDIR_PATH_EXTRA 2
#else
# define _TINYDIR_PATH_EXTRA 0
#endif
#define _TINYDIR_FILENAME_MAX 256
#if (defined _MSC_VER || defined __MINGW32__)
#define _TINYDIR_DRIVE_MAX 3
#endif
#ifdef _MSC_VER
# define _TINYDIR_FUNC static __inline
#elif !defined __STDC_VERSION__ || __STDC_VERSION__ < 199901L
# define _TINYDIR_FUNC static __inline__
#else
# define _TINYDIR_FUNC static inline
#endif
/* readdir_r usage; define TINYDIR_USE_READDIR_R to use it (if supported) */
#ifdef TINYDIR_USE_READDIR_R
/* readdir_r is a POSIX-only function, and may not be available under various
* environments/settings, e.g. MinGW. Use readdir fallback */
#if _POSIX_C_SOURCE >= 1 || _XOPEN_SOURCE || _BSD_SOURCE || _SVID_SOURCE ||\
_POSIX_SOURCE
# define _TINYDIR_HAS_READDIR_R
#endif
#if _POSIX_C_SOURCE >= 200112L
# define _TINYDIR_HAS_FPATHCONF
# include <unistd.h>
#endif
#if _BSD_SOURCE || _SVID_SOURCE || \
(_POSIX_C_SOURCE >= 200809L || _XOPEN_SOURCE >= 700)
# define _TINYDIR_HAS_DIRFD
# include <sys/types.h>
#endif
#if defined _TINYDIR_HAS_FPATHCONF && defined _TINYDIR_HAS_DIRFD &&\
defined _PC_NAME_MAX
# define _TINYDIR_USE_FPATHCONF
#endif
#if defined __MINGW32__ || !defined _TINYDIR_HAS_READDIR_R ||\
!(defined _TINYDIR_USE_FPATHCONF || defined NAME_MAX)
# define _TINYDIR_USE_READDIR
#endif
/* Use readdir by default */
#else
# define _TINYDIR_USE_READDIR
#endif
/* MINGW32 has two versions of dirent, ASCII and UNICODE*/
#ifndef _MSC_VER
#if (defined __MINGW32__) && (defined _UNICODE)
#define _TINYDIR_DIR _WDIR
#define _tinydir_dirent _wdirent
#define _tinydir_opendir _wopendir
#define _tinydir_readdir _wreaddir
#define _tinydir_closedir _wclosedir
#else
#define _TINYDIR_DIR DIR
#define _tinydir_dirent dirent
#define _tinydir_opendir opendir
#define _tinydir_readdir readdir
#define _tinydir_closedir closedir
#endif
#endif
/* Allow user to use a custom allocator by defining _TINYDIR_MALLOC and _TINYDIR_FREE. */
#if defined(_TINYDIR_MALLOC) && defined(_TINYDIR_FREE)
#elif !defined(_TINYDIR_MALLOC) && !defined(_TINYDIR_FREE)
#else
#error "Either define both alloc and free or none of them!"
#endif
#if !defined(_TINYDIR_MALLOC)
#define _TINYDIR_MALLOC(_size) malloc(_size)
#define _TINYDIR_FREE(_ptr) free(_ptr)
#endif /* !defined(_TINYDIR_MALLOC) */
typedef struct tinydir_file
{
_tinydir_char_t path[_TINYDIR_PATH_MAX];
_tinydir_char_t name[_TINYDIR_FILENAME_MAX];
_tinydir_char_t *extension;
int is_dir;
int is_reg;
#ifndef _MSC_VER
#ifdef __MINGW32__
struct _stat _s;
#else
struct stat _s;
#endif
#endif
} tinydir_file;
typedef struct tinydir_dir
{
_tinydir_char_t path[_TINYDIR_PATH_MAX];
int has_next;
size_t n_files;
tinydir_file *_files;
#ifdef _MSC_VER
HANDLE _h;
WIN32_FIND_DATA _f;
#else
_TINYDIR_DIR *_d;
struct _tinydir_dirent *_e;
#ifndef _TINYDIR_USE_READDIR
struct _tinydir_dirent *_ep;
#endif
#endif
} tinydir_dir;
/* declarations */
_TINYDIR_FUNC
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path);
_TINYDIR_FUNC
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path);
_TINYDIR_FUNC
void tinydir_close(tinydir_dir *dir);
_TINYDIR_FUNC
int tinydir_next(tinydir_dir *dir);
_TINYDIR_FUNC
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file);
_TINYDIR_FUNC
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i);
_TINYDIR_FUNC
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i);
_TINYDIR_FUNC
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path);
_TINYDIR_FUNC
void _tinydir_get_ext(tinydir_file *file);
_TINYDIR_FUNC
int _tinydir_file_cmp(const void *a, const void *b);
#ifndef _MSC_VER
#ifndef _TINYDIR_USE_READDIR
_TINYDIR_FUNC
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp);
#endif
#endif
/* definitions*/
_TINYDIR_FUNC
int tinydir_open(tinydir_dir *dir, const _tinydir_char_t *path)
{
#ifndef _MSC_VER
#ifndef _TINYDIR_USE_READDIR
int error;
int size; /* using int size */
#endif
#else
_tinydir_char_t path_buf[_TINYDIR_PATH_MAX];
#endif
_tinydir_char_t *pathp;
if (dir == NULL || path == NULL || _tinydir_strlen(path) == 0)
{
errno = EINVAL;
return -1;
}
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
{
errno = ENAMETOOLONG;
return -1;
}
/* initialise dir */
dir->_files = NULL;
#ifdef _MSC_VER
dir->_h = INVALID_HANDLE_VALUE;
#else
dir->_d = NULL;
#ifndef _TINYDIR_USE_READDIR
dir->_ep = NULL;
#endif
#endif
tinydir_close(dir);
_tinydir_strcpy(dir->path, path);
/* Remove trailing slashes */
pathp = &dir->path[_tinydir_strlen(dir->path) - 1];
while (pathp != dir->path && (*pathp == TINYDIR_STRING('\\') || *pathp == TINYDIR_STRING('/')))
{
*pathp = TINYDIR_STRING('\0');
pathp++;
}
#ifdef _MSC_VER
_tinydir_strcpy(path_buf, dir->path);
_tinydir_strcat(path_buf, TINYDIR_STRING("\\*"));
#if (defined WINAPI_FAMILY) && (WINAPI_FAMILY != WINAPI_FAMILY_DESKTOP_APP)
dir->_h = FindFirstFileEx(path_buf, FindExInfoStandard, &dir->_f, FindExSearchNameMatch, NULL, 0);
#else
dir->_h = FindFirstFile(path_buf, &dir->_f);
#endif
if (dir->_h == INVALID_HANDLE_VALUE)
{
errno = ENOENT;
#else
dir->_d = _tinydir_opendir(path);
if (dir->_d == NULL)
{
#endif
goto bail;
}
/* read first file */
dir->has_next = 1;
#ifndef _MSC_VER
#ifdef _TINYDIR_USE_READDIR
dir->_e = _tinydir_readdir(dir->_d);
#else
/* allocate dirent buffer for readdir_r */
size = _tinydir_dirent_buf_size(dir->_d); /* conversion to int */
if (size == -1) return -1;
dir->_ep = (struct _tinydir_dirent*)_TINYDIR_MALLOC(size);
if (dir->_ep == NULL) return -1;
error = readdir_r(dir->_d, dir->_ep, &dir->_e);
if (error != 0) return -1;
#endif
if (dir->_e == NULL)
{
dir->has_next = 0;
}
#endif
return 0;
bail:
tinydir_close(dir);
return -1;
}
_TINYDIR_FUNC
int tinydir_open_sorted(tinydir_dir *dir, const _tinydir_char_t *path)
{
/* Count the number of files first, to pre-allocate the files array */
size_t n_files = 0;
if (tinydir_open(dir, path) == -1)
{
return -1;
}
while (dir->has_next)
{
n_files++;
if (tinydir_next(dir) == -1)
{
goto bail;
}
}
tinydir_close(dir);
if (n_files == 0 || tinydir_open(dir, path) == -1)
{
return -1;
}
dir->n_files = 0;
dir->_files = (tinydir_file *)_TINYDIR_MALLOC(sizeof *dir->_files * n_files);
if (dir->_files == NULL)
{
goto bail;
}
while (dir->has_next)
{
tinydir_file *p_file;
dir->n_files++;
p_file = &dir->_files[dir->n_files - 1];
if (tinydir_readfile(dir, p_file) == -1)
{
goto bail;
}
if (tinydir_next(dir) == -1)
{
goto bail;
}
/* Just in case the number of files has changed between the first and
second reads, terminate without writing into unallocated memory */
if (dir->n_files == n_files)
{
break;
}
}
qsort(dir->_files, dir->n_files, sizeof(tinydir_file), _tinydir_file_cmp);
return 0;
bail:
tinydir_close(dir);
return -1;
}
_TINYDIR_FUNC
void tinydir_close(tinydir_dir *dir)
{
if (dir == NULL)
{
return;
}
memset(dir->path, 0, sizeof(dir->path));
dir->has_next = 0;
dir->n_files = 0;
_TINYDIR_FREE(dir->_files);
dir->_files = NULL;
#ifdef _MSC_VER
if (dir->_h != INVALID_HANDLE_VALUE)
{
FindClose(dir->_h);
}
dir->_h = INVALID_HANDLE_VALUE;
#else
if (dir->_d)
{
_tinydir_closedir(dir->_d);
}
dir->_d = NULL;
dir->_e = NULL;
#ifndef _TINYDIR_USE_READDIR
_TINYDIR_FREE(dir->_ep);
dir->_ep = NULL;
#endif
#endif
}
_TINYDIR_FUNC
int tinydir_next(tinydir_dir *dir)
{
if (dir == NULL)
{
errno = EINVAL;
return -1;
}
if (!dir->has_next)
{
errno = ENOENT;
return -1;
}
#ifdef _MSC_VER
if (FindNextFile(dir->_h, &dir->_f) == 0)
#else
#ifdef _TINYDIR_USE_READDIR
dir->_e = _tinydir_readdir(dir->_d);
#else
if (dir->_ep == NULL)
{
return -1;
}
if (readdir_r(dir->_d, dir->_ep, &dir->_e) != 0)
{
return -1;
}
#endif
if (dir->_e == NULL)
#endif
{
dir->has_next = 0;
#ifdef _MSC_VER
if (GetLastError() != ERROR_SUCCESS &&
GetLastError() != ERROR_NO_MORE_FILES)
{
tinydir_close(dir);
errno = EIO;
return -1;
}
#endif
}
return 0;
}
_TINYDIR_FUNC
int tinydir_readfile(const tinydir_dir *dir, tinydir_file *file)
{
const _tinydir_char_t *filename;
if (dir == NULL || file == NULL)
{
errno = EINVAL;
return -1;
}
#ifdef _MSC_VER
if (dir->_h == INVALID_HANDLE_VALUE)
#else
if (dir->_e == NULL)
#endif
{
errno = ENOENT;
return -1;
}
filename =
#ifdef _MSC_VER
dir->_f.cFileName;
#else
dir->_e->d_name;
#endif
if (_tinydir_strlen(dir->path) +
_tinydir_strlen(filename) + 1 + _TINYDIR_PATH_EXTRA >=
_TINYDIR_PATH_MAX)
{
/* the path for the file will be too long */
errno = ENAMETOOLONG;
return -1;
}
if (_tinydir_strlen(filename) >= _TINYDIR_FILENAME_MAX)
{
errno = ENAMETOOLONG;
return -1;
}
_tinydir_strcpy(file->path, dir->path);
if (_tinydir_strcmp(dir->path, TINYDIR_STRING("/")) != 0)
_tinydir_strcat(file->path, TINYDIR_STRING("/"));
_tinydir_strcpy(file->name, filename);
_tinydir_strcat(file->path, filename);
#ifndef _MSC_VER
#ifdef __MINGW32__
if (_tstat(
#elif (defined _BSD_SOURCE) || (defined _DEFAULT_SOURCE) \
|| ((defined _XOPEN_SOURCE) && (_XOPEN_SOURCE >= 500)) \
|| ((defined _POSIX_C_SOURCE) && (_POSIX_C_SOURCE >= 200112L))
if (lstat(
#else
if (stat(
#endif
file->path, &file->_s) == -1)
{
return -1;
}
#endif
_tinydir_get_ext(file);
file->is_dir =
#ifdef _MSC_VER
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY);
#else
S_ISDIR(file->_s.st_mode);
#endif
file->is_reg =
#ifdef _MSC_VER
!!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NORMAL) ||
(
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DEVICE) &&
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) &&
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_ENCRYPTED) &&
#ifdef FILE_ATTRIBUTE_INTEGRITY_STREAM
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_INTEGRITY_STREAM) &&
#endif
#ifdef FILE_ATTRIBUTE_NO_SCRUB_DATA
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_NO_SCRUB_DATA) &&
#endif
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_OFFLINE) &&
!(dir->_f.dwFileAttributes & FILE_ATTRIBUTE_TEMPORARY));
#else
S_ISREG(file->_s.st_mode);
#endif
return 0;
}
_TINYDIR_FUNC
int tinydir_readfile_n(const tinydir_dir *dir, tinydir_file *file, size_t i)
{
if (dir == NULL || file == NULL)
{
errno = EINVAL;
return -1;
}
if (i >= dir->n_files)
{
errno = ENOENT;
return -1;
}
memcpy(file, &dir->_files[i], sizeof(tinydir_file));
_tinydir_get_ext(file);
return 0;
}
_TINYDIR_FUNC
int tinydir_open_subdir_n(tinydir_dir *dir, size_t i)
{
_tinydir_char_t path[_TINYDIR_PATH_MAX];
if (dir == NULL)
{
errno = EINVAL;
return -1;
}
if (i >= dir->n_files || !dir->_files[i].is_dir)
{
errno = ENOENT;
return -1;
}
_tinydir_strcpy(path, dir->_files[i].path);
tinydir_close(dir);
if (tinydir_open_sorted(dir, path) == -1)
{
return -1;
}
return 0;
}
/* Open a single file given its path */
_TINYDIR_FUNC
int tinydir_file_open(tinydir_file *file, const _tinydir_char_t *path)
{
tinydir_dir dir;
int result = 0;
int found = 0;
_tinydir_char_t dir_name_buf[_TINYDIR_PATH_MAX];
_tinydir_char_t file_name_buf[_TINYDIR_FILENAME_MAX];
_tinydir_char_t *dir_name;
_tinydir_char_t *base_name;
#if (defined _MSC_VER || defined __MINGW32__)
_tinydir_char_t drive_buf[_TINYDIR_PATH_MAX];
_tinydir_char_t ext_buf[_TINYDIR_FILENAME_MAX];
#endif
if (file == NULL || path == NULL || _tinydir_strlen(path) == 0)
{
errno = EINVAL;
return -1;
}
if (_tinydir_strlen(path) + _TINYDIR_PATH_EXTRA >= _TINYDIR_PATH_MAX)
{
errno = ENAMETOOLONG;
return -1;
}
/* Get the parent path */
#if (defined _MSC_VER || defined __MINGW32__)
#if ((defined _MSC_VER) && (_MSC_VER >= 1400))
errno = _tsplitpath_s(
path,
drive_buf, _TINYDIR_DRIVE_MAX,
dir_name_buf, _TINYDIR_FILENAME_MAX,
file_name_buf, _TINYDIR_FILENAME_MAX,
ext_buf, _TINYDIR_FILENAME_MAX);
#else
_tsplitpath(
path,
drive_buf,
dir_name_buf,
file_name_buf,
ext_buf);
#endif
if (errno)
{
return -1;
}
/* _splitpath_s not work fine with only filename and widechar support */
#ifdef _UNICODE
if (drive_buf[0] == L'\xFEFE')
drive_buf[0] = '\0';
if (dir_name_buf[0] == L'\xFEFE')
dir_name_buf[0] = '\0';
#endif
/* Emulate the behavior of dirname by returning "." for dir name if it's
empty */
if (drive_buf[0] == '\0' && dir_name_buf[0] == '\0')
{
_tinydir_strcpy(dir_name_buf, TINYDIR_STRING("."));
}
/* Concatenate the drive letter and dir name to form full dir name */
_tinydir_strcat(drive_buf, dir_name_buf);
dir_name = drive_buf;
/* Concatenate the file name and extension to form base name */
_tinydir_strcat(file_name_buf, ext_buf);
base_name = file_name_buf;
#else
_tinydir_strcpy(dir_name_buf, path);
dir_name = dirname(dir_name_buf);
_tinydir_strcpy(file_name_buf, path);
base_name = basename(file_name_buf);
#endif
/* Special case: if the path is a root dir, open the parent dir as the file */
#if (defined _MSC_VER || defined __MINGW32__)
if (_tinydir_strlen(base_name) == 0)
#else
if ((_tinydir_strcmp(base_name, TINYDIR_STRING("/"))) == 0)
#endif
{
memset(file, 0, sizeof * file);
file->is_dir = 1;
file->is_reg = 0;
_tinydir_strcpy(file->path, dir_name);
file->extension = file->path + _tinydir_strlen(file->path);
return 0;
}
/* Open the parent directory */
if (tinydir_open(&dir, dir_name) == -1)
{
return -1;
}
/* Read through the parent directory and look for the file */
while (dir.has_next)
{
if (tinydir_readfile(&dir, file) == -1)
{
result = -1;
goto bail;
}
if (_tinydir_strcmp(file->name, base_name) == 0)
{
/* File found */
found = 1;
break;
}
tinydir_next(&dir);
}
if (!found)
{
result = -1;
errno = ENOENT;
}
bail:
tinydir_close(&dir);
return result;
}
_TINYDIR_FUNC
void _tinydir_get_ext(tinydir_file *file)
{
_tinydir_char_t *period = _tinydir_strrchr(file->name, TINYDIR_STRING('.'));
if (period == NULL)
{
file->extension = &(file->name[_tinydir_strlen(file->name)]);
}
else
{
file->extension = period + 1;
}
}
_TINYDIR_FUNC
int _tinydir_file_cmp(const void *a, const void *b)
{
const tinydir_file *fa = (const tinydir_file *)a;
const tinydir_file *fb = (const tinydir_file *)b;
if (fa->is_dir != fb->is_dir)
{
return -(fa->is_dir - fb->is_dir);
}
return _tinydir_strncmp(fa->name, fb->name, _TINYDIR_FILENAME_MAX);
}
#ifndef _MSC_VER
#ifndef _TINYDIR_USE_READDIR
/*
The following authored by Ben Hutchings <ben@decadent.org.uk>
from https://womble.decadent.org.uk/readdir_r-advisory.html
*/
/* Calculate the required buffer size (in bytes) for directory *
* entries read from the given directory handle. Return -1 if this *
* this cannot be done. *
* *
* This code does not trust values of NAME_MAX that are less than *
* 255, since some systems (including at least HP-UX) incorrectly *
* define it to be a smaller value. */
_TINYDIR_FUNC
size_t _tinydir_dirent_buf_size(_TINYDIR_DIR *dirp)
{
long name_max;
size_t name_end;
/* parameter may be unused */
(void)dirp;
#if defined _TINYDIR_USE_FPATHCONF
name_max = fpathconf(dirfd(dirp), _PC_NAME_MAX);
if (name_max == -1)
#if defined(NAME_MAX)
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
#else
return (size_t)(-1);
#endif
#elif defined(NAME_MAX)
name_max = (NAME_MAX > 255) ? NAME_MAX : 255;
#else
#error "buffer size for readdir_r cannot be determined"
#endif
name_end = (size_t)offsetof(struct _tinydir_dirent, d_name) + name_max + 1;
return (name_end > sizeof(struct _tinydir_dirent) ?
name_end : sizeof(struct _tinydir_dirent));
}
#endif
#endif
#ifdef __cplusplus
}
#endif
# if defined (_MSC_VER)
# pragma warning(pop)
# endif
#endif

54
core/reference.cpp Normal file
View File

@ -0,0 +1,54 @@
#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() :
Object() {
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

118
core/signal.cpp Normal file
View File

@ -0,0 +1,118 @@
#include "signal.h"
void Signal::connect_static(void (*func)(Signal *)) {
StaticSignalEntry *se = new StaticSignalEntry();
se->func = func;
entries.push_back(se);
}
void Signal::disconnect_static(void (*func)(Signal *)) {
for (int i = 0; i < entries.size(); ++i) {
SignalEntry *e = entries[i];
if (e->type == SIGNAL_ENTRY_TYPE_STATIC) {
StaticSignalEntry *se = static_cast<StaticSignalEntry *>(e);
if (se->func == func) {
entries.remove_keep_order(i);
return;
}
}
}
}
bool Signal::is_connected_static(void (*func)(Signal *)) {
for (int i = 0; i < entries.size(); ++i) {
SignalEntry *e = entries[i];
if (e->type == SIGNAL_ENTRY_TYPE_STATIC) {
StaticSignalEntry *se = static_cast<StaticSignalEntry *>(e);
if (se->func == func) {
return true;
}
}
}
return false;
}
void Signal::emit(Object *p_emitter) {
emitter = p_emitter;
for (int i = 0; i < entries.size(); ++i) {
entries[i]->call(this);
}
}
void Signal::emit(Object *p_emitter, const Variant &p1) {
emitter = p_emitter;
params.push_back(p1);
for (int i = 0; i < entries.size(); ++i) {
entries[i]->call(this);
}
params.clear();
}
void Signal::emit(Object *p_emitter, const Variant &p1, const Variant &p2) {
emitter = p_emitter;
params.push_back(p1);
params.push_back(p2);
for (int i = 0; i < entries.size(); ++i) {
entries[i]->call(this);
}
params.clear();
}
void Signal::emit(Object *p_emitter, const Variant &p1, const Variant &p2, const Variant &p3) {
emitter = p_emitter;
params.push_back(p1);
params.push_back(p2);
params.push_back(p3);
for (int i = 0; i < entries.size(); ++i) {
entries[i]->call(this);
}
params.clear();
}
void Signal::emit(Object *p_emitter, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4) {
emitter = p_emitter;
params.push_back(p1);
params.push_back(p2);
params.push_back(p3);
params.push_back(p4);
for (int i = 0; i < entries.size(); ++i) {
entries[i]->call(this);
}
params.clear();
}
void Signal::emit(Object *p_emitter, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5) {
emitter = p_emitter;
params.push_back(p1);
params.push_back(p2);
params.push_back(p3);
params.push_back(p4);
params.push_back(p5);
for (int i = 0; i < entries.size(); ++i) {
entries[i]->call(this);
}
params.clear();
}
Signal::Signal() {
}
Signal::~Signal() {
}

172
core/signal.h Normal file
View File

@ -0,0 +1,172 @@
#ifndef SIGNAL_H
#define SIGNAL_H
#include "core/containers/vector.h"
#include "core/string.h"
#include "core/variant.h"
#include "reference.h"
class Signal {
public:
Object *emitter;
Vector<Variant> params;
Vector<Variant> static_data;
template <class T>
void connect(T *obj, void (*func)(T*, Signal *));
template <class T>
void disconnect(T *obj, void (*func)(T*, Signal *));
template <class T>
bool is_connected(T *obj, void (*func)(T*, Signal *));
void connect_static(void (*func)(Signal *));
void disconnect_static(void (*func)(Signal *));
bool is_connected_static(void (*func)(Signal *));
void emit(Object *p_emitter);
void emit(Object *p_emitter, const Variant &p1);
void emit(Object *p_emitter, const Variant &p1, const Variant &p2);
void emit(Object *p_emitter, const Variant &p1, const Variant &p2, const Variant &p3);
void emit(Object *p_emitter, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4);
void emit(Object *p_emitter, const Variant &p1, const Variant &p2, const Variant &p3, const Variant &p4, const Variant &p5);
Signal();
~Signal();
protected:
enum SignalEntryType {
SIGNAL_ENTRY_TYPE_NONE = 0,
SIGNAL_ENTRY_TYPE_STATIC = 1,
SIGNAL_ENTRY_TYPE_CLASS = 2,
};
struct SignalEntry {
SignalEntryType type;
virtual void call(Signal *s) {
}
SignalEntry() {
type = SIGNAL_ENTRY_TYPE_NONE;
}
};
struct StaticSignalEntry : public SignalEntry {
void (*func)(Signal *);
virtual void call(Signal *s) {
func(s);
}
StaticSignalEntry() {
type = SIGNAL_ENTRY_TYPE_STATIC;
func = nullptr;
}
};
struct ClassSignalEntry : public SignalEntry {
virtual void* get_obj_ptr() {
return nullptr;
}
virtual void* get_func_ptr() {
return nullptr;
}
ClassSignalEntry() {
type = SIGNAL_ENTRY_TYPE_CLASS;
}
};
template<typename T>
struct ClassSignalEntrySpec : public ClassSignalEntry {
union {
T* obj;
void* obj_ptr;
};
union {
void (*func)(T*, Signal *);
void* func_ptr;
};
virtual void call(Signal *s) {
func(obj, s);
}
void* get_obj_ptr() {
return obj_ptr;
}
void* get_func_ptr() {
return func_ptr;
}
ClassSignalEntrySpec() {
obj = nullptr;
func = nullptr;
}
};
protected:
Vector<SignalEntry *> entries;
};
template <typename T>
void Signal::connect(T *obj, void (*func)(T*, Signal *)) {
ClassSignalEntrySpec<T> *ce = new ClassSignalEntrySpec<T>();
ce->obj = obj;
ce->func = func;
entries.push_back(ce);
}
template <typename T>
void Signal::disconnect(T *obj, void (*func)(T*, Signal *)) {
ClassSignalEntrySpec<T> t;
t.obj = obj;
t.func = func;
void* obj_ptr = t.obj_ptr;
void* func_ptr = t.func_ptr;
for (int i = 0; i < entries.size(); ++i) {
SignalEntry *e = entries[i];
if (e->type == SIGNAL_ENTRY_TYPE_CLASS) {
ClassSignalEntry *se = static_cast<ClassSignalEntry *>(e);
if (se->get_obj_ptr() == obj_ptr && se->get_func_ptr() == func_ptr) {
entries.remove_keep_order(i);
return;
}
}
}
}
template <typename T>
bool Signal::is_connected(T *obj, void (*func)(T*, Signal *)) {
ClassSignalEntrySpec<T> t;
t.obj = obj;
t.func = func;
void* obj_ptr = t.obj_ptr;
void* func_ptr = t.func_ptr;
for (int i = 0; i < entries.size(); ++i) {
SignalEntry *e = entries[i];
if (e->type == SIGNAL_ENTRY_TYPE_CLASS) {
ClassSignalEntry *se = static_cast<ClassSignalEntry *>(e);
if (se->get_obj_ptr() == obj_ptr && se->get_func_ptr() == func_ptr) {
return true;
}
}
}
return false;
}
#endif

2528
core/string.cpp Normal file

File diff suppressed because it is too large Load Diff

280
core/string.h Normal file
View File

@ -0,0 +1,280 @@
#ifndef STRING_H
#define STRING_H
#include <inttypes.h>
#include <string>
#include "core/containers/vector.h"
#ifndef DEFAULT_DIRECTORY_SEPARATOR
#define DEFAULT_DIRECTORY_SEPARATOR '/'
#endif
class Variant;
// TODO move to wchar_t!
class String {
public:
void push_back(const char element);
void push_back(const wchar_t element);
void pop_back();
void remove(const int index);
void erase(const char element);
void erase(const int start_index, const int length);
void clear();
bool empty() const;
char get(const int index);
const char get(const int index) const;
void set(const int index, const char value);
int size() const;
int capacity() const;
void ensure_capacity(const int capacity);
void resize(const int s);
int find(const char val, const int from = 0) const;
int find(const String &val, const int from = 0) const;
int find_reversed(const char val, const int from = -1) const;
int find_reversed(const String &val, const int from = -1) const;
void get_substr(char *into_buf, const int start_index, const int len);
void get_substr_nt(char *into_buf, const int start_index, const int len);
String substr(const int start_index, const int len) const;
String substr_index(const int start_index, const int end_index) const; //end_index is not included
bool contains(const char val) const;
bool contains(const String &val) const;
bool is_word_at(const int index, const char *str) const;
bool is_word_at(const int index, const String &val) const;
void replace_from(const int start_index, const int length, const String &with);
void replace(const String &find_str, const String &with);
void replace(const String &find_str, const String &with, const int count);
int compare(const String &other) const;
int first_difference_index(const String &other) const;
void to_lower();
String as_lower() const;
void trim();
void trim_beginning();
void trim_end();
bool ends_with(const char c) const;
bool ends_with(const String &str) const;
bool starts_with(const char c) const;
bool starts_with(const String &str) const;
int get_slice_count(const char splitter) const;
int get_slice_count(const String &splitter) const;
String get_slice(const char splitter, int index);
String get_slice(const String &splitter, int index);
Vector<String> split(const char splitter) const;
Vector<String> split(const String &splitter) const;
uint8_t read_uint8_bytes_at(int &index, bool advance_index = true);
uint16_t read_uint16_bytes_at(int &index, bool advance_index = true);
uint32_t read_uint32_bytes_at(int &index, bool advance_index = true);
uint64_t read_uint64_bytes_at(int &index, bool advance_index = true);
int8_t read_int8_bytes_at(int &index, bool advance_index = true);
int16_t read_int16_bytes_at(int &index, bool advance_index = true);
int32_t read_int32_bytes_at(int &index, bool advance_index = true);
int64_t read_int64_bytes_at(int &index, bool advance_index = true);
void append_uint8_bytes(const uint8_t val);
void append_uint16_bytes(const uint16_t val);
void append_uint32_bytes(const uint32_t val);
void append_uint64_bytes(const uint64_t val);
void append_int8_bytes(const int8_t val);
void append_int16_bytes(const int16_t val);
void append_int32_bytes(const int32_t val);
void append_int64_bytes(const int64_t val);
float read_float_bytes_at(int &index, bool advance_index = true);
void append_float_bytes(const float val);
double read_double_bytes_at(int &index, bool advance_index = true);
void append_double_bytes(const double val);
void append_str(const char *str);
void append_str(const wchar_t *str);
void append_str(const String &other);
void append_str(const std::string &str);
void append_str(const String &other, const int from);
void append_str(const std::string &str, const int from);
void append_repeat(const char *str, const int times);
void append_repeat(const String &other, const int times);
void append_path(const char *path);
void append_path(const String &path);
void path_clean_end_slash();
void path_ensure_end_slash();
String path_get_basename() const;
String path_get_last_segment() const;
String path_get_prev_dir() const;
String file_get_extension() const;
void to_html_special_chars();
void from_html_special_chars();
void newline_to_br();
bool to_bool() const;
float to_float() const;
double to_double() const;
int to_int() const;
bool is_bool() const;
bool is_numeric() const;
bool is_int() const;
bool is_uint() const;
bool is_zero() const;
uint32_t to_uint() const;
std::string to_string() const;
void print() const;
// Generic set of append helpers
void append(const char *str);
void append(const wchar_t *str);
void append(const String &other);
void append(const std::string &str);
void append(const char chr);
void append(const wchar_t chr);
void append(const int num);
void append(const unsigned int num);
void append(const float num);
void append(const double num);
void append(const Variant &variant);
static String bool_num(bool val);
static String bool_str(bool val);
// Taken from the Godot Engine (MIT License)
// Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.
// Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).
static String num(double p_num, int p_decimals = -1);
static String num_scientific(double p_num);
static String num_real(double p_num, bool p_trailing = true);
static String num_int64(int64_t p_num, int base = 10, bool capitalize_hex = false);
static String num_uint64(uint64_t p_num, int base = 10, bool capitalize_hex = false);
static String chr(char32_t p_char);
// Taken from the Godot Engine (MIT License)
// Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.
// Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).
String ascii(bool p_allow_extended = false) const;
String utf8() const;
bool parse_utf8(const char *p_utf8, int p_len = -1); // return true on error
static String utf8(const char *p_utf8, int p_len = -1);
// Taken from the Godot Engine (MIT License)
// Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.
// Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).
static uint32_t hash(const wchar_t *p_cstr, int p_len); /* hash the string */
static uint32_t hash(const wchar_t *p_cstr); /* hash the string */
static uint32_t hash(const char *p_cstr, int p_len); /* hash the string */
static uint32_t hash(const char *p_cstr); /* hash the string */
uint32_t hash() const; /* hash the string */
uint64_t hash64() const; /* hash the string */
char *c_str();
const char *c_str() const;
char *dataw();
const char *data() const;
const char operator[](const int index) const;
char &operator[](const int index);
String &operator+=(const String &b);
String &operator+=(const char chr);
String &operator+=(const char *p_c_str);
String &operator+=(const std::string &b);
friend String operator+(String lhs, const String &rhs);
friend String operator+(String lhs, const char *rhs);
friend String operator+(String lhs, const char rhs);
friend String operator+(String lhs, const std::string &rhs);
friend bool operator==(const String &a, const String &b);
friend bool operator!=(const String &a, const String &b);
friend bool operator==(const String &a, const char *b);
friend bool operator!=(const String &a, const char *b);
friend bool operator==(const char *b, const String &a);
friend bool operator!=(const char *b, const String &a);
friend bool operator==(const String &a, const wchar_t *b);
friend bool operator!=(const String &a, const wchar_t *b);
friend bool operator==(const wchar_t *b, const String &a);
friend bool operator!=(const wchar_t *b, const String &a);
friend bool operator==(const String &a, std::string &b);
friend bool operator!=(const String &a, std::string &b);
friend bool operator==(std::string &b, const String &a);
friend bool operator!=(std::string &b, const String &a);
friend bool operator<(const String &a, const String &b);
friend bool operator>(const String &a, const String &b);
friend bool operator<=(const String &a, const String &b);
friend bool operator>=(const String &a, const String &b);
operator std::string() { return to_string(); }
operator std::string() const { return to_string(); }
String &operator=(const String &other);
String &operator=(const std::string &other);
String &operator=(const char *other);
String &operator=(const wchar_t *other);
String();
String(const String &other);
String(const String &other, const int grow_by);
String(const char *p_c_str);
String(const char *p_c_str, const int grow_by);
String(const wchar_t *p_c_str);
String(const int prealloc);
String(const int prealloc, const int grow_by);
String(const std::string &str);
~String();
private:
char *_data;
int _actual_size;
int _size;
int _grow_by;
};
// Taken from the Godot Engine (MIT License)
// Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur.
// Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md).
template <typename L, typename R>
bool is_str_less(const L *l_ptr, const R *r_ptr) {
while (true) {
if (*l_ptr == 0 && *r_ptr == 0) {
return false;
} else if (*l_ptr == 0) {
return true;
} else if (*r_ptr == 0) {
return false;
} else if (*l_ptr < *r_ptr) {
return true;
} else if (*l_ptr > *r_ptr) {
return false;
}
l_ptr++;
r_ptr++;
}
}
#endif

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

624
core/variant.cpp Normal file
View File

@ -0,0 +1,624 @@
#include "variant.h"
#include "core/math/math.h"
#include "core/reference.h"
Variant::Type Variant::get_type() const {
return _type;
}
void Variant::clear() {
switch (_type) {
case TYPE_NULL:
break;
case TYPE_BOOL:
_bool = false;
break;
case TYPE_INT:
_int = 0;
break;
case TYPE_UINT:
_uint = 0;
break;
case TYPE_FLOAT:
_float = 0;
break;
case TYPE_STRING:
if (_string->owner) {
delete _string->string;
}
delete _string;
_string = nullptr;
break;
case TYPE_OBJECT:
delete _object;
_object = nullptr;
break;
case TYPE_POINTER:
_pointer = nullptr;
break;
default:
break;
}
_type = TYPE_NULL;
}
void Variant::zero() {
switch (_type) {
case TYPE_NULL:
break;
case TYPE_BOOL:
_bool = false;
break;
case TYPE_INT:
_int = 0;
break;
case TYPE_UINT:
_uint = 0;
break;
case TYPE_FLOAT:
_float = 0;
break;
case TYPE_STRING:
_string->string->resize(0);
break;
case TYPE_OBJECT:
_object->object = nullptr;
_object->reference.unref();
break;
case TYPE_POINTER:
_pointer = nullptr;
break;
default:
break;
}
}
void Variant::parse(const String &str) {
if (str.is_int()) {
set_int(str.to_int());
return;
}
if (str.is_uint()) {
set_uint(str.to_uint());
return;
}
if (str.is_numeric()) {
set_float(str.to_float());
return;
}
if (str.is_bool()) {
set_bool(str.to_bool());
return;
}
set_string(str);
}
Variant Variant::parse_string(const String &str) {
Variant v = Variant();
v.parse(str);
return v;
}
bool Variant::is_null() const {
return _type == TYPE_NULL;
}
bool Variant::is_bool() const {
return _type == TYPE_BOOL;
}
bool Variant::is_int() const {
return _type == TYPE_INT;
}
bool Variant::is_uint() const {
return _type == TYPE_UINT;
}
bool Variant::is_float() const {
return _type == TYPE_FLOAT;
}
bool Variant::is_numeric() const {
return _type == TYPE_INT || _type == TYPE_UINT || _type == TYPE_FLOAT;
}
bool Variant::is_string() const {
return _type == TYPE_STRING;
}
bool Variant::is_object() const {
return _type == TYPE_OBJECT;
}
bool Variant::is_pointer() const {
return _type == TYPE_POINTER;
}
bool Variant::is_reference() const {
if (_type == TYPE_OBJECT) {
return _object->reference.is_valid();
}
return false;
}
bool Variant::is_primitive_type() const {
return _type == TYPE_BOOL || _type == TYPE_INT || _type == TYPE_UINT || _type == TYPE_FLOAT;
}
bool Variant::is_simple_type() const {
return _type == TYPE_BOOL || _type == TYPE_INT || _type == TYPE_UINT || _type == TYPE_FLOAT || _type == TYPE_STRING;
}
bool Variant::to_bool() const {
return _bool;
}
int Variant::to_int() const {
switch (_type) {
case TYPE_NULL:
return 0;
case TYPE_BOOL:
if (_bool) {
return 1;
} else {
return 0;
}
case TYPE_INT:
case TYPE_UINT:
return _int;
case TYPE_FLOAT:
return static_cast<float>(_int);
case TYPE_STRING:
return _string->string->to_int();
case TYPE_OBJECT:
case TYPE_POINTER:
// just read the value of the pointer as int
// Could return 1 or 0, but this is almost the same, but hopefully it's more useful
return _int;
default:
return 0;
}
}
uint64_t Variant::to_uint() const {
switch (_type) {
case TYPE_NULL:
return 0;
case TYPE_BOOL:
if (_bool) {
return 1;
} else {
return 0;
}
case TYPE_INT:
case TYPE_UINT:
return _uint;
case TYPE_FLOAT:
return static_cast<uint64_t>(_float);
case TYPE_STRING:
return _string->string->to_uint();
case TYPE_OBJECT:
case TYPE_POINTER:
// just read the value of the pointer as uint
// Could return 1 or 0, but this is almost the same, but hopefully it's more useful
return _uint;
default:
return 0;
}
}
float Variant::to_float() const {
switch (_type) {
case TYPE_NULL:
return 0;
case TYPE_BOOL:
if (_bool) {
return 0;
} else {
return 1;
}
case TYPE_INT:
return static_cast<float>(_int);
case TYPE_UINT:
return static_cast<float>(_uint);
case TYPE_FLOAT:
return _float;
case TYPE_STRING:
return _string->string->to_float();
case TYPE_OBJECT:
case TYPE_POINTER:
if (_uint) {
return 1;
} else {
return 0;
}
default:
return 0;
}
}
String Variant::to_string() const {
switch (_type) {
case TYPE_NULL:
return "NULL";
case TYPE_BOOL:
if (Math::is_zero_approx(_float)) {
return "false";
} else {
return "true";
}
case TYPE_INT:
return String::num(_int);
case TYPE_UINT:
return String::num(_uint);
case TYPE_FLOAT:
return String::num(_float);
case TYPE_STRING:
return *(_string->string);
case TYPE_OBJECT:
case TYPE_POINTER:
if (_uint) {
return "[ Object ]";
} else {
return "[ Object (NULL) ]";
}
default:
return "";
}
}
Object *Variant::to_object() const {
switch (_type) {
case TYPE_NULL:
return nullptr;
case TYPE_BOOL:
return nullptr;
case TYPE_INT:
return nullptr;
case TYPE_UINT:
return nullptr;
case TYPE_FLOAT:
return nullptr;
case TYPE_STRING:
return nullptr;
case TYPE_OBJECT:
return _object->object;
case TYPE_POINTER:
return nullptr;
default:
return nullptr;
}
}
Reference *Variant::to_reference() const {
switch (_type) {
case TYPE_NULL:
return nullptr;
case TYPE_BOOL:
return nullptr;
case TYPE_INT:
return nullptr;
case TYPE_UINT:
return nullptr;
case TYPE_FLOAT:
return nullptr;
case TYPE_STRING:
return nullptr;
case TYPE_OBJECT:
return Object::cast_to<Reference>(_object->object);
case TYPE_POINTER:
return nullptr;
default:
return nullptr;
}
}
void *Variant::to_pointer() const {
switch (_type) {
case TYPE_NULL:
return nullptr;
case TYPE_BOOL:
return nullptr;
case TYPE_INT:
return nullptr;
case TYPE_UINT:
return nullptr;
case TYPE_FLOAT:
return nullptr;
case TYPE_STRING:
return nullptr;
case TYPE_OBJECT:
return nullptr;
case TYPE_POINTER:
return _pointer;
default:
return nullptr;
}
}
String *Variant::get_string_ptr() const {
if (_type == TYPE_STRING) {
return _string->string;
}
return nullptr;
}
bool Variant::is_string_owned() const {
if (_type == TYPE_STRING) {
return _string->owner;
}
return false;
}
void Variant::set_null() {
clear();
_type = TYPE_NULL;
}
void Variant::set_bool(const bool value) {
clear();
_type = TYPE_BOOL;
_bool = value;
}
void Variant::set_int(const int value) {
clear();
_type = TYPE_INT;
_int = value;
}
void Variant::set_uint(const uint64_t value) {
clear();
_type = TYPE_UINT;
_uint = value;
}
void Variant::set_float(const float value) {
clear();
_type = TYPE_FLOAT;
_float = value;
}
void Variant::set_float(const double value) {
clear();
_type = TYPE_FLOAT;
_float = value;
}
void Variant::set_string(String *value, const bool copy) {
clear();
if (!value) {
return;
}
_type = TYPE_STRING;
_string = new StringData();
if (copy) {
_string->string = new String(*value);
_string->owner = true;
} else {
_string->string = value;
_string->owner = false;
}
}
void Variant::set_string(const String &value, const bool copy) {
clear();
_type = TYPE_STRING;
_string = new StringData();
if (copy) {
_string->string = new String(value);
_string->owner = true;
} else {
_string->string = &const_cast<String &>(value);
_string->owner = false;
}
}
void Variant::set_object(Object *value) {
clear();
if (!value) {
return;
}
_object = new ObjectData();
_object->object = value;
if (value->is_class_ptr(Reference::get_class_ptr_static())) {
_object->reference = Ref<Reference>(Object::cast_to<Reference>(value));
}
}
void Variant::set_pointer(void *value) {
clear();
_type = TYPE_POINTER;
_pointer = value;
}
void Variant::set_variant(const Variant &value) {
clear();
switch (value._type) {
case TYPE_NULL:
break;
case TYPE_BOOL:
_bool = value._bool;
break;
case TYPE_INT:
_int = value._int;
break;
case TYPE_UINT:
_uint = value._uint;
break;
case TYPE_FLOAT:
_float = value._float;
break;
case TYPE_STRING:
set_string(value._string->string, true);
break;
case TYPE_OBJECT:
set_object(value._object->object);
break;
case TYPE_POINTER:
_pointer = value._pointer;
default:
break;
}
_type = value._type;
}
Variant::operator bool() const {
return to_bool();
}
Variant::operator int() const {
return to_int();
}
Variant::operator uint64_t() const {
return to_uint();
}
Variant::operator float() const {
return to_float();
}
Variant::operator double() const {
return to_float();
}
Variant::operator String() const {
return to_string();
}
Variant::operator Object *() const {
return to_object();
}
Variant::operator Reference *() const {
return to_reference();
}
Variant::operator void *() const {
return to_pointer();
}
void Variant::operator=(const Variant &other) {
set_variant(other);
}
bool Variant::operator==(const Variant &other) const {
if (_type != other._type) {
return false;
}
switch (_type) {
case TYPE_NULL:
return true;
case TYPE_BOOL:
return _bool == other._bool;
case TYPE_INT:
return _int == other._int;
case TYPE_UINT:
return _uint == other._uint;
case TYPE_FLOAT:
return _float == other._float;
case TYPE_STRING:
return (*_string->string) == (*other._string->string);
case TYPE_OBJECT:
return (_object->object) == (other._object->object);
case TYPE_POINTER:
return _pointer == other._pointer;
default:
break;
}
return false;
}
bool Variant::operator!=(const Variant &other) const {
return !(operator==(other));
}
bool Variant::operator<(const Variant &other) const {
switch (_type) {
case TYPE_NULL: {
if (other.is_null()) {
return false;
} else {
return true;
}
}
case TYPE_BOOL: {
return _bool < other.to_bool();
}
case TYPE_INT:
return _int < other.to_int();
return _int == other._int;
case TYPE_UINT:
return _uint < other.to_uint();
return _uint == other._uint;
case TYPE_FLOAT:
return _float < other.to_float();
return _float == other._float;
case TYPE_STRING:
return (*_string->string) < other.to_string();
case TYPE_OBJECT:
return (_object->object) < other.to_object();
case TYPE_POINTER:
return _pointer < other.to_pointer();
default:
break;
}
return false;
}
Variant::Variant(const bool value) {
_type = TYPE_BOOL;
_bool = value;
}
Variant::Variant(const int value) {
_type = TYPE_INT;
_int = value;
}
Variant::Variant(const uint64_t value) {
_type = TYPE_UINT;
_uint = value;
}
Variant::Variant(const float value) {
_type = TYPE_FLOAT;
_float = value;
}
Variant::Variant(const double value) {
_type = TYPE_FLOAT;
_float = value;
}
Variant::Variant(String *value, bool copy) {
_type = TYPE_NULL;
set_string(value, copy);
}
Variant::Variant(const String &value, bool copy) {
_type = TYPE_NULL;
set_string(value, copy);
}
Variant::Variant(Object *value) {
_type = TYPE_NULL;
set_object(value);
}
Variant::Variant(void *value) {
_type = TYPE_NULL;
set_pointer(value);
}
Variant::Variant(const Variant &value) {
_type = TYPE_NULL;
set_variant(value);
}
Variant::Variant() {
_type = TYPE_NULL;
}
Variant::~Variant() {
clear();
}

120
core/variant.h Normal file
View File

@ -0,0 +1,120 @@
#ifndef VARIANT_H
#define VARIANT_H
#include "core/object.h"
#include "core/reference.h"
#include "core/string.h"
class Variant {
public:
enum Type {
TYPE_NULL = 0,
TYPE_BOOL,
TYPE_INT,
TYPE_UINT,
TYPE_FLOAT,
TYPE_STRING,
TYPE_OBJECT,
TYPE_POINTER,
};
Type get_type() const;
void clear();
void zero();
void parse(const String &str);
static Variant parse_string(const String &str);
bool is_null() const;
bool is_bool() const;
bool is_int() const;
bool is_uint() const;
bool is_float() const;
bool is_numeric() const;
bool is_string() const;
bool is_object() const;
bool is_pointer() const;
bool is_reference() const;
bool is_primitive_type() const;
bool is_simple_type() const;
bool to_bool() const;
int to_int() const;
uint64_t to_uint() const;
float to_float() const;
String to_string() const;
Object *to_object() const;
Reference *to_reference() const;
void *to_pointer() const;
String *get_string_ptr() const;
bool is_string_owned() const;
void set_null();
void set_bool(const bool value);
void set_int(const int value);
void set_uint(const uint64_t value);
void set_float(const float value);
void set_float(const double value);
void set_string(String *value, bool copy = false);
void set_string(const String &value, bool copy = true);
void set_object(Object *value);
void set_pointer(void *value);
void set_variant(const Variant &value);
operator bool() const;
operator int() const;
operator uint64_t() const;
operator float() const;
operator double() const;
operator String() const;
operator Object *() const;
operator Reference *() const;
operator void *() const;
void operator=(const Variant &other);
bool operator==(const Variant &other) const;
bool operator!=(const Variant &other) const;
bool operator<(const Variant &other) const;
Variant(const bool value);
Variant(const int value);
Variant(const uint64_t value);
Variant(const float value);
Variant(const double value);
Variant(String *value, const bool copy = false);
Variant(const String &value, const bool copy = true);
Variant(Object *value);
Variant(void *value);
Variant(const Variant &value);
Variant();
~Variant();
private:
struct StringData {
bool owner;
String *string;
};
struct ObjectData {
Object *object;
Ref<Reference> reference;
};
union {
bool _bool;
int _int;
uint64_t _uint;
float _float;
StringData *_string;
ObjectData *_object;
void *_pointer;
};
Type _type;
};
#endif