add basic c++ project setup

This commit is contained in:
2026-04-19 10:19:27 +02:00
parent 1e1f2d7816
commit 8b740dfe8e
36 changed files with 16842 additions and 0 deletions

176
src/CMakeLists.txt Normal file
View File

@@ -0,0 +1,176 @@
set(TARGET_BASE_NAME "DotaFactory")
set(TARGET_APP_NAME "${TARGET_BASE_NAME}")
set(TARGET_LIB_NAME "${TARGET_BASE_NAME}_lib")
set(TARGET_TEST_NAME "${TARGET_BASE_NAME}_test")
set(TARGET_LIB_HEADER_SEARCH_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/lib" "${CMAKE_CURRENT_SOURCE_DIR}/external")
set(TARGET_TEST_HEADER_SEARCH_PATHS "${CMAKE_CURRENT_SOURCE_DIR}/test")
set(HEADER_SEARCH_PATHS ${TARGET_LIB_HEADER_SEARCH_PATHS} ${HEADER_SEARCH_PATHS})
set (SRC_DIR "${CMAKE_CURRENT_SOURCE_DIR}")
# Lib ------------------------------------------------------------
SET(HDRS)
SET(SRCS)
SET(LIB_INCLUDE_PATH)
add_subdirectory(external)
add_subdirectory(lib)
set_source_files_properties(${EXTERNAL_FILES} PROPERTIES COMPILE_FLAGS "-w")
# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
# Instruct CMake to run moc automatically when needed.
set(CMAKE_AUTOMOC ON)
SET(RELATIVE_HDRS)
foreach (_file ${HDRS})
file (RELATIVE_PATH _relPath "${SRC_DIR}" "${_file}")
list (APPEND RELATIVE_HDRS "${_relPath}")
endforeach()
SET(RELATIVE_SRCS)
foreach (_file ${SRCS})
file (RELATIVE_PATH _relPath "${SRC_DIR}" "${_file}")
list (APPEND RELATIVE_SRCS "${_relPath}")
endforeach()
add_files(
LIB_FILES
${RELATIVE_HDRS}
${RELATIVE_SRCS}
)
set(HEADER_SEARCH_PATHS ${LIB_INCLUDE_PATH} ${HEADER_SEARCH_PATHS})
add_library(${TARGET_LIB_NAME} ${LIB_FILES} ${EXTERNAL_FILES})
create_source_groups(${LIB_FILES})
create_source_groups(${EXTERNAL_FILES})
UNSET(LIB_FILES)
UNSET(RELATIVE_HDRS)
UNSET(RELATIVE_SRCS)
set_property(TARGET ${TARGET_LIB_NAME} PROPERTY CXX_STANDARD 17)
set_property(
TARGET ${TARGET_LIB_NAME}
PROPERTY INCLUDE_DIRECTORIES "${HEADER_SEARCH_PATHS}"
)
# include external header without warnings
target_include_directories(${TARGET_LIB_NAME} SYSTEM
PUBLIC "${SYSTEM_HEADER_SEARCH_PATHS}"
)
target_link_libraries(${TARGET_LIB_NAME} ${LINK_LIBRARIES})
set(CMAKE_AUTOMOC OFF)
set(LINK_LIBRARIES ${LINK_LIBRARIES} ${TARGET_LIB_NAME})
# App ------------------------------------------------------------
set(OUTPUT_ROOT_PATH "${CMAKE_BINARY_DIR}/${TARGET_BASE_NAME}")
if (WIN32)
COPY_QT_BINARIES("${OUTPUT_ROOT_PATH}/Debug/app/" True)
COPY_QT_BINARIES("${OUTPUT_ROOT_PATH}/Release/app/" False)
string(REGEX REPLACE "/" "\\\\" BACKSLASHED_CMAKE_SOURCE_DIR ${CMAKE_SOURCE_DIR})
string(REGEX REPLACE "/" "\\\\" BACKSLASHED_OUTPUT_ROOT_PATH ${OUTPUT_ROOT_PATH})
execute_process(
COMMAND "cmd.exe" "/k" "rmdir" "${BACKSLASHED_OUTPUT_ROOT_PATH}\\Debug\\app\\data" & "mklink" "/d" "/j" "${BACKSLASHED_OUTPUT_ROOT_PATH}\\Debug\\app\\data" "${BACKSLASHED_CMAKE_SOURCE_DIR}\\bin\\app\\data" & exit
COMMAND "cmd.exe" "/k" "rmdir" "${BACKSLASHED_OUTPUT_ROOT_PATH}\\Release\\app\\data" & "mklink" "/d" "/j" "${BACKSLASHED_OUTPUT_ROOT_PATH}\\Release\\app\\data" "${BACKSLASHED_CMAKE_SOURCE_DIR}\\bin\\app\\data" & exit
)
endif ()
foreach( OUTPUTCONFIG ${CMAKE_CONFIGURATION_TYPES} )
string( TOUPPER ${OUTPUTCONFIG} OUTPUTCONFIG )
set( CMAKE_RUNTIME_OUTPUT_DIRECTORY_${OUTPUTCONFIG} "${OUTPUT_ROOT_PATH}/${OUTPUTCONFIG}/app/")
endforeach( OUTPUTCONFIG CMAKE_CONFIGURATION_TYPES )
add_subdirectory(app)
SET(RELATIVE_HDRS)
foreach (_file ${HDRS})
file (RELATIVE_PATH _relPath "${SRC_DIR}" "${_file}")
list (APPEND RELATIVE_HDRS "${_relPath}")
endforeach()
SET(RELATIVE_SRCS)
foreach (_file ${SRCS})
file (RELATIVE_PATH _relPath "${SRC_DIR}" "${_file}")
list (APPEND RELATIVE_SRCS "${_relPath}")
endforeach()
add_files(
APP_FILES
${RELATIVE_HDRS}
${RELATIVE_SRCS}
)
add_executable(${TARGET_APP_NAME} ${APP_FILES})
set_target_properties(${TARGET_APP_NAME} PROPERTIES VS_DEBUGGER_WORKING_DIRECTORY "${OUTPUT_ROOT_PATH}/$(Configuration)/app/")
create_source_groups(${APP_FILES})
set_property(TARGET ${TARGET_APP_NAME} PROPERTY CXX_STANDARD 17)
set_property(
TARGET ${TARGET_APP_NAME} PROPERTY INCLUDE_DIRECTORIES
"${TARGET_APP_HEADER_SEARCH_PATHS}"
"${HEADER_SEARCH_PATHS}"
)
target_include_directories(${TARGET_APP_NAME} SYSTEM
PUBLIC "${SYSTEM_HEADER_SEARCH_PATHS}"
)
target_link_libraries(${TARGET_APP_NAME} ${LINK_LIBRARIES})
# Test ------------------------------------------------------------
add_subdirectory(test)
# Find includes in corresponding build directories
set(CMAKE_INCLUDE_CURRENT_DIR ON)
add_executable(${TARGET_TEST_NAME} ${TEST_FILES})
create_source_groups(${TEST_FILES})
set_property(TARGET ${TARGET_TEST_NAME} PROPERTY CXX_STANDARD 17)
set_property(
TARGET ${TARGET_TEST_NAME} PROPERTY INCLUDE_DIRECTORIES
"${TARGET_TEST_HEADER_SEARCH_PATHS}"
"${HEADER_SEARCH_PATHS}"
)
target_include_directories(${TARGET_TEST_NAME} SYSTEM
PUBLIC "${SYSTEM_HEADER_SEARCH_PATHS}"
)
target_link_libraries(${TARGET_TEST_NAME} ${LINK_LIBRARIES})
# Export ------------------------------------------------------------
set(TARGET_LIB_NAME "${TARGET_LIB_NAME}" PARENT_SCOPE)
set(TARGET_APP_NAME "${TARGET_APP_NAME}" PARENT_SCOPE)
set(HEADER_SEARCH_PATHS ${HEADER_SEARCH_PATHS} PARENT_SCOPE)
set(LINK_LIBRARIES ${LINK_LIBRARIES} PARENT_SCOPE)

16
src/app/CMakeLists.txt Normal file
View File

@@ -0,0 +1,16 @@
SET(HDRS)
SET(SRCS)
SET(HDRS
${HDRS}
PARENT_SCOPE
)
SET(SRCS
${SRCS}
${CMAKE_CURRENT_SOURCE_DIR}/main.cpp
PARENT_SCOPE
)

34
src/app/main.cpp Normal file
View File

@@ -0,0 +1,34 @@
#include <memory>
#include <QApplication>
#include <QDir>
#include "ConsoleLogger.h"
#include "logging.h"
#include "LogManager.h"
int main(int argc, char *argv[])
{
LogManager::getInstance()->addLogger(std::make_shared<ConsoleLogger>());
LogManager::getInstance()->setLoggingEnabled(true);
LOG_INFO("Logging enabled");
QApplication::setApplicationName("DotaFactory");
if (QSysInfo::windowsVersion() != QSysInfo::WV_None)
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling, true);
}
QApplication application(argc, argv);
const QDir dataDir("data");
if (!dataDir.exists())
{
QDir().mkdir(dataDir.dirName());
}
const int ret = application.exec();
return ret;
}

8
src/external/CMakeLists.txt vendored Normal file
View File

@@ -0,0 +1,8 @@
add_files(
EXTERNAL_FILES
catch/catch.hpp
tinyexpr/tinyexpr.c
tinyexpr/tinyexpr.h
toml++/toml.hpp
)

14361
src/external/catch/catch.hpp vendored Normal file

File diff suppressed because it is too large Load Diff

734
src/external/tinyexpr/tinyexpr.c vendored Normal file
View File

@@ -0,0 +1,734 @@
// SPDX-License-Identifier: Zlib
/*
* TINYEXPR - Tiny recursive descent parser and evaluation engine in C
*
* Copyright (c) 2015-2020 Lewis Van Winkle
*
* http://CodePlea.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgement in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
/* COMPILE TIME OPTIONS */
/* Exponentiation associativity:
For a^b^c = (a^b)^c and -a^b = (-a)^b do nothing.
For a^b^c = a^(b^c) and -a^b = -(a^b) uncomment the next line.*/
/* #define TE_POW_FROM_RIGHT */
/* Logarithms
For log = base 10 log do nothing
For log = natural log uncomment the next line. */
/* #define TE_NAT_LOG */
#include "tinyexpr.h"
#include <stdlib.h>
#include <math.h>
#include <string.h>
#include <stdio.h>
#include <ctype.h>
#include <limits.h>
#ifndef NAN
#define NAN (0.0/0.0)
#endif
#ifndef INFINITY
#define INFINITY (1.0/0.0)
#endif
typedef double (*te_fun2)(double, double);
enum {
TOK_NULL = TE_CLOSURE7+1, TOK_ERROR, TOK_END, TOK_SEP,
TOK_OPEN, TOK_CLOSE, TOK_NUMBER, TOK_VARIABLE, TOK_INFIX
};
enum {TE_CONSTANT = 1};
typedef struct state {
const char *start;
const char *next;
int type;
union {double value; const double *bound; const void *function;};
void *context;
const te_variable *lookup;
int lookup_len;
} state;
#define TYPE_MASK(TYPE) ((TYPE)&0x0000001F)
#define IS_PURE(TYPE) (((TYPE) & TE_FLAG_PURE) != 0)
#define IS_FUNCTION(TYPE) (((TYPE) & TE_FUNCTION0) != 0)
#define IS_CLOSURE(TYPE) (((TYPE) & TE_CLOSURE0) != 0)
#define ARITY(TYPE) ( ((TYPE) & (TE_FUNCTION0 | TE_CLOSURE0)) ? ((TYPE) & 0x00000007) : 0 )
#define NEW_EXPR(type, ...) new_expr((type), (const te_expr*[]){__VA_ARGS__})
#define CHECK_NULL(ptr, ...) if ((ptr) == NULL) { __VA_ARGS__; return NULL; }
static te_expr *new_expr(const int type, const te_expr *parameters[]) {
const int arity = ARITY(type);
const int psize = sizeof(void*) * arity;
const int size = (sizeof(te_expr) - sizeof(void*)) + psize + (IS_CLOSURE(type) ? sizeof(void*) : 0);
te_expr *ret = malloc(size);
CHECK_NULL(ret);
memset(ret, 0, size);
if (arity && parameters) {
memcpy(ret->parameters, parameters, psize);
}
ret->type = type;
ret->bound = 0;
return ret;
}
void te_free_parameters(te_expr *n) {
if (!n) return;
switch (TYPE_MASK(n->type)) {
case TE_FUNCTION7: case TE_CLOSURE7: te_free(n->parameters[6]); /* Falls through. */
case TE_FUNCTION6: case TE_CLOSURE6: te_free(n->parameters[5]); /* Falls through. */
case TE_FUNCTION5: case TE_CLOSURE5: te_free(n->parameters[4]); /* Falls through. */
case TE_FUNCTION4: case TE_CLOSURE4: te_free(n->parameters[3]); /* Falls through. */
case TE_FUNCTION3: case TE_CLOSURE3: te_free(n->parameters[2]); /* Falls through. */
case TE_FUNCTION2: case TE_CLOSURE2: te_free(n->parameters[1]); /* Falls through. */
case TE_FUNCTION1: case TE_CLOSURE1: te_free(n->parameters[0]);
}
}
void te_free(te_expr *n) {
if (!n) return;
te_free_parameters(n);
free(n);
}
static double pi(void) {return 3.14159265358979323846;}
static double e(void) {return 2.71828182845904523536;}
static double fac(double a) {/* simplest version of fac */
if (a < 0.0)
return NAN;
if (a > UINT_MAX)
return INFINITY;
unsigned int ua = (unsigned int)(a);
unsigned long int result = 1, i;
for (i = 1; i <= ua; i++) {
if (i > ULONG_MAX / result)
return INFINITY;
result *= i;
}
return (double)result;
}
static double ncr(double n, double r) {
if (n < 0.0 || r < 0.0 || n < r) return NAN;
if (n > UINT_MAX || r > UINT_MAX) return INFINITY;
unsigned long int un = (unsigned int)(n), ur = (unsigned int)(r), i;
unsigned long int result = 1;
if (ur > un / 2) ur = un - ur;
for (i = 1; i <= ur; i++) {
if (result > ULONG_MAX / (un - ur + i))
return INFINITY;
result *= un - ur + i;
result /= i;
}
return result;
}
static double npr(double n, double r) {return ncr(n, r) * fac(r);}
#ifdef _MSC_VER
#pragma function (ceil)
#pragma function (floor)
#endif
static const te_variable functions[] = {
/* must be in alphabetical order */
{"abs", fabs, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"acos", acos, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"asin", asin, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"atan", atan, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"atan2", atan2, TE_FUNCTION2 | TE_FLAG_PURE, 0},
{"ceil", ceil, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"cos", cos, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"cosh", cosh, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"e", e, TE_FUNCTION0 | TE_FLAG_PURE, 0},
{"exp", exp, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"fac", fac, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"floor", floor, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"ln", log, TE_FUNCTION1 | TE_FLAG_PURE, 0},
#ifdef TE_NAT_LOG
{"log", log, TE_FUNCTION1 | TE_FLAG_PURE, 0},
#else
{"log", log10, TE_FUNCTION1 | TE_FLAG_PURE, 0},
#endif
{"log10", log10, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"ncr", ncr, TE_FUNCTION2 | TE_FLAG_PURE, 0},
{"npr", npr, TE_FUNCTION2 | TE_FLAG_PURE, 0},
{"pi", pi, TE_FUNCTION0 | TE_FLAG_PURE, 0},
{"pow", pow, TE_FUNCTION2 | TE_FLAG_PURE, 0},
{"sin", sin, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"sinh", sinh, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"sqrt", sqrt, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"tan", tan, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{"tanh", tanh, TE_FUNCTION1 | TE_FLAG_PURE, 0},
{0, 0, 0, 0}
};
static const te_variable *find_builtin(const char *name, int len) {
int imin = 0;
int imax = sizeof(functions) / sizeof(te_variable) - 2;
/*Binary search.*/
while (imax >= imin) {
const int i = (imin + ((imax-imin)/2));
int c = strncmp(name, functions[i].name, len);
if (!c) c = '\0' - functions[i].name[len];
if (c == 0) {
return functions + i;
} else if (c > 0) {
imin = i + 1;
} else {
imax = i - 1;
}
}
return 0;
}
static const te_variable *find_lookup(const state *s, const char *name, int len) {
int iters;
const te_variable *var;
if (!s->lookup) return 0;
for (var = s->lookup, iters = s->lookup_len; iters; ++var, --iters) {
if (strncmp(name, var->name, len) == 0 && var->name[len] == '\0') {
return var;
}
}
return 0;
}
static double add(double a, double b) {return a + b;}
static double sub(double a, double b) {return a - b;}
static double mul(double a, double b) {return a * b;}
static double divide(double a, double b) {return a / b;}
static double negate(double a) {return -a;}
static double comma(double a, double b) {(void)a; return b;}
void next_token(state *s) {
s->type = TOK_NULL;
do {
if (!*s->next){
s->type = TOK_END;
return;
}
/* Try reading a number. */
if ((s->next[0] >= '0' && s->next[0] <= '9') || s->next[0] == '.') {
s->value = strtod(s->next, (char**)&s->next);
s->type = TOK_NUMBER;
} else {
/* Look for a variable or builtin function call. */
if (isalpha(s->next[0])) {
const char *start;
start = s->next;
while (isalpha(s->next[0]) || isdigit(s->next[0]) || (s->next[0] == '_')) s->next++;
const te_variable *var = find_lookup(s, start, s->next - start);
if (!var) var = find_builtin(start, s->next - start);
if (!var) {
s->type = TOK_ERROR;
} else {
switch(TYPE_MASK(var->type))
{
case TE_VARIABLE:
s->type = TOK_VARIABLE;
s->bound = var->address;
break;
case TE_CLOSURE0: case TE_CLOSURE1: case TE_CLOSURE2: case TE_CLOSURE3: /* Falls through. */
case TE_CLOSURE4: case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7: /* Falls through. */
s->context = var->context; /* Falls through. */
case TE_FUNCTION0: case TE_FUNCTION1: case TE_FUNCTION2: case TE_FUNCTION3: /* Falls through. */
case TE_FUNCTION4: case TE_FUNCTION5: case TE_FUNCTION6: case TE_FUNCTION7: /* Falls through. */
s->type = var->type;
s->function = var->address;
break;
}
}
} else {
/* Look for an operator or special character. */
switch (s->next++[0]) {
case '+': s->type = TOK_INFIX; s->function = add; break;
case '-': s->type = TOK_INFIX; s->function = sub; break;
case '*': s->type = TOK_INFIX; s->function = mul; break;
case '/': s->type = TOK_INFIX; s->function = divide; break;
case '^': s->type = TOK_INFIX; s->function = pow; break;
case '%': s->type = TOK_INFIX; s->function = fmod; break;
case '(': s->type = TOK_OPEN; break;
case ')': s->type = TOK_CLOSE; break;
case ',': s->type = TOK_SEP; break;
case ' ': case '\t': case '\n': case '\r': break;
default: s->type = TOK_ERROR; break;
}
}
}
} while (s->type == TOK_NULL);
}
static te_expr *list(state *s);
static te_expr *expr(state *s);
static te_expr *power(state *s);
static te_expr *base(state *s) {
/* <base> = <constant> | <variable> | <function-0> {"(" ")"} | <function-1> <power> | <function-X> "(" <expr> {"," <expr>} ")" | "(" <list> ")" */
te_expr *ret;
int arity;
switch (TYPE_MASK(s->type)) {
case TOK_NUMBER:
ret = new_expr(TE_CONSTANT, 0);
CHECK_NULL(ret);
ret->value = s->value;
next_token(s);
break;
case TOK_VARIABLE:
ret = new_expr(TE_VARIABLE, 0);
CHECK_NULL(ret);
ret->bound = s->bound;
next_token(s);
break;
case TE_FUNCTION0:
case TE_CLOSURE0:
ret = new_expr(s->type, 0);
CHECK_NULL(ret);
ret->function = s->function;
if (IS_CLOSURE(s->type)) ret->parameters[0] = s->context;
next_token(s);
if (s->type == TOK_OPEN) {
next_token(s);
if (s->type != TOK_CLOSE) {
s->type = TOK_ERROR;
} else {
next_token(s);
}
}
break;
case TE_FUNCTION1:
case TE_CLOSURE1:
ret = new_expr(s->type, 0);
CHECK_NULL(ret);
ret->function = s->function;
if (IS_CLOSURE(s->type)) ret->parameters[1] = s->context;
next_token(s);
ret->parameters[0] = power(s);
CHECK_NULL(ret->parameters[0], te_free(ret));
break;
case TE_FUNCTION2: case TE_FUNCTION3: case TE_FUNCTION4:
case TE_FUNCTION5: case TE_FUNCTION6: case TE_FUNCTION7:
case TE_CLOSURE2: case TE_CLOSURE3: case TE_CLOSURE4:
case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7:
arity = ARITY(s->type);
ret = new_expr(s->type, 0);
CHECK_NULL(ret);
ret->function = s->function;
if (IS_CLOSURE(s->type)) ret->parameters[arity] = s->context;
next_token(s);
if (s->type != TOK_OPEN) {
s->type = TOK_ERROR;
} else {
int i;
for(i = 0; i < arity; i++) {
next_token(s);
ret->parameters[i] = expr(s);
CHECK_NULL(ret->parameters[i], te_free(ret));
if(s->type != TOK_SEP) {
break;
}
}
if(s->type != TOK_CLOSE || i != arity - 1) {
s->type = TOK_ERROR;
} else {
next_token(s);
}
}
break;
case TOK_OPEN:
next_token(s);
ret = list(s);
CHECK_NULL(ret);
if (s->type != TOK_CLOSE) {
s->type = TOK_ERROR;
} else {
next_token(s);
}
break;
default:
ret = new_expr(0, 0);
CHECK_NULL(ret);
s->type = TOK_ERROR;
ret->value = NAN;
break;
}
return ret;
}
static te_expr *power(state *s) {
/* <power> = {("-" | "+")} <base> */
int sign = 1;
while (s->type == TOK_INFIX && (s->function == add || s->function == sub)) {
if (s->function == sub) sign = -sign;
next_token(s);
}
te_expr *ret;
if (sign == 1) {
ret = base(s);
} else {
te_expr *b = base(s);
CHECK_NULL(b);
ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, b);
CHECK_NULL(ret, te_free(b));
ret->function = negate;
}
return ret;
}
#ifdef TE_POW_FROM_RIGHT
static te_expr *factor(state *s) {
/* <factor> = <power> {"^" <power>} */
te_expr *ret = power(s);
CHECK_NULL(ret);
int neg = 0;
if (ret->type == (TE_FUNCTION1 | TE_FLAG_PURE) && ret->function == negate) {
te_expr *se = ret->parameters[0];
free(ret);
ret = se;
neg = 1;
}
te_expr *insertion = 0;
while (s->type == TOK_INFIX && (s->function == pow)) {
te_fun2 t = s->function;
next_token(s);
if (insertion) {
/* Make exponentiation go right-to-left. */
te_expr *p = power(s);
CHECK_NULL(p, te_free(ret));
te_expr *insert = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, insertion->parameters[1], p);
CHECK_NULL(insert, te_free(p), te_free(ret));
insert->function = t;
insertion->parameters[1] = insert;
insertion = insert;
} else {
te_expr *p = power(s);
CHECK_NULL(p, te_free(ret));
te_expr *prev = ret;
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, p);
CHECK_NULL(ret, te_free(p), te_free(prev));
ret->function = t;
insertion = ret;
}
}
if (neg) {
te_expr *prev = ret;
ret = NEW_EXPR(TE_FUNCTION1 | TE_FLAG_PURE, ret);
CHECK_NULL(ret, te_free(prev));
ret->function = negate;
}
return ret;
}
#else
static te_expr *factor(state *s) {
/* <factor> = <power> {"^" <power>} */
te_expr *ret = power(s);
CHECK_NULL(ret);
while (s->type == TOK_INFIX && (s->function == pow)) {
te_fun2 t = s->function;
next_token(s);
te_expr *p = power(s);
CHECK_NULL(p, te_free(ret));
te_expr *prev = ret;
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, p);
CHECK_NULL(ret, te_free(p), te_free(prev));
ret->function = t;
}
return ret;
}
#endif
static te_expr *term(state *s) {
/* <term> = <factor> {("*" | "/" | "%") <factor>} */
te_expr *ret = factor(s);
CHECK_NULL(ret);
while (s->type == TOK_INFIX && (s->function == mul || s->function == divide || s->function == fmod)) {
te_fun2 t = s->function;
next_token(s);
te_expr *f = factor(s);
CHECK_NULL(f, te_free(ret));
te_expr *prev = ret;
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, f);
CHECK_NULL(ret, te_free(f), te_free(prev));
ret->function = t;
}
return ret;
}
static te_expr *expr(state *s) {
/* <expr> = <term> {("+" | "-") <term>} */
te_expr *ret = term(s);
CHECK_NULL(ret);
while (s->type == TOK_INFIX && (s->function == add || s->function == sub)) {
te_fun2 t = s->function;
next_token(s);
te_expr *te = term(s);
CHECK_NULL(te, te_free(ret));
te_expr *prev = ret;
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, te);
CHECK_NULL(ret, te_free(te), te_free(prev));
ret->function = t;
}
return ret;
}
static te_expr *list(state *s) {
/* <list> = <expr> {"," <expr>} */
te_expr *ret = expr(s);
CHECK_NULL(ret);
while (s->type == TOK_SEP) {
next_token(s);
te_expr *e = expr(s);
CHECK_NULL(e, te_free(ret));
te_expr *prev = ret;
ret = NEW_EXPR(TE_FUNCTION2 | TE_FLAG_PURE, ret, e);
CHECK_NULL(ret, te_free(e), te_free(prev));
ret->function = comma;
}
return ret;
}
#define TE_FUN(...) ((double(*)(__VA_ARGS__))n->function)
#define M(e) te_eval(n->parameters[e])
double te_eval(const te_expr *n) {
if (!n) return NAN;
switch(TYPE_MASK(n->type)) {
case TE_CONSTANT: return n->value;
case TE_VARIABLE: return *n->bound;
case TE_FUNCTION0: case TE_FUNCTION1: case TE_FUNCTION2: case TE_FUNCTION3:
case TE_FUNCTION4: case TE_FUNCTION5: case TE_FUNCTION6: case TE_FUNCTION7:
switch(ARITY(n->type)) {
case 0: return TE_FUN(void)();
case 1: return TE_FUN(double)(M(0));
case 2: return TE_FUN(double, double)(M(0), M(1));
case 3: return TE_FUN(double, double, double)(M(0), M(1), M(2));
case 4: return TE_FUN(double, double, double, double)(M(0), M(1), M(2), M(3));
case 5: return TE_FUN(double, double, double, double, double)(M(0), M(1), M(2), M(3), M(4));
case 6: return TE_FUN(double, double, double, double, double, double)(M(0), M(1), M(2), M(3), M(4), M(5));
case 7: return TE_FUN(double, double, double, double, double, double, double)(M(0), M(1), M(2), M(3), M(4), M(5), M(6));
default: return NAN;
}
case TE_CLOSURE0: case TE_CLOSURE1: case TE_CLOSURE2: case TE_CLOSURE3:
case TE_CLOSURE4: case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7:
switch(ARITY(n->type)) {
case 0: return TE_FUN(void*)(n->parameters[0]);
case 1: return TE_FUN(void*, double)(n->parameters[1], M(0));
case 2: return TE_FUN(void*, double, double)(n->parameters[2], M(0), M(1));
case 3: return TE_FUN(void*, double, double, double)(n->parameters[3], M(0), M(1), M(2));
case 4: return TE_FUN(void*, double, double, double, double)(n->parameters[4], M(0), M(1), M(2), M(3));
case 5: return TE_FUN(void*, double, double, double, double, double)(n->parameters[5], M(0), M(1), M(2), M(3), M(4));
case 6: return TE_FUN(void*, double, double, double, double, double, double)(n->parameters[6], M(0), M(1), M(2), M(3), M(4), M(5));
case 7: return TE_FUN(void*, double, double, double, double, double, double, double)(n->parameters[7], M(0), M(1), M(2), M(3), M(4), M(5), M(6));
default: return NAN;
}
default: return NAN;
}
}
#undef TE_FUN
#undef M
static void optimize(te_expr *n) {
/* Evaluates as much as possible. */
if (n->type == TE_CONSTANT) return;
if (n->type == TE_VARIABLE) return;
/* Only optimize out functions flagged as pure. */
if (IS_PURE(n->type)) {
const int arity = ARITY(n->type);
int known = 1;
int i;
for (i = 0; i < arity; ++i) {
optimize(n->parameters[i]);
if (((te_expr*)(n->parameters[i]))->type != TE_CONSTANT) {
known = 0;
}
}
if (known) {
const double value = te_eval(n);
te_free_parameters(n);
n->type = TE_CONSTANT;
n->value = value;
}
}
}
te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error) {
state s;
s.start = s.next = expression;
s.lookup = variables;
s.lookup_len = var_count;
next_token(&s);
te_expr *root = list(&s);
if (root == NULL) {
if (error) *error = -1;
return NULL;
}
if (s.type != TOK_END) {
te_free(root);
if (error) {
*error = (s.next - s.start);
if (*error == 0) *error = 1;
}
return 0;
} else {
optimize(root);
if (error) *error = 0;
return root;
}
}
double te_interp(const char *expression, int *error) {
te_expr *n = te_compile(expression, 0, 0, error);
double ret;
if (n) {
ret = te_eval(n);
te_free(n);
} else {
ret = NAN;
}
return ret;
}
static void pn (const te_expr *n, int depth) {
int i, arity;
printf("%*s", depth, "");
switch(TYPE_MASK(n->type)) {
case TE_CONSTANT: printf("%f\n", n->value); break;
case TE_VARIABLE: printf("bound %p\n", n->bound); break;
case TE_FUNCTION0: case TE_FUNCTION1: case TE_FUNCTION2: case TE_FUNCTION3:
case TE_FUNCTION4: case TE_FUNCTION5: case TE_FUNCTION6: case TE_FUNCTION7:
case TE_CLOSURE0: case TE_CLOSURE1: case TE_CLOSURE2: case TE_CLOSURE3:
case TE_CLOSURE4: case TE_CLOSURE5: case TE_CLOSURE6: case TE_CLOSURE7:
arity = ARITY(n->type);
printf("f%d", arity);
for(i = 0; i < arity; i++) {
printf(" %p", n->parameters[i]);
}
printf("\n");
for(i = 0; i < arity; i++) {
pn(n->parameters[i], depth + 1);
}
break;
}
}
void te_print(const te_expr *n) {
pn(n, 0);
}

87
src/external/tinyexpr/tinyexpr.h vendored Normal file
View File

@@ -0,0 +1,87 @@
// SPDX-License-Identifier: Zlib
/*
* TINYEXPR - Tiny recursive descent parser and evaluation engine in C
*
* Copyright (c) 2015-2020 Lewis Van Winkle
*
* http://CodePlea.com
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
* arising from the use of this software.
*
* Permission is granted to anyone to use this software for any purpose,
* including commercial applications, and to alter it and redistribute it
* freely, subject to the following restrictions:
*
* 1. The origin of this software must not be misrepresented; you must not
* claim that you wrote the original software. If you use this software
* in a product, an acknowledgement in the product documentation would be
* appreciated but is not required.
* 2. Altered source versions must be plainly marked as such, and must not be
* misrepresented as being the original software.
* 3. This notice may not be removed or altered from any source distribution.
*/
#ifndef TINYEXPR_H
#define TINYEXPR_H
#ifdef __cplusplus
extern "C" {
#endif
typedef struct te_expr {
int type;
union {double value; const double *bound; const void *function;};
void *parameters[1];
} te_expr;
enum {
TE_VARIABLE = 0,
TE_FUNCTION0 = 8, TE_FUNCTION1, TE_FUNCTION2, TE_FUNCTION3,
TE_FUNCTION4, TE_FUNCTION5, TE_FUNCTION6, TE_FUNCTION7,
TE_CLOSURE0 = 16, TE_CLOSURE1, TE_CLOSURE2, TE_CLOSURE3,
TE_CLOSURE4, TE_CLOSURE5, TE_CLOSURE6, TE_CLOSURE7,
TE_FLAG_PURE = 32
};
typedef struct te_variable {
const char *name;
const void *address;
int type;
void *context;
} te_variable;
/* Parses the input expression, evaluates it, and frees it. */
/* Returns NaN on error. */
double te_interp(const char *expression, int *error);
/* Parses the input expression and binds variables. */
/* Returns NULL on error. */
te_expr *te_compile(const char *expression, const te_variable *variables, int var_count, int *error);
/* Evaluates the expression. */
double te_eval(const te_expr *n);
/* Prints debugging information on the syntax tree. */
void te_print(const te_expr *n);
/* Frees the expression. */
/* This is safe to call on NULL pointers. */
void te_free(te_expr *n);
#ifdef __cplusplus
}
#endif
#endif /*TINYEXPR_H*/

16
src/external/toml++/LICENSE vendored Normal file
View File

@@ -0,0 +1,16 @@
MIT License
Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated
documentation files (the "Software"), to deal in the Software without restriction, including without limitation the
rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the
Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE
WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.

234
src/external/toml++/toml.hpp vendored Normal file
View File

@@ -0,0 +1,234 @@
//# This file is a part of toml++ and is subject to the the terms of the MIT license.
//# Copyright (c) Mark Gillard <mark.gillard@outlook.com.au>
//# See https://github.com/marzer/tomlplusplus/blob/master/LICENSE for the full license text.
// SPDX-License-Identifier: MIT
#ifndef TOMLPLUSPLUS_HPP
#define TOMLPLUSPLUS_HPP
#define INCLUDE_TOMLPLUSPLUS_H // old guard name used pre-v3
#define TOMLPLUSPLUS_H // guard name used in the legacy toml.h
#include "impl/preprocessor.hpp"
TOML_PUSH_WARNINGS;
TOML_DISABLE_SPAM_WARNINGS;
TOML_DISABLE_SWITCH_WARNINGS;
TOML_DISABLE_SUGGEST_ATTR_WARNINGS;
// misc warning false-positives
#if TOML_MSVC
#pragma warning(disable : 5031) // #pragma warning(pop): likely mismatch
#if TOML_SHARED_LIB
#pragma warning(disable : 4251) // dll exports for std lib types
#endif
#elif TOML_CLANG
TOML_PRAGMA_CLANG(diagnostic ignored "-Wheader-hygiene")
#if TOML_CLANG >= 12
TOML_PRAGMA_CLANG(diagnostic ignored "-Wc++20-extensions")
#endif
#if TOML_CLANG == 13
TOML_PRAGMA_CLANG(diagnostic ignored "-Wreserved-identifier")
#endif
#endif
// IWYU pragma: begin_exports
#include "impl/std_new.hpp"
#include "impl/std_string.hpp"
#include "impl/std_optional.hpp"
#include "impl/forward_declarations.hpp"
#include "impl/print_to_stream.hpp"
#include "impl/source_region.hpp"
#include "impl/date_time.hpp"
#include "impl/at_path.hpp"
#include "impl/path.hpp"
#include "impl/node.hpp"
#include "impl/node_view.hpp"
#include "impl/value.hpp"
#include "impl/make_node.hpp"
#include "impl/array.hpp"
#include "impl/key.hpp"
#include "impl/table.hpp"
#include "impl/unicode_autogenerated.hpp"
#include "impl/unicode.hpp"
#include "impl/parse_error.hpp"
#include "impl/parse_result.hpp"
#include "impl/parser.hpp"
#include "impl/formatter.hpp"
#include "impl/toml_formatter.hpp"
#include "impl/json_formatter.hpp"
#include "impl/yaml_formatter.hpp"
// IWYU pragma: end_exports
#if TOML_IMPLEMENTATION
#include "impl/std_string.inl"
#include "impl/print_to_stream.inl"
#include "impl/node.inl"
#include "impl/at_path.inl"
#include "impl/path.inl"
#include "impl/array.inl"
#include "impl/table.inl"
#include "impl/unicode.inl"
#include "impl/parser.inl"
#include "impl/formatter.inl"
#include "impl/toml_formatter.inl"
#include "impl/json_formatter.inl"
#include "impl/yaml_formatter.inl"
#endif // TOML_IMPLEMENTATION
TOML_POP_WARNINGS;
// macro hygiene
#if TOML_UNDEF_MACROS
#undef TOML_ABI_NAMESPACE_BOOL
#undef TOML_ABI_NAMESPACE_END
#undef TOML_ABI_NAMESPACE_START
#undef TOML_ABI_NAMESPACES
#undef TOML_ABSTRACT_INTERFACE
#undef TOML_ALWAYS_INLINE
#undef TOML_ANON_NAMESPACE
#undef TOML_ANON_NAMESPACE_END
#undef TOML_ANON_NAMESPACE_START
#undef TOML_ARCH_AMD64
#undef TOML_ARCH_ARM
#undef TOML_ARCH_ARM32
#undef TOML_ARCH_ARM64
#undef TOML_ARCH_BITNESS
#undef TOML_ARCH_ITANIUM
#undef TOML_ARCH_X64
#undef TOML_ARCH_X86
#undef TOML_ASSERT
#undef TOML_ASSERT_ASSUME
#undef TOML_ASSUME
#undef TOML_ASYMMETRICAL_EQUALITY_OPS
#undef TOML_ATTR
#undef TOML_CLANG
#undef TOML_CLANG_VERSION
#undef TOML_CLOSED_ENUM
#undef TOML_CLOSED_FLAGS_ENUM
#undef TOML_COMPILER_HAS_EXCEPTIONS
#undef TOML_COMPILER_HAS_RTTI
#undef TOML_CONST
#undef TOML_CONST_GETTER
#undef TOML_CONST_INLINE_GETTER
#undef TOML_CONSTRAINED_TEMPLATE
#undef TOML_CPP
#undef TOML_DECLSPEC
#undef TOML_DELETE_DEFAULTS
#undef TOML_DISABLE_ARITHMETIC_WARNINGS
#undef TOML_DISABLE_CODE_ANALYSIS_WARNINGS
#undef TOML_DISABLE_SPAM_WARNINGS
#undef TOML_DISABLE_SPAM_WARNINGS_CLANG_10
#undef TOML_DISABLE_SPAM_WARNINGS_CLANG_11
#undef TOML_DISABLE_SUGGEST_ATTR_WARNINGS
#undef TOML_DISABLE_SWITCH_WARNINGS
#undef TOML_DISABLE_WARNINGS
#undef TOML_DOXYGEN
#undef TOML_EMPTY_BASES
#undef TOML_ENABLE_IF
#undef TOML_ENABLE_WARNINGS
#undef TOML_EVAL_BOOL_0
#undef TOML_EVAL_BOOL_1
#undef TOML_EXTERNAL_LINKAGE
#undef TOML_FLAGS_ENUM
#undef TOML_FLOAT_CHARCONV
#undef TOML_FLOAT128
#undef TOML_FLOAT16_DIG
#undef TOML_FLOAT16_LIMITS_SET
#undef TOML_FLOAT16_MANT_DIG
#undef TOML_FLOAT16_MAX_10_EXP
#undef TOML_FLOAT16_MAX_EXP
#undef TOML_FLOAT16_MIN_10_EXP
#undef TOML_FLOAT16_MIN_EXP
#undef TOML_GCC
#undef TOML_GCC_LIKE
#undef TOML_HAS_ATTR
#undef TOML_HAS_BUILTIN
#undef TOML_HAS_CHAR8
#undef TOML_HAS_CPP_ATTR
#undef TOML_HAS_CUSTOM_OPTIONAL_TYPE
#undef TOML_HAS_FEATURE
#undef TOML_HAS_INCLUDE
#undef TOML_HAS_SSE2
#undef TOML_HAS_SSE4_1
#undef TOML_HIDDEN_CONSTRAINT
#undef TOML_ICC
#undef TOML_ICC_CL
#undef TOML_IMPL_NAMESPACE_END
#undef TOML_IMPL_NAMESPACE_START
#undef TOML_IMPLEMENTATION
#undef TOML_INCLUDE_WINDOWS_H
#undef TOML_INLINE_GETTER
#undef TOML_INT_CHARCONV
#undef TOML_INT128
#undef TOML_INTELLISENSE
#undef TOML_INTERNAL_LINKAGE
#undef TOML_LANG_AT_LEAST
#undef TOML_LANG_EFFECTIVE_VERSION
#undef TOML_LANG_HIGHER_THAN
#undef TOML_LANG_UNRELEASED
#undef TOML_LAUNDER
#undef TOML_LIFETIME_HOOKS
#undef TOML_LIKELY
#undef TOML_LIKELY_CASE
#undef TOML_LINUX
#undef TOML_MAKE_FLAGS
#undef TOML_MAKE_FLAGS_
#undef TOML_MAKE_FLAGS_1
#undef TOML_MAKE_FLAGS_2
#undef TOML_MAKE_STRING
#undef TOML_MAKE_STRING_1
#undef TOML_MAKE_VERSION
#undef TOML_MSVC
#undef TOML_MSVC_LIKE
#undef TOML_NAMESPACE
#undef TOML_NEVER_INLINE
#undef TOML_NODISCARD
#undef TOML_NODISCARD_CTOR
#undef TOML_NVCC
#undef TOML_OPEN_ENUM
#undef TOML_OPEN_FLAGS_ENUM
#undef TOML_PARSER_TYPENAME
#undef TOML_POP_WARNINGS
#undef TOML_PRAGMA_CLANG
#undef TOML_PRAGMA_CLANG_GE_10
#undef TOML_PRAGMA_CLANG_GE_11
#undef TOML_PRAGMA_CLANG_GE_8
#undef TOML_PRAGMA_CLANG_GE_9
#undef TOML_PRAGMA_GCC
#undef TOML_PRAGMA_ICC
#undef TOML_PRAGMA_MSVC
#undef TOML_PURE
#undef TOML_PURE_GETTER
#undef TOML_PURE_INLINE_GETTER
#undef TOML_PUSH_WARNINGS
#undef TOML_REQUIRES
#undef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN
#undef TOML_RETURN_BOOL_FROM_FOR_EACH_BROKEN_MESSAGE
#undef TOML_SA_LIST_BEG
#undef TOML_SA_LIST_END
#undef TOML_SA_LIST_NEW
#undef TOML_SA_LIST_NXT
#undef TOML_SA_LIST_SEP
#undef TOML_SA_NATIVE_VALUE_TYPE_LIST
#undef TOML_SA_NEWLINE
#undef TOML_SA_NODE_TYPE_LIST
#undef TOML_SA_UNWRAPPED_NODE_TYPE_LIST
#undef TOML_SA_VALUE_EXACT_FUNC_MESSAGE
#undef TOML_SA_VALUE_FUNC_MESSAGE
#undef TOML_SA_VALUE_MESSAGE_CONST_CHAR8
#undef TOML_SA_VALUE_MESSAGE_U8STRING_VIEW
#undef TOML_SA_VALUE_MESSAGE_WSTRING
#undef TOML_SIMPLE_STATIC_ASSERT_MESSAGES
#undef TOML_TRIVIAL_ABI
#undef TOML_UINT128
#undef TOML_UNIX
#undef TOML_UNLIKELY
#undef TOML_UNLIKELY_CASE
#undef TOML_UNREACHABLE
#undef TOML_UNUSED
#undef TOML_WINDOWS
#endif
#endif // TOMLPLUSPLUS_HPP

21
src/lib/CMakeLists.txt Normal file
View File

@@ -0,0 +1,21 @@
SET(HDRS)
SET(SRCS)
SET(LIB_INCLUDE_PATH)
add_subdirectory(utility)
SET(HDRS
${HDRS}
PARENT_SCOPE
)
SET(SRCS
${SRCS}
PARENT_SCOPE
)
set(LIB_INCLUDE_PATH
${LIB_INCLUDE_PATH}
${CMAKE_CURRENT_SOURCE_DIR}
PARENT_SCOPE
)

View File

@@ -0,0 +1,21 @@
add_subdirectory(logging)
add_subdirectory(random)
SET(HDRS
${HDRS}
${CMAKE_CURRENT_SOURCE_DIR}/utilityRandom.h
PARENT_SCOPE
)
SET(SRCS
${SRCS}
${CMAKE_CURRENT_SOURCE_DIR}/utilityRandom.cpp
PARENT_SCOPE
)
SET(LIB_INCLUDE_PATH
${LIB_INCLUDE_PATH}
${CMAKE_CURRENT_SOURCE_DIR}
PARENT_SCOPE
)

View File

@@ -0,0 +1,25 @@
SET(HDRS
${HDRS}
${CMAKE_CURRENT_SOURCE_DIR}/ConsoleLogger.h
${CMAKE_CURRENT_SOURCE_DIR}/Logger.h
${CMAKE_CURRENT_SOURCE_DIR}/logging.h
${CMAKE_CURRENT_SOURCE_DIR}/LogManager.h
${CMAKE_CURRENT_SOURCE_DIR}/LogManagerImplementation.h
${CMAKE_CURRENT_SOURCE_DIR}/LogMessage.h
PARENT_SCOPE
)
SET(SRCS
${SRCS}
${CMAKE_CURRENT_SOURCE_DIR}/ConsoleLogger.cpp
${CMAKE_CURRENT_SOURCE_DIR}/Logger.cpp
${CMAKE_CURRENT_SOURCE_DIR}/LogManager.cpp
${CMAKE_CURRENT_SOURCE_DIR}/LogManagerImplementation.cpp
PARENT_SCOPE
)
set(LIB_INCLUDE_PATH
${LIB_INCLUDE_PATH}
${CMAKE_CURRENT_SOURCE_DIR}
PARENT_SCOPE
)

View File

@@ -0,0 +1,39 @@
#include "ConsoleLogger.h"
#include <iostream>
ConsoleLogger::ConsoleLogger()
: Logger("ConsoleLogger")
{
}
ConsoleLogger::~ConsoleLogger()
{
}
void ConsoleLogger::logInfo(const LogMessage& message)
{
logMessage("INFO", message);
}
void ConsoleLogger::logWarning(const LogMessage& message)
{
logMessage("WARNING", message);
}
void ConsoleLogger::logError(const LogMessage& message)
{
logMessage("ERROR", message);
}
void ConsoleLogger::logMessage(const std::string& type, const LogMessage& message)
{
std::cout << message.getTimeString("%H:%M:%S") << " | ";
if (message.filePath.size())
{
std::cout << message.getFileName() << ':' << message.line << ' ' << message.functionName << "() | ";
}
std::cout << type << ": " << message.message << std::endl;
}

View File

@@ -0,0 +1,21 @@
#ifndef CONSOLE_LOGGER_H
#define CONSOLE_LOGGER_H
#include "Logger.h"
#include "LogMessage.h"
class ConsoleLogger: public Logger
{
public:
ConsoleLogger();
~ConsoleLogger();
private:
virtual void logInfo(const LogMessage& message);
virtual void logWarning(const LogMessage& message);
virtual void logError(const LogMessage& message);
void logMessage(const std::string& type, const LogMessage& message);
};
#endif // CONSOLE_LOGGER_H

View File

@@ -0,0 +1,110 @@
#include "LogManager.h"
#include <algorithm>
#include "LogMessage.h"
#include "logging.h"
std::shared_ptr<LogManager> LogManager::getInstance()
{
if (s_instance.use_count() == 0)
{
s_instance = std::shared_ptr<LogManager>(new LogManager());
}
return s_instance;
}
void LogManager::destroyInstance()
{
s_instance.reset();
}
LogManager::~LogManager()
{
}
void LogManager::setLoggingEnabled(bool enabled)
{
m_loggingEnabled = enabled;
}
void LogManager::addLogger(std::shared_ptr<Logger> logger)
{
m_logManagerImplementation.addLogger(logger);
}
void LogManager::removeLogger(std::shared_ptr<Logger> logger)
{
m_logManagerImplementation.removeLogger(logger);
}
void LogManager::removeLoggersByType(const std::string& type)
{
m_logManagerImplementation.removeLoggersByType(type);
}
Logger* LogManager::getLogger(std::shared_ptr<Logger> logger)
{
return m_logManagerImplementation.getLogger(logger);
}
Logger* LogManager::getLoggerByType(const std::string& type)
{
return m_logManagerImplementation.getLoggerByType(type);
}
void LogManager::clearLoggers()
{
m_logManagerImplementation.clearLoggers();
}
int LogManager::getLoggerCount() const
{
return m_logManagerImplementation.getLoggerCount();
}
void LogManager::logInfo(
const std::string& message,
const std::string& file,
const std::string& function,
const unsigned int line
)
{
if (m_loggingEnabled)
{
m_logManagerImplementation.logInfo(message, file, function, line);
}
}
void LogManager::logWarning(
const std::string& message,
const std::string& file,
const std::string& function,
const unsigned int line
)
{
if (m_loggingEnabled)
{
m_logManagerImplementation.logWarning(message, file, function, line);
}
}
void LogManager::logError(
const std::string& message,
const std::string& file,
const std::string& function,
const unsigned int line
)
{
if (m_loggingEnabled)
{
m_logManagerImplementation.logError(message, file, function, line);
}
}
std::shared_ptr<LogManager> LogManager::s_instance;
LogManager::LogManager()
: m_loggingEnabled(false)
{
}

View File

@@ -0,0 +1,57 @@
#ifndef LOG_MANAGER_H
#define LOG_MANAGER_H
#include <memory>
#include "Logger.h"
#include "LogManagerImplementation.h"
class LogManager
{
public:
static std::shared_ptr<LogManager> getInstance();
static void destroyInstance();
~LogManager();
void setLoggingEnabled(bool enabled);
void addLogger(std::shared_ptr<Logger> logger);
void removeLogger(std::shared_ptr<Logger> logger);
void removeLoggersByType(const std::string& type);
void clearLoggers();
int getLoggerCount() const;
Logger* getLoggerByType(const std::string& type);
Logger* getLogger(std::shared_ptr<Logger> logger);
void logInfo(
const std::string& message,
const std::string& file,
const std::string& function,
const unsigned int line
);
void logWarning(
const std::string& message,
const std::string& file,
const std::string& function,
const unsigned int line
);
void logError(
const std::string& message,
const std::string& file,
const std::string& function,
const unsigned int line
);
private:
static std::shared_ptr<LogManager> s_instance;
LogManager();
LogManager(const LogManager&);
void operator=(const LogManager&);
LogManagerImplementation m_logManagerImplementation;
bool m_loggingEnabled;
};
#endif // LOG_MANAGER_H

View File

@@ -0,0 +1,136 @@
#include "LogManagerImplementation.h"
#include <algorithm>
LogManagerImplementation::LogManagerImplementation()
{
}
LogManagerImplementation::LogManagerImplementation(const LogManagerImplementation& other)
{
m_loggers = other.m_loggers;
}
void LogManagerImplementation::operator=(const LogManagerImplementation& other)
{
m_loggers = other.m_loggers;
}
LogManagerImplementation::~LogManagerImplementation()
{
}
void LogManagerImplementation::addLogger(std::shared_ptr<Logger> logger)
{
std::lock_guard<std::mutex> lockGuard(m_loggerMutex);
m_loggers.push_back(logger);
}
void LogManagerImplementation::removeLogger(std::shared_ptr<Logger> logger)
{
std::lock_guard<std::mutex> lockGuard(m_loggerMutex);
std::vector<std::shared_ptr<Logger>>::iterator it = std::find(m_loggers.begin(), m_loggers.end(), logger);
if (it != m_loggers.end())
{
m_loggers.erase(it);
}
}
void LogManagerImplementation::removeLoggersByType(const std::string& type)
{
std::lock_guard<std::mutex> lockGuard(m_loggerMutex);
for (unsigned int i = 0; i < m_loggers.size(); i++)
{
if (m_loggers[i]->getType() == type)
{
m_loggers.erase(m_loggers.begin() + i);
i--;
}
}
}
Logger* LogManagerImplementation::getLogger(std::shared_ptr<Logger> logger)
{
std::lock_guard<std::mutex> lockGuard(m_loggerMutex);
std::vector<std::shared_ptr<Logger>>::iterator it = std::find(m_loggers.begin(), m_loggers.end(), logger);
if (it != m_loggers.end())
{
return (*it).get();
}
return nullptr;
}
Logger* LogManagerImplementation::getLoggerByType(const std::string& type)
{
std::lock_guard<std::mutex> lockGuard(m_loggerMutex);
for (unsigned int i = 0; i < m_loggers.size(); i++)
{
if (m_loggers[i]->getType() == type)
{
return m_loggers[i].get();
}
}
return nullptr;
}
void LogManagerImplementation::clearLoggers()
{
m_loggers.clear();
}
int LogManagerImplementation::getLoggerCount() const
{
std::lock_guard<std::mutex> lockGuard(m_loggerMutex);
return m_loggers.size();
}
void LogManagerImplementation::logInfo(
const std::string& message,
const std::string& file,
const std::string& function,
const unsigned int line
)
{
std::lock_guard<std::mutex> lockGuardLogger(m_loggerMutex);
for (unsigned int i = 0; i < m_loggers.size(); i++)
{
m_loggers[i]->onInfo(LogMessage(message, file, function, line, getTime(), std::this_thread::get_id()));
}
}
void LogManagerImplementation::logWarning(
const std::string& message,
const std::string& file,
const std::string& function,
const unsigned int line
)
{
std::lock_guard<std::mutex> lockGuardLogger(m_loggerMutex);
for (unsigned int i = 0; i < m_loggers.size(); i++)
{
m_loggers[i]->onWarning(LogMessage(message, file, function, line, getTime(), std::this_thread::get_id()));
}
}
void LogManagerImplementation::logError(
const std::string& message,
const std::string& file,
const std::string& function,
const unsigned int line
)
{
std::lock_guard<std::mutex> lockGuardLogger(m_loggerMutex);
for (unsigned int i = 0; i < m_loggers.size(); i++)
{
m_loggers[i]->onError(LogMessage(message, file, function, line, getTime(), std::this_thread::get_id()));
}
}
tm LogManagerImplementation::getTime()
{
time_t time;
std::time(&time);
tm result = *std::localtime(&time); // this is done because localtime returns a pointer to a statically allocated object
return result;
}

View File

@@ -0,0 +1,59 @@
#ifndef LOG_MANAGER_IMPLEMENTATION_H
#define LOG_MANAGER_IMPLEMENTATION_H
#include <algorithm>
#include <memory>
#include <mutex>
#include <vector>
#include "Logger.h"
class LogManagerImplementation
{
public:
LogManagerImplementation();
// Must be implemented because std::mutex is non-copyable, see
// http://stackoverflow.com/questions/14263836/why-does-stdmutex-create-a-c2248-when-used-in-a-struct-with-windows-socket
// for more details
LogManagerImplementation(const LogManagerImplementation& other);
void operator=(const LogManagerImplementation& other);
~LogManagerImplementation();
void addLogger(std::shared_ptr<Logger> logger);
void removeLogger(std::shared_ptr<Logger> logger);
void removeLoggersByType(const std::string& type);
void clearLoggers();
int getLoggerCount() const;
Logger* getLogger(std::shared_ptr<Logger> logger);
Logger* getLoggerByType(const std::string& type);
void logInfo(
const std::string& message,
const std::string& file,
const std::string& function,
const unsigned int line
);
void logWarning(
const std::string& message,
const std::string& file,
const std::string& function,
const unsigned int line
);
void logError(
const std::string& message,
const std::string& file,
const std::string& function,
const unsigned int line
);
private:
tm getTime();
std::vector<std::shared_ptr<Logger> > m_loggers;
mutable std::mutex m_loggerMutex;
};
#endif // LOG_MANAGER_IMPLEMENTATION_H

View File

@@ -0,0 +1,48 @@
#ifndef LOG_MESSAGE_H
#define LOG_MESSAGE_H
#include <ctime>
#include <string>
#include <thread>
struct LogMessage
{
public:
LogMessage(
const std::string& message,
const std::string& filePath,
const std::string& functionName,
const unsigned int line,
const std::tm& time,
const std::thread::id& threadId
)
: message(message)
, filePath(filePath)
, functionName(functionName)
, line(line)
, time(time)
, threadId(threadId)
{}
std::string getTimeString(const std::string& format) const
{
char timeString[50];
strftime(timeString, 50, format.c_str(), &time);
std::string temp(timeString);
return std::string(temp.begin(), temp.end());
}
std::string getFileName() const
{
return filePath.substr(filePath.find_last_of("/\\") + 1);
}
const std::string message;
const std::string filePath;
const std::string functionName;
const unsigned int line;
const std::tm time;
const std::thread::id threadId;
};
#endif // LOG_MESSAGE_H

View File

@@ -0,0 +1,55 @@
#include "Logger.h"
Logger::Logger(const std::string& type)
: m_type(type)
, m_levelMask(LOG_ALL)
{
}
Logger::~Logger()
{
}
std::string Logger::getType() const
{
return m_type;
}
Logger::LogLevelMask Logger::getLogLevel() const
{
return m_levelMask;
}
void Logger::setLogLevel(LogLevelMask mask)
{
m_levelMask = mask;
}
bool Logger::isLogLevel(LogLevelMask mask)
{
return (m_levelMask & mask) > 0;
}
void Logger::onInfo(const LogMessage& message)
{
if (isLogLevel(LOG_INFOS))
{
logInfo(message);
}
}
void Logger::onWarning(const LogMessage& message)
{
if (isLogLevel(LOG_WARNINGS))
{
logWarning(message);
}
}
void Logger::onError(const LogMessage& message)
{
if (isLogLevel(LOG_ERRORS))
{
logError(message);
}
}

View File

@@ -0,0 +1,43 @@
#ifndef LOGGER_H
#define LOGGER_H
#include <memory>
#include <vector>
#include "LogMessage.h"
class Logger
{
public:
typedef int LogLevelMask;
enum LogLevel : int
{
LOG_INFOS = 0x1,
LOG_WARNINGS = 0x2,
LOG_ERRORS = 0x4,
LOG_ALL = 0x7
};
Logger(const std::string& type);
virtual ~Logger();
std::string getType() const;
LogLevelMask getLogLevel() const;
void setLogLevel(LogLevelMask mask);
bool isLogLevel(LogLevelMask mask);
void onInfo(const LogMessage& message);
void onWarning(const LogMessage& message);
void onError(const LogMessage& message);
private:
virtual void logInfo(const LogMessage& message) = 0;
virtual void logWarning(const LogMessage& message) = 0;
virtual void logError(const LogMessage& message) = 0;
const std::string m_type;
LogLevelMask m_levelMask;
};
#endif // LOGGER_H

View File

@@ -0,0 +1,86 @@
#ifndef LOGGING_H
#define LOGGING_H
#include <sstream>
#include "LogManager.h"
/**
* @brief Makros to simplify usage of the log manager
*/
#define LOG_INFO(__str__) \
do \
{ \
LogManager::getInstance()->logInfo(__str__, __FILE__, __FUNCTION__, __LINE__); \
} \
while(0)
#define LOG_WARNING(__str__) \
do \
{ \
LogManager::getInstance()->logWarning(__str__, __FILE__, __FUNCTION__, __LINE__); \
} \
while(0)
#define LOG_ERROR(__str__) \
do \
{ \
LogManager::getInstance()->logError(__str__, __FILE__, __FUNCTION__, __LINE__); \
} \
while(0)
#define LOG_INFO_STREAM(__s__) \
do \
{ \
std::stringstream __ss__; \
__ss__ __s__; \
LogManager::getInstance()->logInfo(__ss__.str(), __FILE__, __FUNCTION__, __LINE__); \
} \
while(0)
#define LOG_WARNING_STREAM(__s__) \
do \
{ \
std::stringstream __ss__; \
__ss__ __s__; \
LogManager::getInstance()->logWarning(__ss__.str(), __FILE__, __FUNCTION__, __LINE__); \
} \
while(0)
#define LOG_ERROR_STREAM(__s__) \
do \
{ \
std::stringstream __ss__; \
__ss__ __s__; \
LogManager::getInstance()->logError(__ss__.str(), __FILE__, __FUNCTION__, __LINE__); \
} \
while(0)
#define LOG_INFO_STREAM_BARE(__s__) \
do \
{ \
std::stringstream __ss__; \
__ss__ __s__; \
LogManager::getInstance()->logInfo(__ss__.str(), "", "", 0); \
} \
while(0)
#define LOG_WARNING_STREAM_BARE(__s__) \
do \
{ \
std::stringstream __ss__; \
__ss__ __s__; \
LogManager::getInstance()->logWarning(__ss__.str(), "", "", 0); \
} \
while(0)
#define LOG_ERROR_STREAM_BARE(__s__) \
do \
{ \
std::stringstream __ss__; \
__ss__ __s__; \
LogManager::getInstance()->logError(__ss__.str(), "", "", 0); \
} \
while(0)
#endif // LOGGING_H

View File

@@ -0,0 +1,20 @@
SET(HDRS
${HDRS}
${CMAKE_CURRENT_SOURCE_DIR}/RandomNumberGenerator.h
${CMAKE_CURRENT_SOURCE_DIR}/WeightedRandomGenerator.h
${CMAKE_CURRENT_SOURCE_DIR}/RandomBinaryFunction.h
PARENT_SCOPE
)
SET(SRCS
${SRCS}
${CMAKE_CURRENT_SOURCE_DIR}/RandomNumberGenerator.cpp
${CMAKE_CURRENT_SOURCE_DIR}/RandomBinaryFunction.cpp
PARENT_SCOPE
)
set(LIB_INCLUDE_PATH
${LIB_INCLUDE_PATH}
${CMAKE_CURRENT_SOURCE_DIR}
PARENT_SCOPE
)

View File

@@ -0,0 +1,29 @@
#include "RandomBinaryFunction.h"
#include "utilityRandom.h"
RandomBinaryFunction::RandomBinaryFunction(float resolution_s, float stateChangeProbability)
: m_resolution_s(resolution_s)
, m_stateChangeProbability(stateChangeProbability)
, m_passedTime_s(0.0f)
, m_value(utility::getRandomBool())
{
}
void RandomBinaryFunction::update(float deltaTime_s)
{
m_passedTime_s += deltaTime_s;
while (m_passedTime_s >= m_resolution_s)
{
m_passedTime_s -= m_resolution_s;
if (utility::getRandomFloat() >= m_stateChangeProbability)
{
m_value = !m_value;
}
}
}
bool RandomBinaryFunction::getValue() const
{
return m_value;
}

View File

@@ -0,0 +1,19 @@
#ifndef RANDOM_BINARY_FUNCTION_H
#define RANDOM_BINARY_FUNCTION_H
class RandomBinaryFunction
{
public:
RandomBinaryFunction(float resolution_s, float stateChangeProbability);
void update(float deltaTime_s);
bool getValue() const;
private:
const float m_resolution_s;
const float m_stateChangeProbability;
float m_passedTime_s;
bool m_value;
};
#endif // RANDOM_BINARY_FUNCTION_H

View File

@@ -0,0 +1,68 @@
#include "RandomNumberGenerator.h"
#include <cstdlib>
#include <ctime>
namespace
{
int randInt()
{
static bool initialized = false;
if (!initialized)
{
std::srand(std::time(nullptr));
initialized = true;
}
return std::rand();
}
}
RandomNumberGenerator::RandomNumberGenerator(unsigned int seed):
m_seed(seed),
m_value(seed),
m_a(214013),
m_b(2531011),
m_m(2147483647)
{
}
void RandomNumberGenerator::setSeed(unsigned int seed)
{
m_seed = seed;
reset();
}
void RandomNumberGenerator::reset()
{
m_value = m_seed;
}
int RandomNumberGenerator::getInt(int min, int max)
{
return min + (randInt() % (max - min + 1));
//return min + (getNext() % (max - min + 1));
}
unsigned int RandomNumberGenerator::getUnsignedInt(unsigned int min, unsigned int max)
{
return min + (randInt() % (max - min + 1));
//return min + (getNext() % (max - min + 1));
}
float RandomNumberGenerator::getFloat(float min, float max)
{
const int resolution = RAND_MAX;
return min + (max - min) * (static_cast<float>(randInt() % (resolution + 1)) / resolution);
//return min + float(getNext()) / m_m * (max - min);
}
bool RandomNumberGenerator::getBool()
{
return (randInt() % 2);
//return (getFloat(0.0f, 1.0f) < 0.5f ? true : false);
}
int RandomNumberGenerator::getNext()
{
return m_value = (m_a * m_value + m_b) % m_m;
}

View File

@@ -0,0 +1,27 @@
#ifndef RANDOM_NUMBER_GENERATOR_H
#define RANDOM_NUMBER_GENERATOR_H
class RandomNumberGenerator
{
public:
RandomNumberGenerator(unsigned int seed);
void setSeed(unsigned int seed);
void reset();
int getInt(int min, int max);
unsigned int getUnsignedInt(unsigned int min, unsigned int max);
float getFloat(float min = 0.0f, float max = 1.0f);
bool getBool();
private:
int getNext();
unsigned int m_seed;
unsigned int m_value;
unsigned int m_a;
unsigned int m_b;
unsigned int m_m;
};
#endif // RANDOM_NUMBER_GENERATOR_H

View File

@@ -0,0 +1,133 @@
#ifndef WEIGHTED_RANDOM_GENERATOR_H
#define WEIGHTED_RANDOM_GENERATOR_H
#include <vector>
#include "logging.h"
#include "RandomNumberGenerator.h"
template <typename T>
class WeightedRandomGenerator
{
public:
WeightedRandomGenerator(unsigned int seed);
void setSeed(unsigned int seed);
void reset();
bool hasResult(T value) const;
bool hasResults() const;
void addResult(T value, float weight);
T getResult();
std::vector<T> getResults(int count, bool allowDuplicates);
private:
RandomNumberGenerator m_randomGenerator;
std::vector<std::pair<T, float>> m_results;
};
template <typename T>
WeightedRandomGenerator<T>::WeightedRandomGenerator(unsigned int seed):
m_randomGenerator(seed)
{
}
template <typename T>
void WeightedRandomGenerator<T>::setSeed(unsigned int seed)
{
m_randomGenerator.setSeed(seed);
}
template <typename T>
void WeightedRandomGenerator<T>::reset()
{
m_randomGenerator.reset();
}
template <typename T>
bool WeightedRandomGenerator<T>::hasResult(T value) const
{
for (auto[v, p] : m_results)
{
if (v == value)
{
return true;
}
}
return false;
}
template <typename T>
bool WeightedRandomGenerator<T>::hasResults() const
{
return !m_results.empty();
}
template <typename T>
void WeightedRandomGenerator<T>::addResult(T value, float weight)
{
m_results.push_back(std::make_pair(value, weight));
}
template <typename T>
T WeightedRandomGenerator<T>::getResult()
{
float summedWeights = 0;
for (int i = 0; i < m_results.size(); i++)
summedWeights += m_results[i].second;
float random = m_randomGenerator.getFloat(0.0f, summedWeights);
int index = 0;
float weights = 0.0f;
for (index = 0; index < m_results.size(); index++)
{
weights += m_results[index].second;
if (weights >= random)
break;
}
return m_results[index].first;
}
template <typename T>
std::vector<T> WeightedRandomGenerator<T>::getResults(int count, bool allowDuplicates)
{
if (!allowDuplicates && count > m_results.size())
{
LOG_WARNING("WeightedRandomGenerator has only " + std::to_string(m_results.size()) + " results. Unable to prevent duplicates for " + std::to_string(count) + " requested results.");
allowDuplicates = true;
}
std::vector<std::pair<T, float>> potentialResults = m_results;
std::vector<T> results;
float summedWeights = 0;
for (int i = 0; i < potentialResults.size(); i++)
{
summedWeights += potentialResults[i].second;
}
for (int i = 0; i < count; i++)
{
float random = m_randomGenerator.getFloat(0.0f, summedWeights);
int index = 0;
float weights = 0.0f;
for (index = 0; index < potentialResults.size() - 1; index++)
{
weights += potentialResults[index].second;
if (weights > random)
break;
}
results.push_back(potentialResults[index].first);
summedWeights -= potentialResults[index].second;
potentialResults.erase(potentialResults.begin() + index);
}
return results;
}
#endif // WEIGHTED_RANDOM_GENERATOR_H

View File

@@ -0,0 +1,24 @@
#include "RandomNumberGenerator.h"
namespace
{
RandomNumberGenerator rng(0);
}
namespace utility
{
int getRandomInt(int min, int max)
{
return rng.getInt(min, max);
}
float getRandomFloat(float min = 0.0f, float max = 1.0f)
{
return rng.getFloat(min, max);
}
bool getRandomBool()
{
return rng.getBool();
}
}

View File

@@ -0,0 +1,11 @@
#ifndef UTILITY_RANDOM_H
#define UTILITY_RANDOM_H
namespace utility
{
int getRandomInt(int min, int max);
float getRandomFloat(float min = 0.0f, float max = 1.0f);
bool getRandomBool();
}
#endif // UTILITY_RANDOM_H

6
src/test/CMakeLists.txt Normal file
View File

@@ -0,0 +1,6 @@
add_files(
TEST_FILES
test.cpp
)

3
src/test/test.cpp Normal file
View File

@@ -0,0 +1,3 @@
#define CATCH_CONFIG_MAIN // This tells Catch to provide a main() function
#include "catch/catch.hpp"