a new beginning
Signed-off-by: Folling <mail@folling.io>
This commit is contained in:
commit
8eb2067318
25 changed files with 1718 additions and 0 deletions
222
.clang-format
Normal file
222
.clang-format
Normal file
|
|
@ -0,0 +1,222 @@
|
||||||
|
BasedOnStyle: Google
|
||||||
|
|
||||||
|
AccessModifierOffset: -4
|
||||||
|
|
||||||
|
AlignAfterOpenBracket: BlockIndent
|
||||||
|
AlignArrayOfStructures: Right
|
||||||
|
AlignConsecutiveAssignments:
|
||||||
|
Enabled: false
|
||||||
|
AlignConsecutiveBitFields:
|
||||||
|
Enabled: false
|
||||||
|
AlignConsecutiveDeclarations:
|
||||||
|
Enabled: false
|
||||||
|
AlignConsecutiveMacros: AcrossEmptyLines
|
||||||
|
AlignEscapedNewlines: Left
|
||||||
|
AlignOperands: Align
|
||||||
|
AlignTrailingComments: true
|
||||||
|
|
||||||
|
AllowAllArgumentsOnNextLine: true
|
||||||
|
AllowAllParametersOfDeclarationOnNextLine: true
|
||||||
|
AllowShortBlocksOnASingleLine: Empty
|
||||||
|
AllowShortCaseLabelsOnASingleLine: true
|
||||||
|
AllowShortEnumsOnASingleLine: true
|
||||||
|
AllowShortFunctionsOnASingleLine: Empty
|
||||||
|
AllowShortIfStatementsOnASingleLine: WithoutElse
|
||||||
|
AllowShortLambdasOnASingleLine: All
|
||||||
|
AllowShortLoopsOnASingleLine: true
|
||||||
|
|
||||||
|
AlwaysBreakAfterReturnType: None
|
||||||
|
AlwaysBreakBeforeMultilineStrings: true
|
||||||
|
AlwaysBreakTemplateDeclarations: Yes
|
||||||
|
|
||||||
|
BinPackArguments: false
|
||||||
|
BinPackParameters: false
|
||||||
|
|
||||||
|
BitFieldColonSpacing: Both
|
||||||
|
|
||||||
|
BraceWrapping:
|
||||||
|
BeforeCatch: false
|
||||||
|
BeforeElse: false
|
||||||
|
BeforeLambdaBody: false
|
||||||
|
BeforeWhile: false
|
||||||
|
AfterCaseLabel: false
|
||||||
|
AfterClass: false
|
||||||
|
AfterControlStatement: MultiLine
|
||||||
|
AfterEnum: false
|
||||||
|
AfterExternBlock: false
|
||||||
|
AfterFunction: false
|
||||||
|
AfterNamespace: false
|
||||||
|
AfterObjCDeclaration: false
|
||||||
|
AfterStruct: false
|
||||||
|
AfterUnion: false
|
||||||
|
IndentBraces: false
|
||||||
|
SplitEmptyFunction: false
|
||||||
|
SplitEmptyNamespace: false
|
||||||
|
SplitEmptyRecord: false
|
||||||
|
|
||||||
|
BreakAfterAttributes: Never
|
||||||
|
BreakBeforeBinaryOperators: None
|
||||||
|
BreakBeforeBraces: Attach
|
||||||
|
BreakBeforeConceptDeclarations: Always
|
||||||
|
# BreakBeforeInlineASMColon: OnlyMultiline
|
||||||
|
BreakBeforeTernaryOperators: false
|
||||||
|
BreakConstructorInitializers: AfterColon
|
||||||
|
BreakInheritanceList: AfterColon
|
||||||
|
BreakStringLiterals: false
|
||||||
|
|
||||||
|
ColumnLimit: 128
|
||||||
|
|
||||||
|
CompactNamespaces: false
|
||||||
|
ConstructorInitializerIndentWidth: 4
|
||||||
|
ContinuationIndentWidth: 4
|
||||||
|
|
||||||
|
Cpp11BracedListStyle: true
|
||||||
|
|
||||||
|
DerivePointerAlignment: false
|
||||||
|
|
||||||
|
EmptyLineAfterAccessModifier: Never
|
||||||
|
EmptyLineBeforeAccessModifier: Always
|
||||||
|
|
||||||
|
FixNamespaceComments: false
|
||||||
|
|
||||||
|
IncludeBlocks: Regroup
|
||||||
|
IncludeCategories:
|
||||||
|
# Relative Includes
|
||||||
|
# "blubb.h" / "blubb/blubber.h"
|
||||||
|
- Regex: '^".+\.(h|hpp)"$'
|
||||||
|
Priority: 1
|
||||||
|
|
||||||
|
# C Includes
|
||||||
|
# <string.h>
|
||||||
|
- Regex: '^<[a-z0-9_]+\.h>$'
|
||||||
|
Priority: 2
|
||||||
|
|
||||||
|
# C++ Includes
|
||||||
|
# <string>
|
||||||
|
- Regex: '^<[a-z0-9_]+>$'
|
||||||
|
Priority: 3
|
||||||
|
|
||||||
|
# expected
|
||||||
|
# <expected/ranges.hpp>
|
||||||
|
- Regex: '^<expected/.*>$'
|
||||||
|
Priority: 4
|
||||||
|
|
||||||
|
# libfmt
|
||||||
|
# <fmt/core.hpp>
|
||||||
|
- Regex: '^<fmt/.*>$'
|
||||||
|
Priority: 5
|
||||||
|
|
||||||
|
# nlohmann::json
|
||||||
|
# <nlohmann/json.hpp>
|
||||||
|
- Regex: '^<nlohmann/.*>$'
|
||||||
|
Priority: 6
|
||||||
|
|
||||||
|
# ranges
|
||||||
|
# <range-v3/ranges.hpp>
|
||||||
|
- Regex: '^<range-v3/.*>$'
|
||||||
|
Priority: 7
|
||||||
|
|
||||||
|
# ICU
|
||||||
|
# <unicode/ranges.hpp>
|
||||||
|
- Regex: '^<unicode/.*>$'
|
||||||
|
Priority: 8
|
||||||
|
|
||||||
|
# ranges
|
||||||
|
# <range-v3/ranges.hpp>
|
||||||
|
- Regex: '^<cppbase/.*>$'
|
||||||
|
Priority: 9
|
||||||
|
|
||||||
|
# ranges
|
||||||
|
# <range-v3/ranges.hpp>
|
||||||
|
- Regex: '^<sqlitecpp/.*>$'
|
||||||
|
Priority: 10
|
||||||
|
|
||||||
|
# ranges
|
||||||
|
# <range-v3/ranges.hpp>
|
||||||
|
- Regex: '^<ikarus/.*>$'
|
||||||
|
Priority: 11
|
||||||
|
|
||||||
|
# ranges
|
||||||
|
# <range-v3/ranges.hpp>
|
||||||
|
- Regex: '^<generated/.*>$'
|
||||||
|
Priority: 12
|
||||||
|
|
||||||
|
# ranges
|
||||||
|
# ranges
|
||||||
|
# <range-v3/ranges.hpp>
|
||||||
|
- Regex: '^<impl/.*>$'
|
||||||
|
Priority: 13
|
||||||
|
|
||||||
|
IndentAccessModifiers: false
|
||||||
|
IndentCaseBlocks: false
|
||||||
|
IndentCaseLabels: false
|
||||||
|
IndentExternBlock: NoIndent
|
||||||
|
IndentGotoLabels: true
|
||||||
|
IndentPPDirectives: None
|
||||||
|
IndentRequiresClause: true
|
||||||
|
IndentWidth: 4
|
||||||
|
IndentWrappedFunctionNames: false
|
||||||
|
InsertBraces: true
|
||||||
|
InsertNewlineAtEOF: true
|
||||||
|
|
||||||
|
# InsertNewlineAtEOF: true
|
||||||
|
# IntegerLiteralSeparator:
|
||||||
|
# Binary: 0
|
||||||
|
# Decimal: 3
|
||||||
|
# Hex: -1
|
||||||
|
|
||||||
|
KeepEmptyLinesAtTheStartOfBlocks: false
|
||||||
|
|
||||||
|
LambdaBodyIndentation: Signature
|
||||||
|
Language: Cpp
|
||||||
|
|
||||||
|
# LineEnding: LF
|
||||||
|
|
||||||
|
MaxEmptyLinesToKeep: 1
|
||||||
|
|
||||||
|
NamespaceIndentation: None
|
||||||
|
|
||||||
|
PackConstructorInitializers: Never
|
||||||
|
|
||||||
|
PointerAlignment: Middle
|
||||||
|
QualifierAlignment: Right
|
||||||
|
# QualifierOrder: [ 'friend', 'constexpr', 'inline', 'static', 'type', 'const', 'volatile' ]
|
||||||
|
ReferenceAlignment: Left
|
||||||
|
|
||||||
|
ReflowComments: true
|
||||||
|
# RemoveSemicolon: true
|
||||||
|
|
||||||
|
RequiresClausePosition: OwnLine
|
||||||
|
# RequiresExpressionIndentation: OuterScope
|
||||||
|
|
||||||
|
SeparateDefinitionBlocks: Always
|
||||||
|
|
||||||
|
SortIncludes: CaseInsensitive
|
||||||
|
SortUsingDeclarations: true
|
||||||
|
|
||||||
|
SpaceAfterCStyleCast: false
|
||||||
|
SpaceAfterLogicalNot: false
|
||||||
|
SpaceAfterTemplateKeyword: false
|
||||||
|
|
||||||
|
SpaceBeforeAssignmentOperators: true
|
||||||
|
SpaceBeforeCpp11BracedList: false
|
||||||
|
SpaceBeforeCtorInitializerColon: false
|
||||||
|
SpaceBeforeInheritanceColon: true
|
||||||
|
SpaceBeforeParens: ControlStatements
|
||||||
|
SpaceBeforeRangeBasedForLoopColon: true
|
||||||
|
SpaceBeforeSquareBrackets: false
|
||||||
|
SpaceInEmptyBlock: false
|
||||||
|
SpaceInEmptyParentheses: false
|
||||||
|
SpacesInAngles: false
|
||||||
|
SpacesInCStyleCastParentheses: false
|
||||||
|
SpacesInConditionalStatement: false
|
||||||
|
SpacesInContainerLiterals: false
|
||||||
|
SpacesInLineCommentPrefix:
|
||||||
|
Minimum: 1
|
||||||
|
Maximum: 1
|
||||||
|
SpacesInParentheses: false
|
||||||
|
SpacesInSquareBrackets: false
|
||||||
|
Standard: c++20
|
||||||
|
|
||||||
|
TabWidth: 4
|
||||||
|
UseTab: Never
|
||||||
58
.gitignore
vendored
Normal file
58
.gitignore
vendored
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
# C++
|
||||||
|
# Prerequisites
|
||||||
|
*.d
|
||||||
|
|
||||||
|
# Compiled Object files
|
||||||
|
*.slo
|
||||||
|
*.lo
|
||||||
|
*.o
|
||||||
|
*.obj
|
||||||
|
|
||||||
|
# Precompiled Headers
|
||||||
|
*.gch
|
||||||
|
*.pch
|
||||||
|
|
||||||
|
# Compiled Dynamic libraries
|
||||||
|
*.so
|
||||||
|
*.dylib
|
||||||
|
*.dll
|
||||||
|
|
||||||
|
# Fortran module files
|
||||||
|
*.mod
|
||||||
|
*.smod
|
||||||
|
|
||||||
|
# Compiled Static libraries
|
||||||
|
*.lai
|
||||||
|
*.la
|
||||||
|
*.a
|
||||||
|
*.lib
|
||||||
|
|
||||||
|
# Executables
|
||||||
|
*.exe
|
||||||
|
*.out
|
||||||
|
*.app
|
||||||
|
|
||||||
|
### CMake ###
|
||||||
|
CMakeLists.txt.user
|
||||||
|
CMakeCache.txt
|
||||||
|
CMakeFiles
|
||||||
|
CMakeScripts
|
||||||
|
Testing
|
||||||
|
Makefile
|
||||||
|
cmake_install.cmake
|
||||||
|
install_manifest.txt
|
||||||
|
compile_commands.json
|
||||||
|
CTestTestfile.cmake
|
||||||
|
_deps
|
||||||
|
|
||||||
|
### CMake Patch ###
|
||||||
|
# External projects
|
||||||
|
*-prefix/
|
||||||
|
|
||||||
|
build
|
||||||
|
docs/generated
|
||||||
|
gen/script_old/target
|
||||||
|
include/ikarus/entities
|
||||||
|
include/ikarus/project.h
|
||||||
|
src/generated/**/*.cpp
|
||||||
|
src/generated/**/*.hpp
|
||||||
9
.gitmodules
vendored
Normal file
9
.gitmodules
vendored
Normal file
|
|
@ -0,0 +1,9 @@
|
||||||
|
[submodule "vendor/catch2"]
|
||||||
|
path = vendor/catch2
|
||||||
|
url = git@github.com:catchorg/Catch2.git
|
||||||
|
[submodule "vendor/sqlitecpp"]
|
||||||
|
path = vendor/sqlitecpp
|
||||||
|
url = ssh://git@git.rewritesarebliss.com:16658/Folling/sqlitecpp.git
|
||||||
|
[submodule "vendor/doxygen-awesome-css"]
|
||||||
|
path = vendor/doxygen-awesome-css
|
||||||
|
url = git@github.com:jothepro/doxygen-awesome-css.git
|
||||||
55
CMakeLists.txt
Normal file
55
CMakeLists.txt
Normal file
|
|
@ -0,0 +1,55 @@
|
||||||
|
cmake_minimum_required(VERSION 3.18)
|
||||||
|
project(ikarus)
|
||||||
|
|
||||||
|
set(CMAKE_CXX_STANDARD_REQUIRED ON)
|
||||||
|
set(CMAKE_CXX_STANDARD 20)
|
||||||
|
|
||||||
|
set(CMAKE_POSITION_INDEPENDENT_CODE TRUE)
|
||||||
|
|
||||||
|
add_subdirectory(vendor)
|
||||||
|
add_subdirectory(include)
|
||||||
|
add_subdirectory(src)
|
||||||
|
|
||||||
|
add_library(
|
||||||
|
libikarus OBJECT
|
||||||
|
${INCLUDE_FILES}
|
||||||
|
${SOURCE_FILES}
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(
|
||||||
|
libikarus PUBLIC
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/include
|
||||||
|
)
|
||||||
|
|
||||||
|
target_include_directories(
|
||||||
|
libikarus PRIVATE
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/src
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
libikarus PUBLIC
|
||||||
|
Catch2::Catch2WithMain
|
||||||
|
)
|
||||||
|
|
||||||
|
target_link_libraries(
|
||||||
|
libikarus PRIVATE
|
||||||
|
cppbase
|
||||||
|
sqlitecpp
|
||||||
|
)
|
||||||
|
|
||||||
|
set_target_properties(
|
||||||
|
libikarus PROPERTIES
|
||||||
|
LINKER_LANGUAGE CXX
|
||||||
|
)
|
||||||
|
|
||||||
|
add_executable(ikarus_tests ${SOURCE_FILES})
|
||||||
|
target_link_libraries(ikarus_tests PRIVATE Catch2::Catch2WithMain)
|
||||||
|
|
||||||
|
target_include_directories(
|
||||||
|
ikarus_tests PUBLIC
|
||||||
|
${CMAKE_CURRENT_LIST_DIR}/include
|
||||||
|
)
|
||||||
|
|
||||||
|
include(CTest)
|
||||||
|
include(vendor/catch2/extras/Catch.cmake)
|
||||||
|
catch_discover_tests(ikarus_tests)
|
||||||
11
README.md
Normal file
11
README.md
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
### Data Longevity
|
||||||
|
|
||||||
|
All data returned by libikarus is ephemeral and only represents the state of the project at the time of the request.
|
||||||
|
A snapshot if you will.
|
||||||
|
One must not rely on it representing the actual state of the project at any given time. The data is simply copied
|
||||||
|
from the underlying data sources and returned to the caller.
|
||||||
|
|
||||||
|
No mechanisms are provided to avoid race conditions. LibIkarus itself should only be used in a single-threaded context.
|
||||||
|
However, nothing breaks if you do use it in a multithreaded context, that is, libikarus is threadsafe.
|
||||||
|
You just cannot rely on the data being consistent.
|
||||||
|
This goes especially for inter-process access to the same project.
|
||||||
16
docs/DoxyFile
Normal file
16
docs/DoxyFile
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
DISABLE_INDEX = NO
|
||||||
|
EXCLUDE = ../vendor ../build
|
||||||
|
EXCLUDE_PATTERNS = cmake-*
|
||||||
|
FILE_PATTERNS = *.h *.hpp *.tpp *.ipp *.cpp
|
||||||
|
FULL_SIDEBAR = NO
|
||||||
|
GENERATE_LATEX = NO
|
||||||
|
GENERATE_TREEVIEW = YES
|
||||||
|
HTML_COLORSTYLE = LIGHT # required with Doxygen >= 1.9.5
|
||||||
|
HTML_EXTRA_FILES = ../vendor/doxygen-awesome-css/doxygen-awesome-darkmode-toggle.js ../vendor/doxygen-awesome-css/doxygen-awesome-fragment-copy-button.js ./enum_format_fix.js
|
||||||
|
HTML_EXTRA_STYLESHEET = ../vendor/doxygen-awesome-css/doxygen-awesome.css
|
||||||
|
HTML_HEADER = header.html
|
||||||
|
INPUT = ..
|
||||||
|
OUTPUT_DIRECTORY = generated
|
||||||
|
PROJECT_BRIEF = A C-API implementation for Ikarus, a tool for worldbuilding.
|
||||||
|
PROJECT_NAME = LIBIKARUS
|
||||||
|
RECURSIVE = YES
|
||||||
11
docs/enum_format_fix.js
Normal file
11
docs/enum_format_fix.js
Normal file
|
|
@ -0,0 +1,11 @@
|
||||||
|
// maximum efficiency
|
||||||
|
function enumFormatFix() {
|
||||||
|
Array.from(document.getElementsByClassName("memItemRight")).forEach((elem) => {
|
||||||
|
elem.innerHTML = elem.innerHTML.replaceAll("<br>", "");
|
||||||
|
elem.innerHTML = elem.innerHTML.replaceAll(" ", "");
|
||||||
|
elem.innerHTML = elem.innerHTML.replaceAll("{", "{<br> ");
|
||||||
|
elem.innerHTML = elem.innerHTML.replaceAll("\n,", ",");
|
||||||
|
elem.innerHTML = elem.innerHTML.replaceAll(",", ",<br> ");
|
||||||
|
elem.innerHTML = elem.innerHTML.replaceAll("}", "<br>}");
|
||||||
|
});
|
||||||
|
}
|
||||||
97
docs/header.html
Normal file
97
docs/header.html
Normal file
|
|
@ -0,0 +1,97 @@
|
||||||
|
<!-- HTML header for doxygen 1.9.7-->
|
||||||
|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN"
|
||||||
|
"https://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
||||||
|
<html xmlns="http://www.w3.org/1999/xhtml" lang="$langISO">
|
||||||
|
<head>
|
||||||
|
<meta http-equiv="Content-Type" content="text/xhtml;charset=UTF-8"/>
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=11"/>
|
||||||
|
<meta name="generator" content="Doxygen $doxygenversion"/>
|
||||||
|
<meta name="viewport" content="width=device-width, initial-scale=1"/>
|
||||||
|
<!--BEGIN PROJECT_NAME--><title>$projectname: $title</title><!--END PROJECT_NAME-->
|
||||||
|
<!--BEGIN !PROJECT_NAME--><title>$title</title><!--END !PROJECT_NAME-->
|
||||||
|
<link href="$relpath^tabs.css" rel="stylesheet" type="text/css"/>
|
||||||
|
<!--BEGIN DISABLE_INDEX-->
|
||||||
|
<!--BEGIN FULL_SIDEBAR-->
|
||||||
|
<script type="text/javascript">var page_layout = 1;</script>
|
||||||
|
<!--END FULL_SIDEBAR-->
|
||||||
|
<!--END DISABLE_INDEX-->
|
||||||
|
<script type="text/javascript" src="$relpath^jquery.js"></script>
|
||||||
|
<script type="text/javascript" src="$relpath^dynsections.js"></script>
|
||||||
|
<script type="text/javascript" src="$relpath^doxygen-awesome-darkmode-toggle.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
DoxygenAwesomeDarkModeToggle.init()
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript" src="$relpath^doxygen-awesome-fragment-copy-button.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
DoxygenAwesomeFragmentCopyButton.init()
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript" src="$relpath^doxygen-awesome-paragraph-link.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
DoxygenAwesomeParagraphLink.init()
|
||||||
|
</script>
|
||||||
|
<script type="text/javascript" src="$relpath^enum_format_fix.js"></script>
|
||||||
|
<script type="text/javascript">
|
||||||
|
window.onload = function () {
|
||||||
|
enumFormatFix()
|
||||||
|
}
|
||||||
|
</script>
|
||||||
|
$treeview
|
||||||
|
$search
|
||||||
|
$mathjax
|
||||||
|
$darkmode
|
||||||
|
<link href="$relpath^$stylesheet" rel="stylesheet" type="text/css"/>
|
||||||
|
$extrastylesheet
|
||||||
|
</head>
|
||||||
|
<body>
|
||||||
|
<!--BEGIN DISABLE_INDEX-->
|
||||||
|
<!--BEGIN FULL_SIDEBAR-->
|
||||||
|
<div id="side-nav" class="ui-resizable side-nav-resizable"><!-- do not remove this div, it is closed by doxygen! -->
|
||||||
|
<!--END FULL_SIDEBAR-->
|
||||||
|
<!--END DISABLE_INDEX-->
|
||||||
|
|
||||||
|
<div id="top"><!-- do not remove this div, it is closed by doxygen! -->
|
||||||
|
|
||||||
|
<!--BEGIN TITLEAREA-->
|
||||||
|
<div id="titlearea">
|
||||||
|
<table cellspacing="0" cellpadding="0">
|
||||||
|
<tbody>
|
||||||
|
<tr id="projectrow">
|
||||||
|
<!--BEGIN PROJECT_LOGO-->
|
||||||
|
<td id="projectlogo"><img alt="Logo" src="$relpath^$projectlogo"/></td>
|
||||||
|
<!--END PROJECT_LOGO-->
|
||||||
|
<!--BEGIN PROJECT_NAME-->
|
||||||
|
<td id="projectalign">
|
||||||
|
<div id="projectname">$projectname<!--BEGIN PROJECT_NUMBER--><span id="projectnumber"> $projectnumber</span>
|
||||||
|
<!--END PROJECT_NUMBER-->
|
||||||
|
</div>
|
||||||
|
<!--BEGIN PROJECT_BRIEF-->
|
||||||
|
<div id="projectbrief">$projectbrief</div><!--END PROJECT_BRIEF-->
|
||||||
|
</td>
|
||||||
|
<!--END PROJECT_NAME-->
|
||||||
|
<!--BEGIN !PROJECT_NAME-->
|
||||||
|
<!--BEGIN PROJECT_BRIEF-->
|
||||||
|
<td>
|
||||||
|
<div id="projectbrief">$projectbrief</div>
|
||||||
|
</td>
|
||||||
|
<!--END PROJECT_BRIEF-->
|
||||||
|
<!--END !PROJECT_NAME-->
|
||||||
|
<!--BEGIN DISABLE_INDEX-->
|
||||||
|
<!--BEGIN SEARCHENGINE-->
|
||||||
|
<!--BEGIN !FULL_SIDEBAR-->
|
||||||
|
<td>$searchbox</td>
|
||||||
|
<!--END !FULL_SIDEBAR-->
|
||||||
|
<!--END SEARCHENGINE-->
|
||||||
|
<!--END DISABLE_INDEX-->
|
||||||
|
</tr>
|
||||||
|
<!--BEGIN SEARCHENGINE-->
|
||||||
|
<!--BEGIN FULL_SIDEBAR-->
|
||||||
|
<tr>
|
||||||
|
<td colspan="2">$searchbox</td>
|
||||||
|
</tr>
|
||||||
|
<!--END FULL_SIDEBAR-->
|
||||||
|
<!--END SEARCHENGINE-->
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
<!--END TITLEAREA-->
|
||||||
|
<!-- end header part -->
|
||||||
12
implementation_details
Normal file
12
implementation_details
Normal file
|
|
@ -0,0 +1,12 @@
|
||||||
|
This list is intended to help keep the documentation up to date.
|
||||||
|
If you make changes to, for example, templates, always check the documentation for templates.
|
||||||
|
But sometimes information is shared. and referenced in multiple places. This helps keep track of that.
|
||||||
|
|
||||||
|
Usage: Search for these keys prefixed with IMPLEMENTATION_DETAIL_* to change documentation in relevant places.
|
||||||
|
|
||||||
|
DATABASE: References to the usage of a database
|
||||||
|
TREE_LAYOUT: References to our usage of a tree layout
|
||||||
|
OBJECT_TYPES: References to the types of objects
|
||||||
|
OBJECT_SCOPES: References to the usage of object scopes
|
||||||
|
PROPERTY_TYPES: The property types that currently exist
|
||||||
|
LAZY_VALUE_CREATION: The fact that values are created lazily
|
||||||
8
include/CMakeLists.txt
Normal file
8
include/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
file(
|
||||||
|
GLOB_RECURSE
|
||||||
|
FILES
|
||||||
|
"*.h"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(INCLUDE_FILES ${FILES} PARENT_SCOPE)
|
||||||
|
|
||||||
27
include/ikarus/macros.h
Normal file
27
include/ikarus/macros.h
Normal file
|
|
@ -0,0 +1,27 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#if defined(__unix__)
|
||||||
|
|
||||||
|
#define IKA_OS_FAMILY_UNIX
|
||||||
|
#define IKA_API __attribute__((visibility("default")))
|
||||||
|
|
||||||
|
#if defined(linux)
|
||||||
|
#define IKA_OS_LINUX
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#elif defined(_WIN32) || defined(WIN32)
|
||||||
|
#define IKA_OS_WIN
|
||||||
|
#define IKA_API __declspec(dllexport)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef IKA_API
|
||||||
|
#define IKA_API
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#define IKARUS_BEGIN_HEADER extern "C" {
|
||||||
|
#define IKARUS_END_HEADER }
|
||||||
|
#else
|
||||||
|
#define IKARUS_BEGIN_HEADER
|
||||||
|
#define IKARUS_END_HEADER
|
||||||
|
#endif
|
||||||
8
include/ikarus/stdtypes.h
Normal file
8
include/ikarus/stdtypes.h
Normal file
|
|
@ -0,0 +1,8 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#ifdef __cplusplus
|
||||||
|
#include <cstdint>
|
||||||
|
using std::size_t;
|
||||||
|
#else
|
||||||
|
#include <stdint.h>
|
||||||
|
#endif
|
||||||
58
include/ikarus/types/id.h
Normal file
58
include/ikarus/types/id.h
Normal file
|
|
@ -0,0 +1,58 @@
|
||||||
|
// IMPLEMENTATION_DETAIL_DATABASE
|
||||||
|
|
||||||
|
/// \file id.h
|
||||||
|
/// \author Folling <mail@folling.io>
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ikarus/macros.h>
|
||||||
|
|
||||||
|
IKARUS_BEGIN_HEADER
|
||||||
|
|
||||||
|
#include <ikarus/stdtypes.h>
|
||||||
|
#include <ikarus/types/object_type.h>
|
||||||
|
|
||||||
|
/// \defgroup id Ids
|
||||||
|
/// \brief Ids are used to identify objects in the database.
|
||||||
|
/// \details They are stored as 64 bit integers with the following layout:
|
||||||
|
/// - first 8 bits: #IkarusObjectType - 255 possible values, 0 for special values
|
||||||
|
/// - last 56 bits: incremented counter generated by the database
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// \brief A wrapper around a 64 bit integer that represents the id of an object.
|
||||||
|
/// \details They are stored as 64 bit integers with the following layout:
|
||||||
|
/// - first 8 bits: #IkarusObjectType - 255 possible values, 0 for special values
|
||||||
|
/// - last 56 bits: incremented counter generated by the database
|
||||||
|
struct IkarusId {
|
||||||
|
/// \private \brief The value of the id.
|
||||||
|
uint64_t value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief A special id returned by failed functions.
|
||||||
|
IkarusId const IKARUS_ID_NONE{0};
|
||||||
|
/// \brief A special id used to indicate an optional id not being specified.
|
||||||
|
IkarusId const IKARUS_ID_UNSPECIFIED{1};
|
||||||
|
|
||||||
|
/// \private \brief Generates a new id for the given object type.
|
||||||
|
/// \param object_type The type of the object to generate an id for.
|
||||||
|
/// \return The generated id.
|
||||||
|
IkarusId ikarus_id_from_integer(IkarusObjectType object_type);
|
||||||
|
|
||||||
|
/// \brief Fetches the object type of the given id.
|
||||||
|
/// \param id The id to fetch the object type for.
|
||||||
|
/// \return The object type of the given id.
|
||||||
|
IKA_API IkarusObjectType ikarus_id_get_object_type(IkarusId id);
|
||||||
|
|
||||||
|
/// \brief Checks if the given id is IKARUS_ID_NONE.
|
||||||
|
/// \param id The id to check.
|
||||||
|
/// \return True if the id is IKARUS_ID_NONE, false otherwise.
|
||||||
|
IKA_API bool ikarus_id_is_none(IkarusId id);
|
||||||
|
|
||||||
|
/// \brief Checks if the given id is IKARUS_ID_UNSPECIFIED.
|
||||||
|
/// \param id The id to check.
|
||||||
|
/// \return True if the id is IKARUS_ID_UNSPECIFIED, false otherwise.
|
||||||
|
IKA_API bool ikarus_id_is_unspecified(IkarusId id);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
IKARUS_END_HEADER
|
||||||
164
include/ikarus/types/object.h
Normal file
164
include/ikarus/types/object.h
Normal file
|
|
@ -0,0 +1,164 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// IMPLEMENTATION_DETAIL_OBJECT_TYPES
|
||||||
|
// IMPLEMENTATION_DETAIL_LAZY_VALUE_CREATION
|
||||||
|
// IMPLEMENTATION_DETAIL_PROPERTY_TYPES
|
||||||
|
|
||||||
|
/// \file id.h
|
||||||
|
/// \author Folling <mail@folling.io>
|
||||||
|
|
||||||
|
/// \defgroup object Objects
|
||||||
|
/// \brief Objects are a compound type of all types of objects in the database.
|
||||||
|
/// \details The following objects currently exist:
|
||||||
|
/// - blueprints
|
||||||
|
/// - properties
|
||||||
|
/// - entities
|
||||||
|
/// - blueprint folders
|
||||||
|
/// - property folders
|
||||||
|
/// - entity folders
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
#include <ikarus/types/id.h>
|
||||||
|
|
||||||
|
IKARUS_BEGIN_HEADER
|
||||||
|
|
||||||
|
/// \brief A blueprint object.
|
||||||
|
/// \details A blueprint is a collection of properties which can be linked to entities.
|
||||||
|
/// Each entity the blueprint is linked to will have values for the blueprints properties.
|
||||||
|
struct IkarusBlueprint {
|
||||||
|
IkarusId id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Properties are the placeholders of values for entities.
|
||||||
|
/// \details Each entity can have any number of properties.
|
||||||
|
/// Every property has a type that identifies the kind of data that can be put in.
|
||||||
|
///
|
||||||
|
/// The following types currently exist:
|
||||||
|
/// - Toggle: A true/false boolean-like value
|
||||||
|
/// - Number: An arbitrary numeric value
|
||||||
|
/// - Text: An arbitrary textual value
|
||||||
|
///
|
||||||
|
/// Property Examples:
|
||||||
|
/// - Is Dead (Toggle)
|
||||||
|
/// - Age (Number)
|
||||||
|
/// - ISBN (Text)
|
||||||
|
///
|
||||||
|
/// Every property has settings which can be used to customise the property further.
|
||||||
|
/// Two settings that are shared among all properties are the following:
|
||||||
|
/// - Multiple
|
||||||
|
/// - Allow undefined
|
||||||
|
///
|
||||||
|
/// The former transforms a property into a list. Instead of one number, you could then specify a series of numbers.
|
||||||
|
/// The latter allows you to specify an "unknown" value for a property.
|
||||||
|
/// It might not be known if a character is dead or not for example.
|
||||||
|
///
|
||||||
|
/// Each entity associated with the property has a value for it.
|
||||||
|
///
|
||||||
|
/// Properties can also be added to blueprints in which case they are available for all entities associated with the
|
||||||
|
/// blueprint.
|
||||||
|
///
|
||||||
|
/// We call properties within entities "Entity Properties" and properties within blueprints "Blueprint Properties".
|
||||||
|
///
|
||||||
|
/// \remark Values for properties are lazily created as space saving measure.
|
||||||
|
/// Fetching the value for some property of some entity will return the property's default value if none is specified.
|
||||||
|
/// This default value is specified when the property is created and can be updated later.
|
||||||
|
///
|
||||||
|
/// \remark Properties' tree structures are scoped to the entity or blueprint they are associated with.
|
||||||
|
struct IkarusProperty {
|
||||||
|
/// \private \brief The ID of the property.
|
||||||
|
IkarusId id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Entities are the core building blocks of Ikarus.
|
||||||
|
/// \detials Blueprints and Properties define the structure of the data.
|
||||||
|
/// Entities define the data itself.
|
||||||
|
///
|
||||||
|
/// Properties can be associated with Entities in two ways:
|
||||||
|
/// - Directly: The property is linked to the entity.
|
||||||
|
/// - Indirectly: The property is linked to a blueprint of the entity.
|
||||||
|
///
|
||||||
|
/// For each property an entity is linked to, it has a value. These values depend on the property's type.
|
||||||
|
/// For more information on the types see the property documentation.
|
||||||
|
///
|
||||||
|
/// Values are the core type of data within Ikarus.
|
||||||
|
/// Each value is associated with one page and one property.
|
||||||
|
///
|
||||||
|
/// \remark Values are typed, the type of a value is specified by its associated property.
|
||||||
|
/// For more information on the types see the property documentation.
|
||||||
|
///
|
||||||
|
/// \remark Values are guaranteed to be in valid format for a given type
|
||||||
|
/// but not guaranteed to be valid under the settings of the property.
|
||||||
|
/// This is because changing the settings can invalidate existing values without resetting them.
|
||||||
|
struct IkarusEntity {
|
||||||
|
/// \private \brief The ID of the entity.
|
||||||
|
IkarusId id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief A blueprint folder.
|
||||||
|
/// \see Folder
|
||||||
|
struct IkarusBlueprintFolder {
|
||||||
|
/// \private \brief The ID of the folder.
|
||||||
|
IkarusId id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief A property folder.
|
||||||
|
/// \remark Property folders are scoped to the blueprint or entity they are associated with.
|
||||||
|
/// \see Folder
|
||||||
|
struct IkarusPropertyFolder {
|
||||||
|
/// \private \brief The ID of the folder.
|
||||||
|
IkarusId id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief An entity folder.
|
||||||
|
/// \see Folder
|
||||||
|
struct IkarusEntityFolder {
|
||||||
|
/// \private \brief The ID of the folder.
|
||||||
|
IkarusId id;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \private \brief The data of a folder.
|
||||||
|
union IkarusFolderData {
|
||||||
|
/// \private \brief The blueprint folder data of the folder.
|
||||||
|
IkarusBlueprintFolder blueprint_folder;
|
||||||
|
/// \private \brief The property folder data of the folder.
|
||||||
|
IkarusPropertyFolder property_folder;
|
||||||
|
/// \private \brief The entity folder data of the folder.
|
||||||
|
IkarusEntityFolder entity_folder;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief A generic folder. Similar to how Objects wrap all types of objects, Folders wrap all types of folders.
|
||||||
|
struct IkarusFolder {
|
||||||
|
/// \private \brief The data of the folder.
|
||||||
|
IkarusFolderData data;
|
||||||
|
|
||||||
|
/// \private \brief The type of the folder.
|
||||||
|
IkarusFolderType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \private \brief The data of an object.
|
||||||
|
union IkarusObjectData {
|
||||||
|
/// \private \brief The blueprint data of the object.
|
||||||
|
IkarusBlueprint blueprint;
|
||||||
|
/// \private \brief The property data of the object.
|
||||||
|
IkarusProperty property;
|
||||||
|
/// \private \brief The entity data of the object.
|
||||||
|
IkarusEntity entity;
|
||||||
|
/// \private \brief The blueprint folder data of the object.
|
||||||
|
IkarusBlueprintFolder blueprint_folder;
|
||||||
|
/// \private \brief The property folder data of the object.
|
||||||
|
IkarusPropertyFolder property_folder;
|
||||||
|
/// \private \brief The entity folder data of the object.
|
||||||
|
IkarusEntityFolder entity_folder;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief A generic object. Wraps all types of objects, including folders.
|
||||||
|
struct IkarusObject {
|
||||||
|
/// \private \brief The data of the object.
|
||||||
|
IkarusObjectData data;
|
||||||
|
/// \private \brief The type of the object.
|
||||||
|
IkarusObjectType type;
|
||||||
|
};
|
||||||
|
|
||||||
|
// @}
|
||||||
|
|
||||||
|
IKARUS_END_HEADER
|
||||||
149
include/ikarus/types/object_scope.h
Normal file
149
include/ikarus/types/object_scope.h
Normal file
|
|
@ -0,0 +1,149 @@
|
||||||
|
// IMPLEMENTATION_DETAIL_OBJECT_SCOPES, IMPLEMENTATION_DETAIL_TREE_LAYOUT
|
||||||
|
|
||||||
|
/// \file object_scope.h
|
||||||
|
/// \author Folling <mail@folling.io>
|
||||||
|
|
||||||
|
/// \defgroup object_scopes Object Scopes
|
||||||
|
/// \brief Scopes define where objects belong to.
|
||||||
|
/// \details They are required to differentiate between different types of objects with NULL as their parent.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ikarus/macros.h>
|
||||||
|
#include <ikarus/types/object.h>
|
||||||
|
|
||||||
|
IKARUS_BEGIN_HEADER
|
||||||
|
|
||||||
|
/// \brief The global scope of all blueprints.
|
||||||
|
struct IkarusBlueprintScope {
|
||||||
|
/// \private \brief Empty structs aren't allowed in C, so we need a dummy field.
|
||||||
|
short _dummy;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Data for a property scope. This can either be a blueprint or an entity.
|
||||||
|
union IkarusPropertyScopeData {
|
||||||
|
/// \private \brief The blueprint the property is scoped to.
|
||||||
|
IkarusBlueprint _blueprint;
|
||||||
|
/// \private \brief The entity the property is scoped to.
|
||||||
|
IkarusEntity _entity;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief The type of a property scope. This can either be a blueprint or an entity.
|
||||||
|
enum IkarusPropertyScopeType {
|
||||||
|
/// \brief The property is scoped to a blueprint.
|
||||||
|
IkarusPropertyScopeType_Blueprint,
|
||||||
|
/// \brief The property is scoped to an entity.
|
||||||
|
IkarusPropertyScopeType_Entity
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief The scope of a property
|
||||||
|
struct IkarusPropertyScope {
|
||||||
|
/// \private \brief Represents the type of the scope.
|
||||||
|
IkarusPropertyScopeType _type;
|
||||||
|
/// \private \brief Represents the data of the scope.
|
||||||
|
IkarusPropertyScopeData _data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The global scope of all entities.
|
||||||
|
struct IkarusEntityScope {
|
||||||
|
/// \private \brief Empty structs aren't allowed in C, so we need a dummy field.
|
||||||
|
short _dummy;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \private \brief The data for an object scope.
|
||||||
|
union IkarusObjectScopeData {
|
||||||
|
/// \private \brief The blueprint data of the scope.
|
||||||
|
IkarusBlueprintScope _blueprint;
|
||||||
|
/// \private \brief The property data of the scope.
|
||||||
|
IkarusPropertyScope _property;
|
||||||
|
/// \private \brief The entity data of the scope.
|
||||||
|
IkarusEntityScope _entity;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// The type of an object scope.
|
||||||
|
enum IkarusObjectScopeType {
|
||||||
|
/// \brief The scope is a blueprint scope.
|
||||||
|
IkarusObjectScopeType_Blueprint,
|
||||||
|
/// \brief The scope is a property scope.
|
||||||
|
IkarusObjectScopeType_Property,
|
||||||
|
/// \brief The scope is an entity scope.
|
||||||
|
IkarusObjectScopeType_Entity
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief The scope of an object.
|
||||||
|
struct IkarusObjectScope {
|
||||||
|
/// \private \brief Represents the type of the scope.
|
||||||
|
IkarusObjectScopeType _type;
|
||||||
|
/// \private \brief Represents the data of the scope.
|
||||||
|
IkarusObjectScopeData _data;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Creates a blueprint scope.
|
||||||
|
/// \return The created blueprint scope.
|
||||||
|
IKA_API IkarusBlueprintScope ikarus_blueprint_scope_create();
|
||||||
|
/// \brief Converts a blueprint scope to an object scope.
|
||||||
|
/// \param scope The scope to convert.
|
||||||
|
/// \return The converted scope.
|
||||||
|
IKA_API IkarusObjectScope ikarus_blueprint_scope_to_object_scope(IkarusBlueprintScope const * scope);
|
||||||
|
|
||||||
|
/// \brief Creates a property scope from a blueprint.
|
||||||
|
/// \param blueprint The blueprint the property is scoped to.
|
||||||
|
/// \return The created property scope.
|
||||||
|
IKA_API IkarusPropertyScope ikarus_property_scope_create_blueprint(IkarusBlueprint const * blueprint);
|
||||||
|
/// \brief Creates a property scope from a entity.
|
||||||
|
/// \param entity The entity the property is scoped to.
|
||||||
|
/// \return The created property scope.
|
||||||
|
IKA_API IkarusPropertyScope ikarus_property_scope_create_entity(IkarusEntity const * entity);
|
||||||
|
/// \brief Converts a property scope to an object scope.
|
||||||
|
/// \param scope The scope to convert.
|
||||||
|
/// \return The converted scope.
|
||||||
|
IKA_API IkarusObjectScope ikarus_property_scope_to_object_scope(IkarusPropertyScope const * scope);
|
||||||
|
|
||||||
|
/// \brief Fetches the type of an property scope.
|
||||||
|
/// \param scope The scope to fetch the type of.
|
||||||
|
/// \return The type of the scope.
|
||||||
|
IKA_API IkarusPropertyScopeType ikarus_property_scope_get_type(IkarusPropertyScope const * scope);
|
||||||
|
|
||||||
|
/// \brief Visits a property scope, calling the appropriate function.
|
||||||
|
/// \param scope The scope to to visit
|
||||||
|
/// \param blueprint The function to call if the property is scoped to a blueprint.
|
||||||
|
/// \param entity The function to call if the property is scoped to an entity.
|
||||||
|
/// \param data Optional data to pass to the functions.
|
||||||
|
void ikarus_property_scope_visit(
|
||||||
|
IkarusPropertyScope const * scope,
|
||||||
|
void (*blueprint)(IkarusBlueprint const *, void *),
|
||||||
|
void (*entity)(IkarusEntity const *, void *),
|
||||||
|
void * data
|
||||||
|
);
|
||||||
|
|
||||||
|
/// \brief Creates an entity scope.
|
||||||
|
/// \return The created entity scope.
|
||||||
|
IKA_API IkarusEntityScope ikarus_entity_scope_create();
|
||||||
|
/// Converts an entity scope to an object scope.
|
||||||
|
/// \param scope The scope to convert.
|
||||||
|
/// \return The converted scope.
|
||||||
|
IKA_API IkarusObjectScope ikarus_entity_scope_to_object_scope(IkarusEntityScope const * scope);
|
||||||
|
|
||||||
|
/// \brief Fetches the type of an object scope.
|
||||||
|
/// \param scope The scope to fetch the type of.
|
||||||
|
/// \return The type of the scope.
|
||||||
|
IKA_API IkarusObjectScopeType ikarus_object_scope_get_type(IkarusObjectScope const * scope);
|
||||||
|
|
||||||
|
/// \brief Visits an object scope, calling the appropriate function.
|
||||||
|
/// \param scope The scope to visit.
|
||||||
|
/// \param blueprint The function to call if the scope is an #IkarusBlueprintScope.
|
||||||
|
/// \param property The function to call if the scope is an #IkarusPropertyScope.
|
||||||
|
/// \param entity The function to call if the scope is an #IkarusEntityScope.
|
||||||
|
/// \remark function pointers may be null in which case they are not called.
|
||||||
|
IKA_API void ikarus_object_scope_visit(
|
||||||
|
IkarusObjectScope const * scope,
|
||||||
|
void (*blueprint)(IkarusBlueprintScope const *, void *),
|
||||||
|
void (*property)(IkarusPropertyScope const *, void *),
|
||||||
|
void (*entity)(IkarusEntityScope const *, void *),
|
||||||
|
void * data
|
||||||
|
);
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
IKARUS_END_HEADER
|
||||||
63
include/ikarus/types/object_type.h
Normal file
63
include/ikarus/types/object_type.h
Normal file
|
|
@ -0,0 +1,63 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <ikarus/macros.h>
|
||||||
|
|
||||||
|
IKARUS_BEGIN_HEADER
|
||||||
|
|
||||||
|
/// \defgroup object_types ObjectTypes
|
||||||
|
/// \brief ObjectTypes are used to identify the type of objects.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// \brief The type of a folder.
|
||||||
|
/// \remark folders have the first bit set and then mirror the object type of the underlying object
|
||||||
|
enum IkarusFolderType {
|
||||||
|
/// \brief Not a folder or no folder.
|
||||||
|
IkarusFolderType_None = 0,
|
||||||
|
/// \brief An IkarusBlueprintFolder
|
||||||
|
IkarusFolderType_BlueprintFolder = 0b1000'0001,
|
||||||
|
/// \brief An IkarusPropertyFolder
|
||||||
|
IkarusFolderType_PropertyFolder = 0b1000'0010,
|
||||||
|
/// \brief An IkarusEntityFolder
|
||||||
|
IkarusFolderType_EntityFolder = 0b1000'0011,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief The type of an object.
|
||||||
|
/// \remark folders have the first bit set and then mirror the object type of the underlying object
|
||||||
|
enum IkarusObjectType {
|
||||||
|
/// \brief Not an object or no object.
|
||||||
|
ObjectType_None = 0,
|
||||||
|
/// \brief An IkarusBlueprint.
|
||||||
|
ObjectType_Blueprint = 0b0000'0001,
|
||||||
|
/// \brief An IkarusProperty.
|
||||||
|
ObjectType_Property = 0b0000'0010,
|
||||||
|
/// \brief An IkarusEntity.
|
||||||
|
ObjectType_Entity = 0b0000'0011,
|
||||||
|
/// \brief An IkarusBlueprintFolder
|
||||||
|
ObjectType_BlueprintFolder = 0b1000'0001,
|
||||||
|
/// \brief An IkarusPropertyFolder
|
||||||
|
ObjectType_PropertyFolder = 0b1000'0010,
|
||||||
|
/// \brief An IkarusEntityFolder
|
||||||
|
ObjectType_EntityFolder = 0b1000'0011,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief A bitset of IkarusObjectType%s.
|
||||||
|
enum ObjectTypes {
|
||||||
|
/// \brief No object type.
|
||||||
|
ObjectTypes_None = 0,
|
||||||
|
/// \brief An IkarusBlueprint.
|
||||||
|
ObjectTypes_Blueprint = 1 << ObjectType_Blueprint,
|
||||||
|
/// \brief An IkarusProperty.
|
||||||
|
ObjectTypes_Property = 1 << ObjectType_Property,
|
||||||
|
/// \brief An IkarusEntity.
|
||||||
|
ObjectTypes_Entity = 1 << ObjectType_Entity,
|
||||||
|
/// \brief An IkarusBlueprintFolder
|
||||||
|
ObjectTypes_BlueprintFolder = 1 << ObjectType_BlueprintFolder,
|
||||||
|
/// \brief An IkarusPropertyFolder
|
||||||
|
ObjectTypes_PropertyFolder = 1 << ObjectType_PropertyFolder,
|
||||||
|
/// \brief An IkarusEntityFolder
|
||||||
|
ObjectTypes_EntityFolder = 1 << ObjectType_EntityFolder,
|
||||||
|
};
|
||||||
|
|
||||||
|
// @}
|
||||||
|
|
||||||
|
IKARUS_END_HEADER
|
||||||
31
include/ikarus/types/property_type.h
Normal file
31
include/ikarus/types/property_type.h
Normal file
|
|
@ -0,0 +1,31 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// IMPLEMENTATION_DETAIL_PROPERTY_TYPES
|
||||||
|
|
||||||
|
/// \file id.h
|
||||||
|
/// \author Folling <mail@folling.io>
|
||||||
|
|
||||||
|
#include <ikarus/macros.h>
|
||||||
|
|
||||||
|
IKARUS_BEGIN_HEADER
|
||||||
|
|
||||||
|
/// \defgroup property_types Property Types
|
||||||
|
/// \brief Property Types delineate the type of data stored by a property.
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// \brief The type of a property.
|
||||||
|
/// \details Designates the type of data stored by the property as well as which settings are
|
||||||
|
/// available.
|
||||||
|
/// \see IkarusPropertySettings
|
||||||
|
enum IkarusPropertyType {
|
||||||
|
/// \brief A true/false boolean-like value.
|
||||||
|
IkarusPropertyType_Toggle,
|
||||||
|
/// \brief An arbitrary numeric value.
|
||||||
|
IkarusPropertyType_Number,
|
||||||
|
/// \brief An arbitrary textual value.
|
||||||
|
IkarusPropertyType_Text,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// @}
|
||||||
|
|
||||||
|
IKARUS_END_HEADER
|
||||||
161
include/ikarus/types/value.h
Normal file
161
include/ikarus/types/value.h
Normal file
|
|
@ -0,0 +1,161 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
// IMPLEMENTATION_DETAIL_PROPERTY_TYPES
|
||||||
|
|
||||||
|
#include <ikarus/macros.h>
|
||||||
|
#include <ikarus/stdtypes.h>
|
||||||
|
#include <ikarus/types/property_type.h>
|
||||||
|
|
||||||
|
IKARUS_BEGIN_HEADER
|
||||||
|
|
||||||
|
/// \defgroup entity_value Entity Values
|
||||||
|
/// \brief The values stored in entities.
|
||||||
|
/// \details Each entity has a value for each property it is associated with.
|
||||||
|
/// The value is of the type specified by the property and constrained by the property's settings.
|
||||||
|
/// \see PropertyType PropertySettings
|
||||||
|
/// @{
|
||||||
|
|
||||||
|
/// \brief A true/false boolean-like value. For example "IsDead".
|
||||||
|
struct IkarusToggleValue {
|
||||||
|
/// \private \brief The value of the property.
|
||||||
|
bool _value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief An arbitrary numeric value. For example "Age".
|
||||||
|
struct IkarusNumberValue {
|
||||||
|
/// \private \brief The value of the property.
|
||||||
|
long double _value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief An arbitrary textual value. For example "First Name".
|
||||||
|
struct IkarusTextValue {
|
||||||
|
/// \private \brief The value of the property.
|
||||||
|
char const * _value;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \private \brief The data for a value.
|
||||||
|
union IkarusEntityValueData {
|
||||||
|
/// \private \brief The value as a toggle.
|
||||||
|
IkarusToggleValue toggle;
|
||||||
|
/// \private \brief The value as a number.
|
||||||
|
IkarusNumberValue number;
|
||||||
|
/// \private \brief The value as text.
|
||||||
|
IkarusTextValue text;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief The state of an entity value.
|
||||||
|
/// \details States provide insight into the nature of a value.
|
||||||
|
enum IkarusEntityValueState {
|
||||||
|
/// \brief The value is invalid.
|
||||||
|
IkarusEntityValueState_Invalid,
|
||||||
|
/// \brief The value is normal and can be used as-is.
|
||||||
|
IkarusEntityValueState_Normal,
|
||||||
|
/// \brief The value is unknown.
|
||||||
|
IkarusEntityValueState_Indeterminate,
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief The value of an entity associated with a property.
|
||||||
|
struct IkarusEntityValue {
|
||||||
|
/// \private \brief The type of the value.
|
||||||
|
IkarusPropertyType _type;
|
||||||
|
/// \private \brief The data for the value.p
|
||||||
|
IkarusEntityValueData _data;
|
||||||
|
/// \private \brief The state of the value.
|
||||||
|
IkarusEntityValueState _state;
|
||||||
|
};
|
||||||
|
|
||||||
|
/// \brief Creates an entity value from a toggle value.
|
||||||
|
/// \param value The toggle value.
|
||||||
|
/// \return The entity value.
|
||||||
|
IKA_API IkarusEntityValue ikarus_value_create_toggle(bool value);
|
||||||
|
/// \brief Creates an entity value from a number value.
|
||||||
|
/// \param value The number value.
|
||||||
|
/// \return The entity value.
|
||||||
|
/// \remark If the value is NaN or infinity an InvalidEntityValue is returned.
|
||||||
|
IKA_API IkarusEntityValue ikarus_value_create_number(long double value);
|
||||||
|
/// \brief Creates an entity value from a text value.
|
||||||
|
/// \param value The text value.
|
||||||
|
/// \return The entity value.
|
||||||
|
/// \remark If the value is null an InvalidEntityValue is returned.
|
||||||
|
IKA_API IkarusEntityValue ikarus_value_create_text(char const * value);
|
||||||
|
|
||||||
|
/// \brief Creates an indeterminate entity value of a given type.
|
||||||
|
/// \param type The type of the value.
|
||||||
|
/// \return The entity value.
|
||||||
|
IKA_API IkarusEntityValue ikarus_value_create_indeterminate(IkarusPropertyType type);
|
||||||
|
|
||||||
|
/// \brief Fetches the default value for a property type.
|
||||||
|
/// \remark Not to be confused with the default value of a property. See ikarus_property_get_default_value
|
||||||
|
/// \param type The property type.
|
||||||
|
/// \return The default value for the property type.
|
||||||
|
IKA_API IkarusEntityValue ikarus_value_get_default(IkarusPropertyType type);
|
||||||
|
|
||||||
|
/// \brief Fetches the underlying value of a toggle value.
|
||||||
|
/// \param value The toggle value.
|
||||||
|
/// \return The underlying value.
|
||||||
|
IKA_API bool ikarus_toggle_value_get_underlying(IkarusToggleValue const * value);
|
||||||
|
|
||||||
|
/// \brief Fetches the underlying value of a number value.
|
||||||
|
/// \param value The number value.
|
||||||
|
/// \return The underlying value.
|
||||||
|
IKA_API long double ikarus_number_value_get_underlying(IkarusNumberValue const * value);
|
||||||
|
|
||||||
|
/// \brief Fetches the underlying value of a text value.
|
||||||
|
/// \param value The text value.
|
||||||
|
/// \return The underlying value.
|
||||||
|
IKA_API char const * ikarus_text_value_get_underlying(IkarusTextValue const * value);
|
||||||
|
|
||||||
|
/// \brief Checks if a toggle value is equal to a boolean.
|
||||||
|
/// \param value The toggle value.
|
||||||
|
/// \param check The boolean value.
|
||||||
|
/// \return False if value is null. True if it is equal to check, false otherwise.
|
||||||
|
IKA_API bool ikarus_toggle_value_is_equal(IkarusToggleValue const * value, bool check);
|
||||||
|
|
||||||
|
/// \brief Checks if a number value is equal to a number.
|
||||||
|
/// \param value The number value.
|
||||||
|
/// \param check The number value.
|
||||||
|
/// \return False if value is null. True if it is equal to check, false otherwise.
|
||||||
|
IKA_API bool ikarus_number_value_is_equal(IkarusNumberValue const * value, long double check);
|
||||||
|
|
||||||
|
/// \brief Checks if a text value is equal to a string.
|
||||||
|
/// \param value The text value.
|
||||||
|
/// \param check The string value.
|
||||||
|
/// \return False if value or check are null. True if it is equal to check, false otherwise.
|
||||||
|
IKA_API bool ikarus_text_value_is_equal(IkarusTextValue const * value, char const * check);
|
||||||
|
|
||||||
|
/// \brief Checks if two entity values are equal.
|
||||||
|
/// \details Two entity values are equal if they are of the same type and their value is considered equal.
|
||||||
|
/// Note that floating point values can only be checked for approximate equality.
|
||||||
|
/// \param left The left-hand entity value.
|
||||||
|
/// \param right The right-hand entity value.
|
||||||
|
/// \return True if the values are considered equal, false otherwise.
|
||||||
|
/// \remark Null values compare false to all other values. As do invalid values. Indeterminate values however, compare true to
|
||||||
|
/// other indeterminate values of the same type.
|
||||||
|
IKA_API bool ikarus_value_is_equal(IkarusEntityValue const * left, IkarusEntityValue const * right);
|
||||||
|
|
||||||
|
/// \brief Checks if an entity value is invalid.
|
||||||
|
/// \param value The entity value.
|
||||||
|
/// \return True if the value is invalid or null, false otherwise.
|
||||||
|
IKA_API bool ikarus_value_is_invalid(IkarusEntityValue const * value);
|
||||||
|
|
||||||
|
/// \brief Fetches the type of an entity value.
|
||||||
|
/// \param value The entity value.
|
||||||
|
/// \return The type of the entity value.
|
||||||
|
IKA_API IkarusPropertyType ikarus_value_get_type(IkarusEntityValue const * value);
|
||||||
|
|
||||||
|
/// \brief Visits an entity value, calling the appropriate function for the value's type.
|
||||||
|
/// \param value The entity value to visit.
|
||||||
|
/// \param toggle The function to call if the value is a toggle value.
|
||||||
|
/// \param number The function to call if the value is a number value.
|
||||||
|
/// \param text The function to call if the value is a text value.
|
||||||
|
/// \param data The data to pass to the functions.
|
||||||
|
/// \remark function pointers may be null in which case they are not called.
|
||||||
|
IKA_API void ikarus_value_visit(
|
||||||
|
IkarusEntityValue const * value,
|
||||||
|
void (*toggle)(IkarusToggleValue const *, void *),
|
||||||
|
void (*number)(IkarusNumberValue const *, void *),
|
||||||
|
void (*text)(IkarusTextValue const *, void *),
|
||||||
|
void * data
|
||||||
|
);
|
||||||
|
|
||||||
|
IKARUS_END_HEADER
|
||||||
7
src/CMakeLists.txt
Normal file
7
src/CMakeLists.txt
Normal file
|
|
@ -0,0 +1,7 @@
|
||||||
|
file(
|
||||||
|
GLOB_RECURSE
|
||||||
|
FILES
|
||||||
|
"*.cpp"
|
||||||
|
)
|
||||||
|
|
||||||
|
set(SOURCE_FILES ${FILES} PARENT_SCOPE)
|
||||||
209
src/types/object_scope.cpp
Normal file
209
src/types/object_scope.cpp
Normal file
|
|
@ -0,0 +1,209 @@
|
||||||
|
#include "ikarus/types/object_scope.h"
|
||||||
|
|
||||||
|
#include <utility>
|
||||||
|
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
|
IkarusBlueprintScope ikarus_blueprint_scope_create() {
|
||||||
|
return IkarusBlueprintScope{._dummy = 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
IkarusObjectScope ikarus_blueprint_scope_to_object_scope(IkarusBlueprintScope const * scope) {
|
||||||
|
IkarusObjectScopeData data{};
|
||||||
|
data._blueprint = *scope;
|
||||||
|
|
||||||
|
return IkarusObjectScope{._type = IkarusObjectScopeType_Blueprint, ._data = data};
|
||||||
|
}
|
||||||
|
|
||||||
|
IkarusPropertyScope ikarus_property_scope_create_blueprint(IkarusBlueprint const * blueprint) {
|
||||||
|
IkarusPropertyScopeData data{};
|
||||||
|
data._blueprint = *blueprint;
|
||||||
|
return IkarusPropertyScope{._type = IkarusPropertyScopeType_Blueprint, ._data = data};
|
||||||
|
}
|
||||||
|
|
||||||
|
IkarusPropertyScope ikarus_property_scope_create_entity(IkarusEntity const * entity) {
|
||||||
|
IkarusPropertyScopeData data{};
|
||||||
|
data._entity = *entity;
|
||||||
|
return IkarusPropertyScope{._type = IkarusPropertyScopeType_Entity, ._data = data};
|
||||||
|
}
|
||||||
|
|
||||||
|
IkarusObjectScope ikarus_property_scope_to_object_scope(IkarusPropertyScope const * scope) {
|
||||||
|
IkarusObjectScopeData data{};
|
||||||
|
data._property = *scope;
|
||||||
|
|
||||||
|
return IkarusObjectScope{._type = IkarusObjectScopeType_Property, ._data = data};
|
||||||
|
}
|
||||||
|
|
||||||
|
IkarusPropertyScopeType ikarus_property_scope_get_type(IkarusPropertyScope const * scope) {
|
||||||
|
return scope->_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ikarus_property_scope_visit(
|
||||||
|
IkarusPropertyScope const * scope,
|
||||||
|
void (*blueprint)(IkarusBlueprint const *, void *),
|
||||||
|
void (*entity)(IkarusEntity const *, void *),
|
||||||
|
void * data
|
||||||
|
) {
|
||||||
|
switch (scope->_type) {
|
||||||
|
case IkarusPropertyScopeType_Blueprint: blueprint(&scope->_data._blueprint, data); break;
|
||||||
|
case IkarusPropertyScopeType_Entity: entity(&scope->_data._entity, data); break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
IkarusEntityScope ikarus_entity_scope_create() {
|
||||||
|
return IkarusEntityScope{._dummy = 0};
|
||||||
|
}
|
||||||
|
|
||||||
|
IkarusObjectScope ikarus_entity_scope_to_object_scope(IkarusEntityScope const * scope) {
|
||||||
|
IkarusObjectScopeData data{};
|
||||||
|
data._entity = *scope;
|
||||||
|
|
||||||
|
return IkarusObjectScope{._type = IkarusObjectScopeType_Entity, ._data = data};
|
||||||
|
}
|
||||||
|
|
||||||
|
IkarusObjectScopeType ikarus_object_scope_get_type(IkarusObjectScope const * scope) {
|
||||||
|
return scope->_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ikarus_object_scope_visit(
|
||||||
|
IkarusObjectScope const * scope,
|
||||||
|
void (*blueprint)(IkarusBlueprintScope const *, void *),
|
||||||
|
void (*property)(IkarusPropertyScope const *, void *),
|
||||||
|
void (*entity)(IkarusEntityScope const *, void *),
|
||||||
|
void * data
|
||||||
|
) {
|
||||||
|
switch (scope->_type) {
|
||||||
|
case IkarusObjectScopeType_Blueprint: {
|
||||||
|
if (blueprint != nullptr) {
|
||||||
|
blueprint(&scope->_data._blueprint, data);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IkarusObjectScopeType_Property: {
|
||||||
|
if (property != nullptr) {
|
||||||
|
property(&scope->_data._property, data);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IkarusObjectScopeType_Entity: {
|
||||||
|
if (entity != nullptr) {
|
||||||
|
entity(&scope->_data._entity, data);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("blueprint_object_scope_conversion", "[object_scope]") {
|
||||||
|
auto blueprint_scope = ikarus_blueprint_scope_create();
|
||||||
|
auto blueprint_object_scope = ikarus_blueprint_scope_to_object_scope(&blueprint_scope);
|
||||||
|
REQUIRE(blueprint_object_scope._type == IkarusObjectScopeType_Blueprint);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("property_scope_type", "[object_scope]") {
|
||||||
|
auto blueprint = IkarusBlueprint{};
|
||||||
|
auto entity = IkarusEntity{};
|
||||||
|
|
||||||
|
auto property_blueprint_scope = ikarus_property_scope_create_blueprint(&blueprint);
|
||||||
|
auto property_entity_scope = ikarus_property_scope_create_entity(&entity);
|
||||||
|
|
||||||
|
REQUIRE(ikarus_property_scope_get_type(&property_blueprint_scope) == IkarusPropertyScopeType_Blueprint);
|
||||||
|
REQUIRE(ikarus_property_scope_get_type(&property_entity_scope) == IkarusPropertyScopeType_Entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("property_object_scope_conversion", "[object_scope]") {
|
||||||
|
auto blueprint = IkarusBlueprint{};
|
||||||
|
auto entity = IkarusEntity{};
|
||||||
|
|
||||||
|
auto property_blueprint_scope = ikarus_property_scope_create_blueprint(&blueprint);
|
||||||
|
auto property_blueprint_object_scope = ikarus_property_scope_to_object_scope(&property_blueprint_scope);
|
||||||
|
|
||||||
|
REQUIRE(property_blueprint_object_scope._type == IkarusObjectScopeType_Property);
|
||||||
|
|
||||||
|
auto property_entity_scope = ikarus_property_scope_create_entity(&entity);
|
||||||
|
auto property_entity_object_scope = ikarus_property_scope_to_object_scope(&property_entity_scope);
|
||||||
|
|
||||||
|
REQUIRE(property_entity_object_scope._type == IkarusObjectScopeType_Property);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("property_scope_visiting", "[object_scope]") {
|
||||||
|
auto blueprint = IkarusBlueprint{};
|
||||||
|
auto entity = IkarusEntity{};
|
||||||
|
|
||||||
|
auto property_blueprint_scope = ikarus_property_scope_create_blueprint(&blueprint);
|
||||||
|
auto property_entity_scope = ikarus_property_scope_create_entity(&entity);
|
||||||
|
|
||||||
|
int test = 0;
|
||||||
|
|
||||||
|
ikarus_property_scope_visit(
|
||||||
|
&property_blueprint_scope,
|
||||||
|
[](IkarusBlueprint const * _, void * data) { *reinterpret_cast<decltype(test) *>(data) = 1; },
|
||||||
|
[](IkarusEntity const * _, void * data) { *reinterpret_cast<decltype(test) *>(data) = 2; },
|
||||||
|
&test
|
||||||
|
);
|
||||||
|
|
||||||
|
REQUIRE(test == 1);
|
||||||
|
|
||||||
|
ikarus_property_scope_visit(
|
||||||
|
&property_entity_scope,
|
||||||
|
[](IkarusBlueprint const * _, void * data) { *reinterpret_cast<decltype(test) *>(data) = 1; },
|
||||||
|
[](IkarusEntity const * _, void * data) { *reinterpret_cast<decltype(test) *>(data) = 2; },
|
||||||
|
&test
|
||||||
|
);
|
||||||
|
|
||||||
|
REQUIRE(test == 2);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("entity_object_scope_conversion", "[object_scope]") {
|
||||||
|
auto entity_scope = ikarus_entity_scope_create();
|
||||||
|
auto entity_object_scope = ikarus_entity_scope_to_object_scope(&entity_scope);
|
||||||
|
REQUIRE(entity_object_scope._type == IkarusObjectScopeType_Entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("object_scope_type_fetching", "[object_scope]") {
|
||||||
|
auto blueprint = IkarusBlueprint{};
|
||||||
|
|
||||||
|
auto blueprint_scope = ikarus_blueprint_scope_create();
|
||||||
|
auto property_scope = ikarus_property_scope_create_blueprint(&blueprint);
|
||||||
|
auto entity_scope = ikarus_entity_scope_create();
|
||||||
|
|
||||||
|
auto blueprint_object_scope = ikarus_blueprint_scope_to_object_scope(&blueprint_scope);
|
||||||
|
auto property_object_scope = ikarus_property_scope_to_object_scope(&property_scope);
|
||||||
|
auto entity_object_scope = ikarus_entity_scope_to_object_scope(&entity_scope);
|
||||||
|
|
||||||
|
REQUIRE(ikarus_object_scope_get_type(&blueprint_object_scope) == IkarusObjectScopeType_Blueprint);
|
||||||
|
REQUIRE(ikarus_object_scope_get_type(&property_object_scope) == IkarusObjectScopeType_Property);
|
||||||
|
REQUIRE(ikarus_object_scope_get_type(&entity_object_scope) == IkarusObjectScopeType_Entity);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("object_scope_visiting", "[object_scope]") {
|
||||||
|
auto blueprint = IkarusBlueprint{};
|
||||||
|
|
||||||
|
auto blueprint_scope = ikarus_blueprint_scope_create();
|
||||||
|
auto property_scope = ikarus_property_scope_create_blueprint(&blueprint);
|
||||||
|
auto entity_scope = ikarus_entity_scope_create();
|
||||||
|
|
||||||
|
auto blueprint_object_scope = ikarus_blueprint_scope_to_object_scope(&blueprint_scope);
|
||||||
|
auto property_object_scope = ikarus_property_scope_to_object_scope(&property_scope);
|
||||||
|
auto entity_object_scope = ikarus_entity_scope_to_object_scope(&entity_scope);
|
||||||
|
|
||||||
|
auto scopes = {
|
||||||
|
std::make_pair(blueprint_object_scope, 1),
|
||||||
|
std::make_pair(property_object_scope, 2),
|
||||||
|
std::make_pair(entity_object_scope, 3),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto [scope, value] : scopes) {
|
||||||
|
int test = 0;
|
||||||
|
|
||||||
|
ikarus_object_scope_visit(
|
||||||
|
&scope,
|
||||||
|
[](IkarusBlueprintScope const * _, void * data) { *reinterpret_cast<decltype(test) *>(data) = 1; },
|
||||||
|
[](IkarusPropertyScope const * _, void * data) { *reinterpret_cast<decltype(test) *>(data) = 2; },
|
||||||
|
[](IkarusEntityScope const * _, void * data) { *reinterpret_cast<decltype(test) *>(data) = 3; },
|
||||||
|
&test
|
||||||
|
);
|
||||||
|
|
||||||
|
REQUIRE(test == value);
|
||||||
|
}
|
||||||
|
}
|
||||||
337
src/types/value.cpp
Normal file
337
src/types/value.cpp
Normal file
|
|
@ -0,0 +1,337 @@
|
||||||
|
#include "ikarus/types/value.h"
|
||||||
|
|
||||||
|
#include <cmath>
|
||||||
|
#include <limits>
|
||||||
|
|
||||||
|
#include <catch2/catch_test_macros.hpp>
|
||||||
|
|
||||||
|
/// \brief Creates an indeterminate entity value of a given type.
|
||||||
|
/// \param type The type of the value.
|
||||||
|
/// \return The entity value.
|
||||||
|
IKA_API IkarusEntityValue value_create_invalid(IkarusPropertyType type) {
|
||||||
|
return IkarusEntityValue{
|
||||||
|
._type = type,
|
||||||
|
._data = IkarusEntityValueData{},
|
||||||
|
._state = IkarusEntityValueState_Invalid,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
IkarusEntityValue ikarus_value_create_toggle(bool value) {
|
||||||
|
return IkarusEntityValue{
|
||||||
|
._type = IkarusPropertyType_Toggle,
|
||||||
|
._data = IkarusEntityValueData{.toggle = IkarusToggleValue{._value = value}},
|
||||||
|
._state = IkarusEntityValueState_Normal,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
IkarusEntityValue ikarus_value_create_number(long double value) {
|
||||||
|
if (auto fp_class = std::fpclassify(value); fp_class != FP_NORMAL && fp_class != FP_ZERO) {
|
||||||
|
return value_create_invalid(IkarusPropertyType_Number);
|
||||||
|
}
|
||||||
|
|
||||||
|
return IkarusEntityValue{
|
||||||
|
._type = IkarusPropertyType_Number,
|
||||||
|
._data = IkarusEntityValueData{.number = IkarusNumberValue{._value = value}},
|
||||||
|
._state = IkarusEntityValueState_Normal,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
IkarusEntityValue ikarus_value_create_text(char const * value) {
|
||||||
|
if (value == nullptr) {
|
||||||
|
return value_create_invalid(IkarusPropertyType_Text);
|
||||||
|
};
|
||||||
|
|
||||||
|
return IkarusEntityValue{
|
||||||
|
._type = IkarusPropertyType_Text,
|
||||||
|
._data = IkarusEntityValueData{.text = IkarusTextValue{._value = value}},
|
||||||
|
._state = IkarusEntityValueState_Normal,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
IkarusEntityValue ikarus_value_create_indeterminate(IkarusPropertyType type) {
|
||||||
|
IkarusEntityValueData data{};
|
||||||
|
|
||||||
|
switch (type) {
|
||||||
|
case IkarusPropertyType_Toggle: {
|
||||||
|
data.toggle = IkarusToggleValue{._value = false};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IkarusPropertyType_Number: {
|
||||||
|
data.number = IkarusNumberValue{._value = 0.0};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IkarusPropertyType_Text: {
|
||||||
|
data.text = IkarusTextValue{._value = ""};
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: return value_create_invalid(type);
|
||||||
|
}
|
||||||
|
|
||||||
|
return IkarusEntityValue{
|
||||||
|
._type = type,
|
||||||
|
._data = data,
|
||||||
|
._state = IkarusEntityValueState_Indeterminate,
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
IkarusEntityValue ikarus_value_get_default(IkarusPropertyType type) {
|
||||||
|
switch (type) {
|
||||||
|
case IkarusPropertyType_Toggle: return ikarus_value_create_toggle(false);
|
||||||
|
case IkarusPropertyType_Number: return ikarus_value_create_number(0.0);
|
||||||
|
case IkarusPropertyType_Text: return ikarus_value_create_text("");
|
||||||
|
default: return value_create_invalid(type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ikarus_toggle_value_get_underlying(IkarusToggleValue const * value) {
|
||||||
|
return value->_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
long double ikarus_number_value_get_underlying(IkarusNumberValue const * value) {
|
||||||
|
return value->_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
char const * ikarus_text_value_get_underlying(IkarusTextValue const * value) {
|
||||||
|
return value->_value;
|
||||||
|
}
|
||||||
|
|
||||||
|
// no need to check for validity here, since these concrete types are only created by the library
|
||||||
|
bool ikarus_toggle_value_is_equal(IkarusToggleValue const * value, bool check) {
|
||||||
|
return value != nullptr && value->_value == check;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ikarus_number_value_is_equal(IkarusNumberValue const * value, long double check) {
|
||||||
|
return value != nullptr && value->_value == check;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ikarus_text_value_is_equal(IkarusTextValue const * value, char const * check) {
|
||||||
|
return value != nullptr && check != nullptr && std::strcmp(value->_value, check) == 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ikarus_value_is_equal(IkarusEntityValue const * left, IkarusEntityValue const * right) {
|
||||||
|
if (left == nullptr || right == nullptr) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left->_state == IkarusEntityValueState_Invalid || right->_state == IkarusEntityValueState_Invalid) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (left->_type != right->_type) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// indeterminate values are only equal if they have the same type
|
||||||
|
if (left->_state == IkarusEntityValueState_Indeterminate && right->_state == IkarusEntityValueState_Indeterminate) {
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (left->_type) {
|
||||||
|
case IkarusPropertyType_Toggle: return left->_data.toggle._value == right->_data.toggle._value;
|
||||||
|
case IkarusPropertyType_Number: return left->_data.number._value == right->_data.number._value;
|
||||||
|
case IkarusPropertyType_Text: return std::strcmp(left->_data.text._value, right->_data.text._value) == 0;
|
||||||
|
default: return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool ikarus_value_is_invalid(IkarusEntityValue const * value) {
|
||||||
|
return value == nullptr || value->_state == IkarusEntityValueState_Invalid;
|
||||||
|
}
|
||||||
|
|
||||||
|
IkarusPropertyType ikarus_value_get_type(IkarusEntityValue const * value) {
|
||||||
|
return value->_type;
|
||||||
|
}
|
||||||
|
|
||||||
|
void ikarus_value_visit(
|
||||||
|
IkarusEntityValue const * value,
|
||||||
|
void (*toggle)(IkarusToggleValue const * value, void * data),
|
||||||
|
void (*number)(IkarusNumberValue const * value, void * data),
|
||||||
|
void (*text)(IkarusTextValue const * value, void * data),
|
||||||
|
void * data
|
||||||
|
) {
|
||||||
|
if (value == nullptr) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch (value->_type) {
|
||||||
|
case IkarusPropertyType_Toggle: {
|
||||||
|
if (toggle != nullptr) {
|
||||||
|
toggle(&value->_data.toggle, data);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IkarusPropertyType_Number: {
|
||||||
|
if (number != nullptr) {
|
||||||
|
number(&value->_data.number, data);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
case IkarusPropertyType_Text: {
|
||||||
|
if (text != nullptr) {
|
||||||
|
text(&value->_data.text, data);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
default: break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("toggle_value_creation", "[value]") {
|
||||||
|
auto toggle_value = ikarus_value_create_toggle(true);
|
||||||
|
|
||||||
|
REQUIRE(ikarus_value_get_type(&toggle_value) == IkarusPropertyType_Toggle);
|
||||||
|
REQUIRE(ikarus_toggle_value_is_equal(&toggle_value._data.toggle, true));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("number_value_creation", "[value]") {
|
||||||
|
auto number_value = ikarus_value_create_number(1.0);
|
||||||
|
|
||||||
|
REQUIRE(ikarus_value_get_type(&number_value) == IkarusPropertyType_Number);
|
||||||
|
REQUIRE(ikarus_number_value_is_equal(&number_value._data.number, 1.0));
|
||||||
|
|
||||||
|
auto nan_value = ikarus_value_create_number(std::numeric_limits<long double>::quiet_NaN());
|
||||||
|
REQUIRE(ikarus_value_is_invalid(&nan_value));
|
||||||
|
auto signaling_non_value = ikarus_value_create_number(std::numeric_limits<long double>::signaling_NaN());
|
||||||
|
REQUIRE(ikarus_value_is_invalid(&signaling_non_value));
|
||||||
|
auto inf_value = ikarus_value_create_number(std::numeric_limits<long double>::infinity());
|
||||||
|
REQUIRE(ikarus_value_is_invalid(&inf_value));
|
||||||
|
auto neg_inf_value = ikarus_value_create_number(-std::numeric_limits<long double>::infinity());
|
||||||
|
REQUIRE(ikarus_value_is_invalid(&neg_inf_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("text_value_creation", "[value]") {
|
||||||
|
auto text_value = ikarus_value_create_text("test");
|
||||||
|
|
||||||
|
REQUIRE(ikarus_value_get_type(&text_value) == IkarusPropertyType_Text);
|
||||||
|
REQUIRE(ikarus_text_value_is_equal(&text_value._data.text, "test"));
|
||||||
|
|
||||||
|
auto null_value = ikarus_value_create_text(nullptr);
|
||||||
|
REQUIRE(ikarus_value_is_invalid(&null_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("default_value_creation", "[value]") {
|
||||||
|
auto types = {
|
||||||
|
IkarusPropertyType_Toggle,
|
||||||
|
IkarusPropertyType_Number,
|
||||||
|
IkarusPropertyType_Text,
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto type : types) {
|
||||||
|
auto value = ikarus_value_get_default(type);
|
||||||
|
REQUIRE(ikarus_value_get_type(&value) == type);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("toggle_value_underlying", "[value]") {
|
||||||
|
auto true_toggle_value = ikarus_value_create_toggle(true);
|
||||||
|
auto false_toggle_value = ikarus_value_create_toggle(false);
|
||||||
|
|
||||||
|
REQUIRE(ikarus_toggle_value_get_underlying(&true_toggle_value._data.toggle) == true);
|
||||||
|
REQUIRE(ikarus_toggle_value_get_underlying(&false_toggle_value._data.toggle) == false);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("number_value_underlying", "[value]") {
|
||||||
|
auto zero_number_value = ikarus_value_create_number(0.0);
|
||||||
|
auto third_number_value = ikarus_value_create_number(1.0 / 3.0);
|
||||||
|
auto large_number_value = ikarus_value_create_number(1.2345678910e123);
|
||||||
|
|
||||||
|
REQUIRE(ikarus_number_value_get_underlying(&zero_number_value._data.number) == 0.0);
|
||||||
|
REQUIRE(ikarus_number_value_get_underlying(&third_number_value._data.number) == 1.0 / 3.0);
|
||||||
|
REQUIRE(ikarus_number_value_get_underlying(&large_number_value._data.number) == 1.2345678910e123);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("text_value_underlying", "[value]") {
|
||||||
|
auto test_value = ikarus_value_create_text("test");
|
||||||
|
auto empty_value = ikarus_value_create_text("");
|
||||||
|
|
||||||
|
REQUIRE(std::strcmp(ikarus_text_value_get_underlying(&test_value._data.text), "test") == 0);
|
||||||
|
REQUIRE(std::strcmp(ikarus_text_value_get_underlying(&empty_value._data.text), "") == 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("toggle_comparison", "[value]") {
|
||||||
|
auto true_toggle_value = ikarus_value_create_toggle(true);
|
||||||
|
auto false_toggle_value = ikarus_value_create_toggle(false);
|
||||||
|
|
||||||
|
REQUIRE(ikarus_toggle_value_is_equal(&true_toggle_value._data.toggle, true));
|
||||||
|
REQUIRE(ikarus_toggle_value_is_equal(&false_toggle_value._data.toggle, false));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("number_comparison", "[value]") {
|
||||||
|
auto zero_number_value = ikarus_value_create_number(0.0);
|
||||||
|
auto third_number_value = ikarus_value_create_number(1.0 / 3.0);
|
||||||
|
auto large_number_value = ikarus_value_create_number(1.2345678910e123);
|
||||||
|
|
||||||
|
REQUIRE(ikarus_number_value_is_equal(&zero_number_value._data.number, 0.0));
|
||||||
|
REQUIRE(ikarus_number_value_is_equal(&third_number_value._data.number, 1.0 / 6.0 + 1.0 / 6.0));
|
||||||
|
REQUIRE(ikarus_number_value_is_equal(&large_number_value._data.number, 1.2345678910e123));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("text_comparison", "[value]") {
|
||||||
|
auto test_value = ikarus_value_create_text("test");
|
||||||
|
auto empty_value = ikarus_value_create_text("");
|
||||||
|
|
||||||
|
REQUIRE(ikarus_text_value_is_equal(&test_value._data.text, "test"));
|
||||||
|
REQUIRE(ikarus_text_value_is_equal(&empty_value._data.text, ""));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("value_comparison", "[value]") {
|
||||||
|
auto true_toggle_value = ikarus_value_create_toggle(true);
|
||||||
|
auto false_toggle_value = ikarus_value_create_toggle(false);
|
||||||
|
auto number_value1 = ikarus_value_create_number(0.0);
|
||||||
|
auto number_value2 = ikarus_value_create_number(0.0);
|
||||||
|
auto invalid_value = ikarus_value_create_text(nullptr);
|
||||||
|
|
||||||
|
auto indeterminate_toggle = ikarus_value_create_indeterminate(IkarusPropertyType_Toggle);
|
||||||
|
auto indeterminate_number1 = ikarus_value_create_indeterminate(IkarusPropertyType_Number);
|
||||||
|
auto indeterminate_number2 = ikarus_value_create_indeterminate(IkarusPropertyType_Number);
|
||||||
|
|
||||||
|
REQUIRE(!ikarus_value_is_equal(nullptr, nullptr));
|
||||||
|
REQUIRE(!ikarus_value_is_equal(&true_toggle_value, nullptr));
|
||||||
|
REQUIRE(!ikarus_value_is_equal(nullptr, &true_toggle_value));
|
||||||
|
|
||||||
|
REQUIRE(!ikarus_value_is_equal(&invalid_value, &invalid_value));
|
||||||
|
REQUIRE(!ikarus_value_is_equal(&true_toggle_value, &invalid_value));
|
||||||
|
REQUIRE(!ikarus_value_is_equal(&invalid_value, &true_toggle_value));
|
||||||
|
|
||||||
|
REQUIRE(ikarus_value_is_equal(&true_toggle_value, &true_toggle_value));
|
||||||
|
REQUIRE(!ikarus_value_is_equal(&true_toggle_value, &false_toggle_value));
|
||||||
|
REQUIRE(!ikarus_value_is_equal(&true_toggle_value, &number_value1));
|
||||||
|
REQUIRE(!ikarus_value_is_equal(&number_value1, &true_toggle_value));
|
||||||
|
REQUIRE(ikarus_value_is_equal(&number_value1, &number_value2));
|
||||||
|
|
||||||
|
REQUIRE(!ikarus_value_is_equal(&indeterminate_toggle, &indeterminate_number1));
|
||||||
|
REQUIRE(ikarus_value_is_equal(&indeterminate_number1, &indeterminate_number2));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("invalid_value", "[value]") {
|
||||||
|
auto invalid_value = ikarus_value_create_toggle(false);
|
||||||
|
invalid_value._state = IkarusEntityValueState_Invalid;
|
||||||
|
|
||||||
|
REQUIRE(ikarus_value_is_invalid(&invalid_value));
|
||||||
|
}
|
||||||
|
|
||||||
|
TEST_CASE("visit_value", "[value]") {
|
||||||
|
auto toggle_value = ikarus_value_create_toggle(true);
|
||||||
|
auto number_value = ikarus_value_create_number(0.0);
|
||||||
|
auto text_value = ikarus_value_create_text("test");
|
||||||
|
|
||||||
|
auto values = {
|
||||||
|
std::make_pair(toggle_value, 1),
|
||||||
|
std::make_pair(number_value, 2),
|
||||||
|
std::make_pair(text_value, 3),
|
||||||
|
};
|
||||||
|
|
||||||
|
for (auto [value, expected] : values) {
|
||||||
|
int test = 0;
|
||||||
|
|
||||||
|
ikarus_value_visit(
|
||||||
|
&value,
|
||||||
|
[](IkarusToggleValue const * _, void * data) { *reinterpret_cast<decltype(test) *>(data) = 1; },
|
||||||
|
[](IkarusNumberValue const * _, void * data) { *reinterpret_cast<decltype(test) *>(data) = 2; },
|
||||||
|
[](IkarusTextValue const * _, void * data) { *reinterpret_cast<decltype(test) *>(data) = 3; },
|
||||||
|
&test
|
||||||
|
);
|
||||||
|
|
||||||
|
REQUIRE(test == expected);
|
||||||
|
}
|
||||||
|
}
|
||||||
2
vendor/CMakeLists.txt
vendored
Normal file
2
vendor/CMakeLists.txt
vendored
Normal file
|
|
@ -0,0 +1,2 @@
|
||||||
|
add_subdirectory(catch2)
|
||||||
|
add_subdirectory(sqlitecpp)
|
||||||
1
vendor/catch2
vendored
Submodule
1
vendor/catch2
vendored
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 5bba3e4038602badb691da914523f667a2dd1f27
|
||||||
1
vendor/doxygen-awesome-css
vendored
Submodule
1
vendor/doxygen-awesome-css
vendored
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit 00a52f6c74065ffbd836cbd791ddfe8edf2836b8
|
||||||
1
vendor/sqlitecpp
vendored
Submodule
1
vendor/sqlitecpp
vendored
Submodule
|
|
@ -0,0 +1 @@
|
||||||
|
Subproject commit afe7b165002ccf86a37da5b6b157ce4ff9db0401
|
||||||
Loading…
Add table
Add a link
Reference in a new issue