a new beginning
Signed-off-by: Folling <mail@folling.io>
This commit is contained in:
commit
dff8d96c55
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