This commit is contained in:
2023-11-01 20:33:46 -05:00
parent 96291cbd88
commit 0590883c0d
20 changed files with 0 additions and 66 deletions

View File

@ -0,0 +1,9 @@
# Copyright (c) 2022 Dominic Masters
#
# This software is released under the MIT License.
# https://opensource.org/licenses/MIT
target_sources(${DAWN_TARGET_NAME}
PRIVATE
assert.cpp
)

View File

@ -0,0 +1,66 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#include "assert.hpp"
void assertTrue(bool_t x, const char message[]) {
if(x != true) {
std::cout << message << std::endl;
throw message;
abort();
}
assert(x == true);
}
void assertTrue(bool_t x, std::string message) {
assertTrue(x, message.c_str());
}
void assertFalse(bool_t x, const char message[]) {
assertTrue(!x, message);
}
void assertFalse(bool_t x, std::string message) {
assertFalse(x, message.c_str());
}
void assertUnreachable(const char message[]) {
assertTrue(false, message);
}
void assertUnreachable(std::string message) {
assertUnreachable(message.c_str());
}
void assertNotNull(void *pointer, const char message[]) {
assertTrue(pointer != nullptr && pointer != NULL, message);
}
void assertNotNull(void *pointer, std::string message) {
assertNotNull(pointer, message.c_str());
}
void assertNull(void *pointer, const char message[]) {
assertTrue(pointer == NULL || pointer == nullptr, message);
}
void assertNull(void *pointer, std::string message) {
assertNull(pointer, message.c_str());
}
void assertDeprecated(const char message[]) {
assertUnreachable(message);
}
void assertDeprecated(std::string message) {
assertDeprecated(message.c_str());
}

View File

@ -0,0 +1,80 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawnsharedlibs.hpp"
/**
* Assert a given value to be true.
* @param x Value to assert as true.
* @param message Message to throw against assertion failure.
*/
void assertTrue(bool_t x, const char message[]);
void assertTrue(bool_t x, std::string message);
/**
* Asserts a given statement to be false.
* @param x Value to assert as false.
* @param message Message to throw against assertion failure.
*/
void assertFalse(bool_t x, const char message[]);
void assertFalse(bool_t x, std::string message);
/**
* Asserts that a given line of code is unreachable. Essentially a forced
* assertion failure, good for "edge cases"
* @param message Message to throw against assertion failure.
*/
void assertUnreachable(const char message[]);
void assertUnreachable(std::string message);
/**
* Assert a given pointer to not point to a null pointer.
* @param pointer Pointer to assert is not a null pointer.
* @param message Message to throw against assertion failure.
*/
void assertNotNull(void *pointer, const char message[]);
void assertNotNull(void *pointer, std::string message);
/**
* Asserts a given pointer to be a nullptr.
* @param pointer Pointer to assert is nullptr.
* @param message Message to throw against assertion failure.
*/
void assertNull(void *pointer, const char message[]);
void assertNull(void *pointer, std::string message);
/**
* Asserts a function as being deprecated.
* @param message Message to throw against assertion failure.
*/
void assertDeprecated(const char message[]);
void assertDeprecated(std::string message);
/**
* Asserts that a given map has a key.
*
* @param map Map to check.
* @param key Key to try and assert exists.
* @param message Message to throw against assertion failure.
*/
template<typename K, typename V>
void assertMapHasKey(std::map<K,V> map, K key, const char message[]) {
assertTrue(map.find(key) != map.end(), message);
}
/**
* Asserts that a given map has a key.
*
* @param map Map to check.
* @param key Key to try and assert exists.
* @param message Message to throw against assertion failure.
*/
template<typename K, typename V>
void assertMapHasKey(std::map<K,V> map, K key, std::string message) {
assertMapHasKey(map, key, message.c_str());
}

View File

@ -0,0 +1,83 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "Color.hpp"
#include "util/parser/TypeParsers.hpp"
using namespace Dawn;
struct Color Color::fromString(std::string str) {
// Convert to lowercase
auto lower = stringToLowercase(str);
if(stringIncludes(lower, "cornflower")) {
return COLOR_CORNFLOWER_BLUE;
} else if(stringIncludes(lower, "magenta")) {
return COLOR_MAGENTA;
} else if(stringIncludes(lower, "white")) {
return COLOR_WHITE;
} else if(stringIncludes(lower, "black")) {
return COLOR_BLACK;
} else if(stringIncludes(lower, "red")) {
return COLOR_RED;
} else if(stringIncludes(lower, "green")) {
return COLOR_GREEN;
} else if(stringIncludes(lower, "blue")) {
return COLOR_BLUE;
} else if(stringIncludes(lower, "transparent")) {
return COLOR_TRANSPARENT;
}
// Hex code?
if(lower[0] == '#') {
// Remove the hash
lower = lower.substr(1);
// Convert to RGB
if(lower.length() == 3) {
// Convert to 6 digit hex
lower = lower[0] + lower[0] + lower[1] + lower[1] + lower[2] + lower[2];
}
// Convert to RGB
return {
(float_t)std::stoi(lower.substr(0, 2), nullptr, 16) / 255.0f,
(float_t)std::stoi(lower.substr(2, 2), nullptr, 16) / 255.0f,
(float_t)std::stoi(lower.substr(4, 2), nullptr, 16) / 255.0f,
1.0f
};
}
// Split by comma
auto splitByComma = stringSplit(str, ",");
if(splitByComma.size() == 3) {
// RGB
return {
(float_t)std::stof(splitByComma[0]),
(float_t)std::stof(splitByComma[1]),
(float_t)std::stof(splitByComma[2]),
1.0f
};
} else if(splitByComma.size() == 4) {
// RGBA
return {
(float_t)std::stof(splitByComma[0]),
(float_t)std::stof(splitByComma[1]),
(float_t)std::stof(splitByComma[2]),
(float_t)std::stof(splitByComma[3])
};
}
// TODO: Parse other kinds of colors
assertUnreachable("Failed to find a color match for " + str);
return {};
}

View File

@ -0,0 +1,90 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawnsharedlibs.hpp"
#include "util/string.hpp"
namespace Dawn {
struct ColorU8 {
uint8_t r, g, b, a;
};
#pragma pack(push, 4)
struct Color {
/**
* Returns a color from a string.
*
* @param str String to parse.
* @return Color parsed.
*/
static struct Color fromString(std::string str);
float_t r, g, b, a;
const struct Color& operator = (const struct Color &val) {
this->r = val.r;
this->g = val.g;
this->b = val.b;
this->a = val.a;
return *this;
}
struct Color operator * (const float_t &x) {
return {
r * x,
g * x,
b * x,
a * x
};
}
struct Color operator - (const struct Color &color) {
return {
r - color.r,
g - color.g,
b - color.b,
a - color.a
};
}
struct Color operator + (const struct Color &color) {
return {
r + color.r,
g + color.g,
b + color.b,
a + color.a
};
}
const bool_t operator == (const struct Color &other) {
return r == other.r && g == other.g && b == other.b && a == other.a;
}
operator struct ColorU8() const {
return {
(uint8_t)(r * 255),
(uint8_t)(g * 255),
(uint8_t)(b * 255),
(uint8_t)(a * 255)
};
}
};
#pragma pack(pop)
#define COLOR_DEF(r,g,b,a) { r, g, b, a }
#define COLOR_WHITE COLOR_DEF(1.0f, 1.0f, 1.0f, 1.0f)
#define COLOR_RED COLOR_DEF(1.0f, 0, 0, 1.0f)
#define COLOR_GREEN COLOR_DEF(0, 1.0f, 0, 1.0f)
#define COLOR_BLUE COLOR_DEF(0, 0, 1.0f, 1.0f)
#define COLOR_BLACK COLOR_DEF(0, 0, 0, 1.0f)
#define COLOR_MAGENTA COLOR_DEF(1.0f, 0, 1.0f, 1.0f)
#define COLOR_DARK_GREY COLOR_DEF(0.2f, 0.2f, 0.2f, 1.0f)
#define COLOR_LIGHT_GREY COLOR_DEF(0.8f, 0.8f, 0.8f, 1.0f)
#define COLOR_CORNFLOWER_BLUE COLOR_DEF(0.4f, 0.6f, 0.9f, 1.0f)
#define COLOR_WHITE_TRANSPARENT COLOR_DEF(1.0f, 1.0f, 1.0f, 0.0f)
#define COLOR_BLACK_TRANSPARENT COLOR_DEF(0.0f, 0.0f, 0.0f, 0.0f)
#define COLOR_TRANSPARENT COLOR_WHITE_TRANSPARENT
}

View File

@ -0,0 +1,16 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/flag.hpp"
#define TRUE_TYPE_CHAR_BEGIN 0x00
#define TRUE_TYPE_CHAR_END 0xFF
#define TRUE_TYPE_VARIANT_BOLD FLAG_DEFINE(0)
#define TRUE_TYPE_VARIANT_ITALICS FLAG_DEFINE(1)
#define TRUE_TYPE_DECORATION_STRIKETHROUGH FLAG_DEFINE(0)
#define TRUE_TYPE_DECORATION_UNDERLINE FLAG_DEFINE(1)

View File

@ -0,0 +1,33 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "util/UsageLock.hpp"
using namespace Dawn;
UsageLock::UsageLock() : UsageLock(&this->internalPool) {
}
UsageLock::UsageLock(usagelockid_t *lockPool) {
assertNotNull(lockPool, "Lock pool cannot be null");
this->pool = lockPool;
this->onEmpty = []() {};
this->onFirstLock = []() {};
}
usagelockid_t UsageLock::createLock() {
usagelockid_t lock = (*this->pool)++;
this->locks.push_back(lock);
if(this->locks.size() == 1) this->onFirstLock();
return lock;
}
void UsageLock::removeLock(usagelockid_t lock) {
auto it = std::find(this->locks.begin(), this->locks.end(), lock);
if(it == this->locks.end()) return;
this->locks.erase(it);
this->onLockRemoved(lock);
if(this->locks.size() == 0) this->onEmpty();
}

View File

@ -0,0 +1,48 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "assert/assert.hpp"
namespace Dawn {
typedef int32_t usagelockid_t;
class UsageLock {
protected:
usagelockid_t internalPool = 0;
usagelockid_t *pool = nullptr;
std::vector<usagelockid_t> locks;
public:
std::function<void()> onEmpty;
std::function<void()> onFirstLock;
std::function<void(usagelockid_t)> onLockRemoved;
/**
* Construct a new usage lock object.
*/
UsageLock();
/**
* Construct a new Usage Lock object
*
* @param lockPool Pool that will be used to create locks.
*/
UsageLock(usagelockid_t *lockPool);
/**
* Creates a new lock.
*
* @return Lock created for this specific instance.
*/
usagelockid_t createLock();
/**
* Removes a lock.
*
* @param lock Lck to remove.
*/
void removeLock(usagelockid_t lock);
};
}

288
src/dawn/util/Xml.cpp Normal file
View File

@ -0,0 +1,288 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "Xml.hpp"
using namespace Dawn;
XmlNode::XmlNode() {
this->child = nullptr;
this->value.clear();
}
bool_t Xml::isWhitespace(char_t c) {
return c == ' ' || c == '\r' || c == '\n' || c == '\t';
}
Xml Xml::load(std::string data) {
size_t j = 0;
Xml xml;
Xml::load(&xml, data, &j);
return xml;
}
void Xml::load(Xml *xml, std::string data, size_t *j) {
char_t c;
int32_t level = 0;
enum XmlParseState doing = XML_PARSE_STATE_DOING_NOTHING;
enum XmlParseState doingBeforeComment;
bool_t insideTag = false;
std::string buffer = "";
std::string attrKey = "";
size_t i = *j;
struct XmlNode childNode;
while(c = data[i++]) {
if(insideTag) {
xml->outerXml += c;
}
switch(doing) {
case XML_PARSE_STATE_DOING_NOTHING:
if(c == '>') continue;
if(c == '<') {
// Parsing comment?
if(data[i] == '!' && data[i+1] == '-' && data[i+2] == '-') {
doingBeforeComment = doing;
doing = XML_PARSE_STATE_PARSING_COMMENT;
i += 3;
} else if(data[i] == '!' && !insideTag) {
// Likely <!DOCTYPE ...>
while((c = data[i++]) != '>') {
// Nothing needs doing here right now, in future may support doctype
}
continue;
} else if(insideTag) {
if(data[i] == '/') {
doing = XML_PARSE_STATE_PARSING_CLOSE;
continue;
}
} else {
doing = XML_PARSE_STATE_PARSING_TAG_NAME;
level++;
insideTag = true;
xml->outerXml += c;
}
continue;
}
if(insideTag) xml->innerXml += c;
if(Xml::isWhitespace(c)) continue;// NEEDS TO GO?
doing = XML_PARSE_STATE_PARSING_VALUE;
buffer += c;
break;
case XML_PARSE_STATE_PARSING_TAG_NAME:
// Just keep reading until we either hit a space (end of the tag name)
// or a closing tag value, either / or >
if(Xml::isWhitespace(c) || c == '>' || c == '/') {
xml->node = buffer;
buffer = "";
if(c == '/') {
level--;
insideTag = false;
doing = XML_PARSE_STATE_PARSING_CLOSE;
} else {
doing = c == '>' ? XML_PARSE_STATE_PARSING_VALUE : XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE;
}
continue;
}
buffer += c;
break;
case XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE:
// Look until we hit either the end of a tag, or the attribute itself
if(Xml::isWhitespace(c) || c == '>' || c == '/' || c == '=') {
if(c == '>' || c == '/') {
doing = XML_PARSE_STATE_PARSING_VALUE;
if(c == '/') {
level--;
insideTag = false;
doing = XML_PARSE_STATE_PARSING_CLOSE;
}
} else if(c == '=') {
doing = XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE_VALUE;
} else {
doing = XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE;
}
if(buffer.size() > 0) {
attrKey = buffer;
xml->attributes[buffer] = "";
buffer = "";
}
continue;
}
buffer += c;
break;
case XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE_VALUE:
// Keep looking until we find a quote mark
if(Xml::isWhitespace(c)) continue;
if(c == '>' || c == '/') {
doing = XML_PARSE_STATE_DOING_NOTHING;
insideTag = false;
continue;
}
if(c != '"') continue;
doing = XML_PARSE_STATE_PARSING_ATTRIBUTE_VALUE;
break;
case XML_PARSE_STATE_PARSING_ATTRIBUTE_VALUE:
// Parse the attribute value until we find a quote mark.
if(c == '\\') {
c = data[i++];
} else if(c == '"') {
doing = XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE;
xml->attributes[attrKey] = buffer;
buffer = "";
continue;
}
buffer += c;
break;
case XML_PARSE_STATE_PARSING_VALUE:
// Keep parsing child until we find a < for an opening/closing tag.
if(c == '<' && !(data[i] == '<' || data[i-2] == '<')) {
if(buffer.size() > 0) {
childNode.nodeType = XML_NODE_TYPE_TEXT;
childNode.value = buffer;
xml->childNodes.push_back(childNode);
}
// Are we parsing the close tag, or parsing a child?
if(data[i] == '/') {
doing = XML_PARSE_STATE_PARSING_CLOSE;
xml->textContent = buffer;
buffer.clear();
continue;
} else if(data[i] == '!' && data[i+1] == '-' && data[i+2] == '-') {
doingBeforeComment = doing;
doing = XML_PARSE_STATE_PARSING_COMMENT;
i += 3;
continue;
}
// Parsing child
i -= 1;
// @deprecated
auto child = new Xml();
Xml::load(child, data, &i);
xml->children.push_back(child);
childNode = XmlNode();
childNode.nodeType = XML_NODE_TYPE_ELEMENT;
childNode.child = child;
xml->childNodes.push_back(childNode);
// Remove last char since we kinda already parsed it.
xml->innerXml += child->outerXml;
xml->outerXml = xml->outerXml.substr(0, xml->outerXml.size()-1);
xml->outerXml += child->outerXml;
buffer.clear();
continue;
}
xml->innerXml += c;
if(c == '&') {
// Handle special characters. First read ahead to nearest semicolon OR
// nearest closing tag.
std::string sc;
while(c = data[i++]) {
xml->innerXml += c;
if(c == ';') break;
if(c == '<') assertUnreachable("Error decrypting XML/HTML Special Char, encountered end of Node?");//Invalid XML
sc += c;
}
if(sc == "lt") {
buffer += '<';
} else if(sc == "gt") {
buffer += '>';
} else if(sc == "amp") {
buffer += '&';
} else if(sc == "apos") {
buffer += '\'';
} else if(sc == "quot") {
buffer += '"';
} else if(sc == "nbsp") {
buffer += ' ';
} else {
// Try parse as integer
if(sc.size() > 1 && sc[0] == '#') {
int code = std::stoi(sc.substr(1));
buffer += (char)code;
} else {
assertUnreachable("Unknown Special character: " + sc);
}
}
} else {
buffer += c;
}
break;
case XML_PARSE_STATE_PARSING_CLOSE:
// Just keep parsing until the tag closer finishes.
if(c != '>') continue;
doing = XML_PARSE_STATE_DOING_NOTHING;
//TODO: Return index or something?
*j = i;
return;
case XML_PARSE_STATE_PARSING_COMMENT:
if(c != '-') continue;
if(data[i] != '-') continue;
if(data[i+1] != '>') continue;
i += 2;
doing = doingBeforeComment;
break;
default:
break;
}
}
*j = i;
}
std::vector<Xml*> Xml::getChildrenOfType(std::string type) {
std::vector<Xml*> children;
auto itChildren = this->children.begin();
while(itChildren != this->children.end()) {
auto child = *itChildren;
if(child->node == type) children.push_back(child);
++itChildren;
}
return children;
}
Xml * Xml::getFirstChildOfType(std::string type) {
auto itChildren = this->children.begin();
while(itChildren != this->children.end()) {
auto child = *itChildren;
if(child->node == type) return child;
++itChildren;
}
return nullptr;
}
Xml::~Xml() {
auto it = this->children.begin();
while(it != this->children.end()) {
Xml *child = *it;
delete child;
++it;
}
}

64
src/dawn/util/Xml.hpp Normal file
View File

@ -0,0 +1,64 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawnsharedlibs.hpp"
#include "util/memory.hpp"
#include "assert/assert.hpp"
#include "util/array.hpp"
namespace Dawn {
enum XmlParseState {
XML_PARSE_STATE_DOING_NOTHING,
XML_PARSE_STATE_PARSING_TAG_NAME,
XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE,
XML_PARSE_STATE_PARSING_ATTRIBUTE_NAME,
XML_PARSE_STATE_LOOKING_FOR_ATTRIBUTE_VALUE,
XML_PARSE_STATE_PARSING_ATTRIBUTE_VALUE,
XML_PARSE_STATE_PARSING_VALUE,
XML_PARSE_STATE_PARSING_CLOSE,
XML_PARSE_STATE_PARSING_COMMENT
};
class Xml;
struct XmlNode;
enum XmlNodeType {
XML_NODE_TYPE_TEXT,
XML_NODE_TYPE_ELEMENT
};
class Xml {
protected:
static bool_t isWhitespace(char_t c);
// @deprecated
std::vector<Xml*> children;
public:
static Xml load(std::string data);
static void load(Xml *xml, std::string data, size_t *j);
std::string node;
std::string innerXml;
std::string outerXml;
std::string textContent;
std::map<std::string, std::string> attributes;
std::vector<struct XmlNode> childNodes;
std::vector<Xml*> getChildrenOfType(std::string type);
Xml * getFirstChildOfType(std::string type);
~Xml();
};
struct XmlNode {
enum XmlNodeType nodeType;
std::string value;
Xml *child;
XmlNode();
};
}

45
src/dawn/util/array.hpp Normal file
View File

@ -0,0 +1,45 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawnsharedlibs.hpp"
#include "assert/assert.hpp"
namespace Dawn {
/**
* Append a list on to another list.
*
* @param list Pointer to list that is being appended to.
* @param append Pointer to list that will be appended.
*/
template<typename T>
void vectorAppend(std::vector<T> *list, std::vector<T> *append) {
assertNotNull(list, "vectorAppend: list cannot be null");
assertNotNull(append, "vectorAppend: append cannot be null");
auto it = append->begin();
while(it != append->end()) {
list->push_back(*it);
++it;
}
}
/**
* Append a list on to another list.
*
* @param list Pointer to list that is being appended to.
* @param append List that will be appended.
*/
template<typename T>
void vectorAppend(std::vector<T> *list, std::vector<T> append) {
assertNotNull(list, "vectorAppend: list cannot be null");
auto it = append.begin();
while(it != append.end()) {
list->push_back(*it);
++it;
}
}
}

15
src/dawn/util/flag.hpp Normal file
View File

@ -0,0 +1,15 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "dawnsharedlibs.hpp"
typedef uint_fast8_t flag8_t;
typedef uint_fast16_t flag16_t;
typedef uint_fast32_t flag32_t;
typedef flag32_t flag_t;
#define FLAG_DEFINE(n) (1 << n)

11
src/dawn/util/macro.hpp Normal file
View File

@ -0,0 +1,11 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#define MACRO_STRINGIFY_RAW(x) #x
#define MACRO_STRINGIFY(x) MACRO_STRINGIFY_RAW(x)
#define MACRO_JOIN(x, y) x ## y

119
src/dawn/util/mathutils.hpp Normal file
View File

@ -0,0 +1,119 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawnsharedlibs.hpp"
#define MATH_PI 3.1415926535897f
namespace Dawn {
/**
* Returns the largest of the two provided int32 numbers.
*
* @param left Left number to get the largest of.
* @param right Right number to get the largest of.
* @return The larger of the two numbers
*/
template<typename T>
static T mathMax(T left, T right) {
return left < right ? right : left;
}
/**
* Returns the smallest of two provided int32 numbers.
*
* @param left Left number to get the smallest of.
* @param right Right number to get the smallest of.
* @return Smaller of the two numbers.
*/
template<typename T>
static T mathMin(T left, T right) {
return left < right ? left : right;
}
/**
* Returns the input value, constrained between the min and max values, so that
* the value cannot underceed the min, and cannot exceed the max.
*
* @param val Value to get the clamp for.
* @param min Minimum clamping value.
* @param max Maximum clamping value.
* @return The value, or the closest clamped value.
*/
template<typename T>
static T mathClamp(T val, T min, T max) {
return mathMin<T>(mathMax<T>(val, min), max);
}
/**
* Returns the absolute value (the non-negative representation of) for the given
* int32 number.Abs values will be -value if value < 0.
*
* @param value Value to get the absolute value for.
* @return The absolute value (-value if value < 0)
*/
template<typename T>
static T mathAbs(T value) {
return value < 0 ? -value : value;
}
/**
* Returns the modulous a result for b. Works for floating point numbers.
*
* @param a Number to modulo against. (a % b)
* @param b Number to modulo with. (a % b)
* @returns The modulo result.
*/
template<typename T>
static inline T mathMod(T value, T modulo) {
return ((value % modulo) + modulo) % modulo;
}
static inline float_t mathMod(float_t value, float_t modulo) {
float_t n = fmod(value, modulo);
return n;
}
/**
* Convert degrees to radians.
*
* @param n Degrees to convert.
* @returns The number in radians.
*/
static float_t mathDeg2Rad(float_t degrees) {
return degrees * (MATH_PI / 180.0f);
}
/**
* Convert radians to degrees.
* @param n Radians to convert.
* @returns The number in degrees.
*/
static float_t mathRad2Deg(float_t n) {
return (n * 180.0f) / MATH_PI;
}
/**
* Round a number to the nearest whole number.
* @param n Number to round.
* @return Rounded number.
*/
template<typename T>
static T mathRound(float_t n) {
return (T)roundf(n);
}
/**
* Rounds the number down to the nearest whole number.
* @param n Number to round down.
* @return Rounded number.
*/
template<typename T>
static T mathFloor(float_t n) {
return (T)floorf(n);
}
}

60
src/dawn/util/memory.cpp Normal file
View File

@ -0,0 +1,60 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#include "memory.hpp"
#include "assert/assert.hpp"
void * memoryAllocate(const size_t size) {
assertTrue(size >= 0, "memoryAllocate: size must be greater than 0 or equal to.");
void *x = (void *)memoryCallMalloc(size);
assertNotNull(x, "memoryAllocate: Failed to allocate memory");
return x;
}
void * memoryAllocateEmpty(const size_t count, const size_t size) {
assertTrue(count >= 0, "memoryAllocateEmpty: count must be greater than or equal to 0");
assertTrue(size >= 0, "memoryAllocateEmpty: size must be greater than or equal to 0");
void *x = (void *)memoryCallCalloc(count, size);
assertNotNull(x, "memoryAllocateEmpty: Failed to allocate memory");
return x;
}
void memoryFree(void *pointer) {
memoryCallFree(pointer);
}
void * memoryReallocate(void *ptr, size_t newSize) {
assertTrue(newSize >= 0, "memoryReallocate: newSize must be greater than or equal to 0");
return memoryCallRealloc(ptr, newSize);
}
void memoryCopy(void *source, void *destination, size_t size) {
assertNotNull(source, "memoryCopy: source must not be null");
assertNotNull(destination, "memoryCopy: destination must not be null");
assertTrue(destination != source, "memoryCopy: destination must not be source");
assertTrue(size > 0, "memoryCopy: size must be greater than 0");
memcpy(destination, source, size);
}
int32_t memoryCompare(const void *left, const void *right, const size_t size) {
assertTrue(left != right, "memoryCompare: left must not be right");
assertTrue(size > 0, "memoryCompare: size must be greater than 0");
return memcmp(left, right, size);
}
void memorySet(void *dest, uint8_t data, size_t length) {
assertNotNull(dest, "memorySet: dest must not be null");
assertTrue(length > 0, "memorySet: length must be greater than 0");
memset(dest, data, length);
}
void memoryInit() {
}
void memoryDispose() {
}

100
src/dawn/util/memory.hpp Normal file
View File

@ -0,0 +1,100 @@
/**
* Copyright (c) 2022 Dominic Masters
*
* This software is released under the MIT License.
* https://opensource.org/licenses/MIT
*/
#pragma once
#include "dawnsharedlibs.hpp"
#define DAWN_MEMORY_TRACKING 1
static void * memoryCallMalloc(const size_t size) {
return malloc(size);
}
static void * memoryCallCalloc(const size_t num, const size_t size) {
return calloc(num, size);
}
static void memoryCallFree(void *p) {
free(p);
}
static void * memoryCallRealloc(void *p, size_t newSize) {
return realloc(p, newSize);
}
/**
* Allocate some space in memory to use for your needs. Memory allocation may
* change how it functions later on to keep things nice and efficient. For now
* this is just an API forward for malloc.
*
* @param size Size of the array you wish to buffer.
* @return Pointer to the space in memory to use.
*/
void * memoryAllocate(const size_t size);
/**
* Allocate space in memory, where all values are set to 0 (in binary space).
*
* @param count Count of elements to allocate.
* @param size Size of each element to allocate.
* @return Pointer to the space in memory to use.
*/
void * memoryAllocateEmpty(const size_t count, const size_t size);
/**
* Free some previously allocated memory space.
* @param pointer Pointer in memory to free.
*/
void memoryFree(void *pointer);
/**
* Reallocate a part of memory. Reallocation simply creates a new buffer that
* will take all of the existing contents and then free's the original buffer.
*
* @param pointer Pointer to pointer in memory that you wish to re-allocate.
* @param newSize The new size of the buffer.
* @return Pointer to the new buffer.
*/
void * memoryReallocate(void *pointer, size_t newSize);
/**
* Copies data from one buffer to another. Typically used for array operations.
*
* @param source Source pointer.
* @param destination Destination buffer.
* @param size Size in bytes of data to copy.
*/
void memoryCopy(void *source, void *destination, size_t size);
/**
* Compares the data within two memory banks. Shorthand for memcpy.
*
* @param left Left item to compare.
* @param right Right item to compare.
* @param size Count of bytes to compare.
* @return 0 for equal, <0 for left being greater, >0 for right being greater.
*/
int32_t memoryCompare(const void *left, const void *right, const size_t size);
/**
* Fill destination with a repeating set of bytes.
*
* @param dest Destination pointer in memory.
* @param data Data byte to write.
* @param length How many times to write that byte.
*/
void memorySet(void *dest, uint8_t data, size_t length);
/**
* Initializes the memory management system.
*/
void memoryInit();
/**
* Disposes of the memory management system.
*/
void memoryDispose();

View File

@ -0,0 +1,204 @@
// Copyright (c) 2023 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "util/string.hpp"
namespace Dawn {
static inline std::string rawParser(std::string v, std::string *error) {
return v;
};
static inline std::string stringParser(std::string v, std::string *error) {
// Replace slashes and quotes
v = stringReplaceAll(v, "\\", "\\\\\\");
v = stringReplaceAll(v, "\"", "\\\"");
// Newlines.
v = stringReplaceAll(v, "\n", "\\n");
return "\"" + v + "\"";
};
static inline std::string floatParser(std::string v, std::string *error) {
v = stringTrim(v);
// Make sure number contains decimal
if(v.find(".") == std::string::npos) {
v += ".0";
}
// Make sure number contains a number before the decimal
if(v.find(".") == 0) {
v = "0" + v;
}
// Make sure ends with f
if(v.find("f") == std::string::npos) {
v += "f";
}
return v;
};
static inline std::string intParser(std::string v, std::string *error) {
v = stringTrim(v);
return v;
}
static inline std::string boolParser(std::string v, std::string *error) {
v = stringTrim(v);
if(v == "true") return "true";
if(v == "false") return "false";
*error = "Invalid bool value: " + v;
return std::string("");
}
static inline std::string vec2Parser(std::string v, std::string *error) {
// Split string by comma into two strings that we pass into float
auto split = stringSplit(v, ",");
if(split.size() != 2) {
*error = "Invalid vec2 value: " + v;
return std::string("");
}
return std::string(
"glm::vec2(" +
floatParser(split[0], error) + ", " +
floatParser(split[1], error) +
")"
);
};
static inline std::string vec3Parser(std::string v, std::string *error) {
// Split string by comma into two strings that we pass into float
auto split = stringSplit(v, ",");
if(split.size() != 3) {
*error = "Invalid vec3 value: " + v;
return std::string("");
}
return std::string(
"glm::vec3(" +
floatParser(split[0], error) + ", " +
floatParser(split[1], error) + ", " +
floatParser(split[2], error) +
")"
);
};
static inline std::string vec6Parser(std::string v, std::string *error) {
// Split string by comma into two strings that we pass into float
auto split = stringSplit(v, ",");
if(split.size() != 6) {
*error = "Invalid vec6 value: " + v;
return std::string("");
}
return std::string(
"glm::vec6(" +
floatParser(split[0], error) + ", " +
floatParser(split[1], error) + ", " +
floatParser(split[2], error) + ", " +
floatParser(split[3], error) + ", " +
floatParser(split[4], error) + ", " +
floatParser(split[5], error) +
")"
);
};
static inline std::string vec4Parser(std::string v, std::string *error) {
// Split string by comma into two strings that we pass into float
auto split = stringSplit(v, ",");
if(split.size() != 4) {
*error = "Invalid vec4 value: " + v + " (incorrect split len " + std::to_string(split.size()) + ")";
return std::string("");
}
return std::string(
"glm::vec4(" +
floatParser(split[0], error) + ", " +
floatParser(split[1], error) + ", " +
floatParser(split[2], error) + ", " +
floatParser(split[3], error) +
")"
);
};
static inline std::string colorParser(std::string v, std::string *error) {
return "Color::fromString(" + stringParser(v, error) + ")";
};
static inline std::string uiComponentAlignParser(std::string v, std::string *error) {
v = stringToLowercase(v);
if(v.find("left") != std::string::npos) return "UI_COMPONENT_ALIGN_START";
if(v.find("center") != std::string::npos) return "UI_COMPONENT_ALIGN_MIDDLE";
if(v.find("right") != std::string::npos) return "UI_COMPONENT_ALIGN_END";
if(v.find("top") != std::string::npos) return "UI_COMPONENT_ALIGN_START";
if(v.find("bottom") != std::string::npos) return "UI_COMPONENT_ALIGN_END";
if(v.find("stretch") != std::string::npos) return "UI_COMPONENT_ALIGN_STRETCH";
if(v.find("start") != std::string::npos) return "UI_COMPONENT_ALIGN_START";
if(v.find("middle") != std::string::npos) return "UI_COMPONENT_ALIGN_MIDDLE";
if(v.find("end") != std::string::npos) return "UI_COMPONENT_ALIGN_END";
*error = "Invalid UIComponentAlign value: " + v;
return "";
}
static inline std::string uiComponentAlignUnitParser(std::string v, std::string *error) {
v = stringToLowercase(v);
if(v.find("scale") != std::string::npos) return "UI_COMPONENT_ALIGN_UNIT_SCALE";
if(v.find("percent") != std::string::npos) return "UI_COMPONENT_ALIGN_UNIT_PERCENT";
if(v.find("ratio") != std::string::npos) return "UI_COMPONENT_ALIGN_UNIT_RATIO";
*error = "Invalid UIComponentAlignUnit value: " + v;
return "";
}
static inline std::string uiLabelTextAlignParser(std::string v, std::string *error) {
v = stringToLowercase(v);
if(v.find("left") != std::string::npos) return "UI_LABEL_TEXT_ALIGN_LEFT";
if(v.find("center") != std::string::npos) return "UI_LABEL_TEXT_ALIGN_CENTER";
if(v.find("right") != std::string::npos) return "UI_LABEL_TEXT_ALIGN_RIGHT";
*error = "Invalid UILabelTextAlign value: " + v;
return "";
}
static inline std::function<std::string(std::string, std::string*)> parserFromTypeName(std::string type) {
std::function<std::string(std::string, std::string*)> parser = rawParser;
if(type.find("string") != std::string::npos) {
parser = stringParser;
} else if(type.find("float") != std::string::npos) {
parser = floatParser;
} else if(type.find("Color") != std::string::npos) {
parser = colorParser;
} else if(type.find("vec2") != std::string::npos) {
parser = vec2Parser;
} else if(type.find("vec3") != std::string::npos) {
parser = vec3Parser;
} else if(type.find("vec4") != std::string::npos) {
parser = vec4Parser;
} else if(type == "int32_t" || type == "int" || type == "uint32_t" || type == "uint") {
parser = intParser;
} else if(type == "bool_t") {
parser = boolParser;
} else if(type == "flag_t") {
parser = rawParser;
} else if(type.starts_with("enum")) {
// Handle Enum Cases
if(type.ends_with("UIComponentAlign")) {
parser = uiComponentAlignParser;
} else if(type.ends_with("UIComponentAlignUnit")) {
parser = uiComponentAlignUnitParser;
} else if(type.ends_with("UILabelTextAlign")) {
parser = uiLabelTextAlignParser;
} else {
parser = rawParser;
}
} else if(type.find("*") == (type.size() - 1)) {
type = type.substr(0, type.size() - 1);
parser = rawParser;
} else {
throw std::string("Invalid parser type");
}
return parser;
}
}

168
src/dawn/util/string.hpp Normal file
View File

@ -0,0 +1,168 @@
// Copyright (c) 2022 Dominic Masters
//
// This software is released under the MIT License.
// https://opensource.org/licenses/MIT
#pragma once
#include "assert/assert.hpp"
/**
* Finds the next instance of a character within a string, safely (with a
* limit). The returned pointer will be NULL if not found, or a pointer to a
* point within the string where the instance is.
*
* @param haystack String to search.
* @param needle Character to search for.
* @param limit Max length you want to search for to limit yourself to.
* @return Pointer to the character found, or NULL if not found.
*/
static inline char * stringFindNext(
char *haystack,
char needle,
size_t limit
) {
char *p;
assertNotNull(haystack, "String find haystack cannot be null");
assertTrue(limit > 0, "String find limit must be greater than 0");
for(p = haystack; (size_t)(p - haystack) < limit; p++) {
if(*p == needle) return p;
assertFalse(*p == '\0', "String find limit reached");
}
return NULL;
}
/**
* Splits a string into a vector of strings, using a delimiter.
*
* @param s String to split.
* @param delim Delimiter to split by.
* @return Vector of strings.
*/
static inline std::vector<std::string> stringSplit(
const std::string &s,
const std::string delim
) {
size_t posStart = 0, posEnd, delimLength = delim.length();
std::string token;
std::vector<std::string> res;
while((posEnd = s.find(delim, posStart)) != std::string::npos) {
token = s.substr(posStart, posEnd - posStart);
posStart = posEnd + delimLength;
res.push_back (token);
}
res.push_back(s.substr(posStart));
return res;
}
/**
* Trims the whitespace from the left side of a string.
*
* @param i Input string to trim.
* @return Trimmed string.
*/
static inline std::string stringLTrim(const std::string &i) {
std::string s = i;
s.erase(s.begin(), std::find_if(s.begin(), s.end(), [](unsigned char ch) {
return !std::isspace(ch);
}));
return s;
}
/**
* Trims the whitespace from the right side of a string.
*
* @param i Input string to trim.
* @return Trimmed string.
*/
static inline std::string stringRTrim(const std::string &i) {
std::string s = i;
s.erase(std::find_if(s.rbegin(), s.rend(), [](unsigned char ch) {
return !std::isspace(ch);
}).base(), s.end());
return s;
}
/**
* Trims the whitespace from both sides of a string.
*
* @param s Input string to trim.
* @return Trimmed string.
*/
static inline std::string stringTrim(const std::string &s) {
return stringLTrim(stringRTrim(s));
}
/**
* Checks if a string contains another string.
*
* @param haystack String to scan.
* @param needle String to search for.
* @return True if the string is found, false otherwise.
*/
static inline bool_t stringIncludes(const std::string &haystack, const std::string &needle) {
return haystack.find(needle) != std::string::npos;
}
/**
* Converts an entire string to lowercase.
*
* @param str String to convert.
* @return A new string with all lowercase characters.
*/
static inline std::string stringToLowercase(const std::string &str) {
std::string data = str;
std::transform(
data.begin(),
data.end(),
data.begin(),
[](char c) {
return std::tolower(c);
}
);
return data;
}
/**
* Replace all instances of a string with another string within a string.
*
* @param str String to replace the contents of.
* @param needle Needle to look for.
* @param replace String to replace the needle with.
* @return A new string instance with the replacements made.
*/
static inline std::string stringReplaceAll(
const std::string &str,
const std::string &needle,
const std::string &replace
) {
std::string newString = str;
size_t startPos = 0;
while((startPos = newString.find(needle, startPos)) != std::string::npos) {
newString.replace(startPos, needle.length(), replace);
startPos += replace.length();
}
return newString;
}
/**
* Joins a vector of strings into a single string, using a delimiter.
*
* @param strings Vector of strings to join.
* @param delim Delimiter to join the strings with.
*/
static inline std::string stringJoin(
const std::vector<std::string> &strings,
const std::string &delim
) {
std::string result;
for(size_t i = 0; i < strings.size(); i++) {
if(i > 0) result += delim;
result += strings[i];
}
return result;
}