Base refactor
This commit is contained in:
@ -1,23 +0,0 @@
|
||||
# Copyright (c) 2023 Dominic Masters
|
||||
#
|
||||
# This software is released under the MIT License.
|
||||
# https://opensource.org/licenses/MIT
|
||||
|
||||
# Sources
|
||||
target_sources(${DAWN_TARGET_NAME}
|
||||
PRIVATE
|
||||
memory.cpp
|
||||
UsageLock.cpp
|
||||
Xml.cpp
|
||||
)
|
||||
|
||||
|
||||
# Tests
|
||||
target_sources(dawntests
|
||||
PRIVATE
|
||||
memory.cpp
|
||||
UsageLock.cpp
|
||||
Xml.cpp
|
||||
|
||||
_test_.memory.cpp
|
||||
)
|
121
src/dawn/util/Math.hpp
Normal file
121
src/dawn/util/Math.hpp
Normal file
@ -0,0 +1,121 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
|
||||
#define MATH_PI 3.1415926535897f
|
||||
|
||||
namespace Dawn {
|
||||
class Math {
|
||||
/**
|
||||
* 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 max(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);
|
||||
}
|
||||
};
|
||||
}
|
@ -1,28 +0,0 @@
|
||||
// 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() {
|
||||
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();
|
||||
}
|
@ -1,40 +0,0 @@
|
||||
// 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 pool = 0;
|
||||
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();
|
||||
|
||||
/**
|
||||
* 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);
|
||||
};
|
||||
}
|
@ -1,288 +0,0 @@
|
||||
// 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: %s", sc.c_str());
|
||||
}
|
||||
}
|
||||
} 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;
|
||||
}
|
||||
}
|
@ -1,64 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.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();
|
||||
};
|
||||
}
|
@ -1,27 +0,0 @@
|
||||
// Copyright (c) 2023 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#include <catch2/catch_test_macros.hpp>
|
||||
#include "util/memory.hpp"
|
||||
#include "assert/assert.hpp"
|
||||
|
||||
TEST_CASE("memorycallMalloc", "[memory]") {
|
||||
SECTION("memory isn't null") {
|
||||
void *p = memoryCallMalloc(10);
|
||||
REQUIRE(p != nullptr);
|
||||
REQUIRE(p != NULL);
|
||||
memoryCallFree(p);
|
||||
}
|
||||
|
||||
SECTION("memory is writeable") {
|
||||
void *p = memoryCallMalloc(10);
|
||||
for(int i = 0; i < 10; i++) {
|
||||
((char*)p)[i] = 'a';
|
||||
}
|
||||
REQUIRE(((char*)p)[0] == 'a');
|
||||
REQUIRE(((char*)p)[9] == 'a');
|
||||
memoryCallFree(p);
|
||||
}
|
||||
}
|
@ -1,21 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.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, const std::vector<T> &append) {
|
||||
list.insert(list.end(), append.begin(), append.end());
|
||||
}
|
||||
}
|
@ -1,15 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.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)
|
@ -1,11 +0,0 @@
|
||||
// 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
|
@ -1,119 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.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);
|
||||
}
|
||||
}
|
@ -1,60 +0,0 @@
|
||||
// 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() {
|
||||
|
||||
}
|
@ -1,103 +0,0 @@
|
||||
/**
|
||||
* Copyright (c) 2022 Dominic Masters
|
||||
*
|
||||
* This software is released under the MIT License.
|
||||
* https://opensource.org/licenses/MIT
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.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.
|
||||
*/
|
||||
template<typename T>
|
||||
T * memoryAllocate(const size_t size) {
|
||||
return (T*)memoryCallMalloc(size * sizeof(T));
|
||||
}
|
||||
|
||||
/**
|
||||
* 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();
|
@ -1,204 +0,0 @@
|
||||
// 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;
|
||||
}
|
||||
}
|
@ -1,53 +0,0 @@
|
||||
// Copyright (c) 2022 Dominic Masters
|
||||
//
|
||||
// This software is released under the MIT License.
|
||||
// https://opensource.org/licenses/MIT
|
||||
|
||||
#pragma once
|
||||
#include "dawnlibs.hpp"
|
||||
#include "util/mathutils.hpp"
|
||||
|
||||
namespace Dawn {
|
||||
/**
|
||||
* Seed the random number generator
|
||||
* @param seed Seed to use for the seeded random number generator.
|
||||
*/
|
||||
static void randSeed(int32_t seed) {
|
||||
srand(seed);
|
||||
}
|
||||
|
||||
static int32_t randomGeneratei32() {
|
||||
return (int32_t)rand();
|
||||
}
|
||||
|
||||
/**
|
||||
* Generates a random number.
|
||||
* @returns A random number.
|
||||
*/
|
||||
template<typename T>
|
||||
static T randomGenerate() {
|
||||
return (T)((float_t)randomGeneratei32() * MATH_PI);
|
||||
}
|
||||
|
||||
////////////////////////////////////////////////////////////////////////////////
|
||||
|
||||
/**
|
||||
* Clamps a random number generation.
|
||||
*
|
||||
* @param min Minimum value to generate from. (Inclusive)
|
||||
* @param max Maximum value to generate to. (Exclusive)
|
||||
* @return Random number between min and max.
|
||||
*/
|
||||
template<typename T>
|
||||
static inline T randRange(T min, T max) {
|
||||
return mathMod<T>(randomGenerate<T>(), (max - min)) + min;
|
||||
}
|
||||
|
||||
static inline float_t randRange(float_t min, float_t max) {
|
||||
return mathMod(randomGenerate<float_t>(), (max - min)) + min;
|
||||
}
|
||||
|
||||
static inline glm::vec2 randRange(glm::vec2 min, glm::vec2 max) {
|
||||
return glm::vec2(randRange(min.x, max.x), randRange(min.y, max.y));
|
||||
}
|
||||
}
|
@ -1,168 +0,0 @@
|
||||
// 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