prog.
This commit is contained in:
9
src/dawn/assert/CMakeLists.txt
Normal file
9
src/dawn/assert/CMakeLists.txt
Normal 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
|
||||
)
|
66
src/dawn/assert/assert.cpp
Normal file
66
src/dawn/assert/assert.cpp
Normal 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());
|
||||
}
|
80
src/dawn/assert/assert.hpp
Normal file
80
src/dawn/assert/assert.hpp
Normal 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());
|
||||
}
|
83
src/dawn/display/Color.cpp
Normal file
83
src/dawn/display/Color.cpp
Normal 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 {};
|
||||
}
|
90
src/dawn/display/Color.hpp
Normal file
90
src/dawn/display/Color.hpp
Normal 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
|
||||
}
|
16
src/dawn/display/font/truetype/TrueTypeShared.hpp
Normal file
16
src/dawn/display/font/truetype/TrueTypeShared.hpp
Normal 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)
|
33
src/dawn/util/UsageLock.cpp
Normal file
33
src/dawn/util/UsageLock.cpp
Normal 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();
|
||||
}
|
48
src/dawn/util/UsageLock.hpp
Normal file
48
src/dawn/util/UsageLock.hpp
Normal 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
288
src/dawn/util/Xml.cpp
Normal 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
64
src/dawn/util/Xml.hpp
Normal 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
45
src/dawn/util/array.hpp
Normal 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
15
src/dawn/util/flag.hpp
Normal 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
11
src/dawn/util/macro.hpp
Normal 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
119
src/dawn/util/mathutils.hpp
Normal 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
60
src/dawn/util/memory.cpp
Normal 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
100
src/dawn/util/memory.hpp
Normal 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();
|
204
src/dawn/util/parser/TypeParsers.hpp
Normal file
204
src/dawn/util/parser/TypeParsers.hpp
Normal 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
168
src/dawn/util/string.hpp
Normal 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;
|
||||
}
|
Reference in New Issue
Block a user