mirror of
https://github.com/Relintai/sfw.git
synced 2024-11-08 07:52:09 +01:00
Added some of the utils from rcpp_fw.
This commit is contained in:
parent
b22a755150
commit
eeb4e7dba0
19
core/SCsub
Normal file
19
core/SCsub
Normal 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
229
core/containers/queue.h
Normal 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
287
core/containers/vector.h
Normal 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
93
core/error_list.h
Normal 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
216
core/error_macros.h
Normal 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
3005
core/image/image.cpp
Normal file
File diff suppressed because it is too large
Load Diff
310
core/image/image.h
Normal file
310
core/image/image.h
Normal 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
57
core/int_types.h
Normal 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
205
core/log/logger.cpp
Normal 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
77
core/log/logger.h
Normal 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
14
core/memory.h
Normal 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
122
core/nodes/node.cpp
Normal 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
52
core/nodes/node.h
Normal 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
60
core/nodes/node_tree.cpp
Normal 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
35
core/nodes/node_tree.h
Normal 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
11
core/object.cpp
Normal file
@ -0,0 +1,11 @@
|
||||
#include "object.h"
|
||||
|
||||
#include "database/database.h"
|
||||
|
||||
Object::Object() {
|
||||
db = nullptr;
|
||||
}
|
||||
|
||||
Object::~Object() {
|
||||
|
||||
}
|
93
core/object.h
Normal file
93
core/object.h
Normal 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
240
core/os/directory.cpp
Normal 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
55
core/os/directory.h
Normal 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
26
core/os/tinydir/COPYING
Normal 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
79
core/os/tinydir/README.md
Normal 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)
|
17
core/os/tinydir/package.json
Normal file
17
core/os/tinydir/package.json
Normal 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
831
core/os/tinydir/tinydir.h
Normal 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
54
core/reference.cpp
Normal 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
201
core/reference.h
Normal 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
118
core/signal.cpp
Normal 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
172
core/signal.h
Normal 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
2528
core/string.cpp
Normal file
File diff suppressed because it is too large
Load Diff
280
core/string.h
Normal file
280
core/string.h
Normal 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
354
core/typedefs.h
Normal 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
624
core/variant.cpp
Normal 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
120
core/variant.h
Normal 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
|
Loading…
Reference in New Issue
Block a user