Compare commits
No commits in common. "1644aa4e9be4555e79f52258995dfe5124b5ecb8" and "0217edf080c7f21eabf3ea051fe68b9a281d380a" have entirely different histories.
1644aa4e9b
...
0217edf080
18
.gitignore
vendored
18
.gitignore
vendored
@ -1,8 +1,9 @@
|
|||||||
# build results
|
# build results
|
||||||
bin/
|
bin/
|
||||||
obj/
|
obj/
|
||||||
src/generated/
|
libs/
|
||||||
imgui.ini
|
*.log
|
||||||
|
*.tmp
|
||||||
|
|
||||||
# IDE files
|
# IDE files
|
||||||
.vs/
|
.vs/
|
||||||
@ -11,13 +12,8 @@ imgui.ini
|
|||||||
*.user
|
*.user
|
||||||
*.vcxproj.filters
|
*.vcxproj.filters
|
||||||
|
|
||||||
# other files
|
# user files
|
||||||
.old*/
|
.old*/
|
||||||
old/
|
current.config
|
||||||
tmp/
|
src/generated/
|
||||||
temp/
|
imgui.ini
|
||||||
*.tmp
|
|
||||||
*.temp
|
|
||||||
logs/
|
|
||||||
log/
|
|
||||||
*.log
|
|
||||||
|
|||||||
22
.gitmodules
vendored
22
.gitmodules
vendored
@ -1,10 +1,18 @@
|
|||||||
[submodule "dependencies/kerep"]
|
[submodule "cbuild"]
|
||||||
|
path = cbuild
|
||||||
|
url = https://github.com/Timerix22/cbuild.git
|
||||||
|
[submodule "kerep"]
|
||||||
path = dependencies/kerep
|
path = dependencies/kerep
|
||||||
url = https://timerix.ddns.net:3322/Timerix/kerep.git
|
url = https://github.com/Timerix22/kerep.git
|
||||||
[submodule "dependencies/imgui"]
|
[submodule "SDL2"]
|
||||||
|
path = dependencies/SDL2
|
||||||
|
url = https://github.com/Timerix22/SDL.git
|
||||||
|
branch = SDL2
|
||||||
|
[submodule "imgui"]
|
||||||
path = dependencies/imgui
|
path = dependencies/imgui
|
||||||
url = https://github.com/ocornut/imgui.git
|
url = https://github.com/Timerix22/imgui.git
|
||||||
branch = docking
|
branch = docking_cbuild
|
||||||
[submodule "dependencies/imnodes"]
|
[submodule "imnodes"]
|
||||||
path = dependencies/imnodes
|
path = dependencies/imnodes
|
||||||
url = https://github.com/Nelarius/imnodes.git
|
url = https://github.com/Timerix22/imnodes
|
||||||
|
branch = master_cbuild
|
||||||
|
|||||||
2
.vscode/.gitignore
vendored
2
.vscode/.gitignore
vendored
@ -0,0 +1,2 @@
|
|||||||
|
settings.json
|
||||||
|
c_cpp_properties.json
|
||||||
26
.vscode/launch.json
vendored
26
.vscode/launch.json
vendored
@ -2,11 +2,33 @@
|
|||||||
"version": "0.2.0",
|
"version": "0.2.0",
|
||||||
"configurations": [
|
"configurations": [
|
||||||
{
|
{
|
||||||
"name": "gdb_debug",
|
"name": "gdb_debug_unix",
|
||||||
"type": "cppdbg",
|
"type": "cppdbg",
|
||||||
"request": "launch",
|
"request": "launch",
|
||||||
"program": "${workspaceFolder}/bin/GraphC",
|
"program": "${workspaceFolder}/bin/GraphC",
|
||||||
"windows": { "program": "${workspaceFolder}/bin/GraphC.exe" },
|
"preLaunchTask": "build_exec_dbg",
|
||||||
|
"stopAtEntry": false,
|
||||||
|
"cwd": "${workspaceFolder}/bin",
|
||||||
|
"externalConsole": false,
|
||||||
|
"MIMode": "gdb",
|
||||||
|
"miDebuggerPath": "gdb",
|
||||||
|
"setupCommands": [
|
||||||
|
{
|
||||||
|
"text": "-enable-pretty-printing",
|
||||||
|
"ignoreFailures": true
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"text": "-gdb-set disassembly-flavor intel",
|
||||||
|
"ignoreFailures": true
|
||||||
|
}
|
||||||
|
]
|
||||||
|
},
|
||||||
|
// the only difference is .exe
|
||||||
|
{
|
||||||
|
"name": "gdb_debug_win",
|
||||||
|
"type": "cppdbg",
|
||||||
|
"request": "launch",
|
||||||
|
"program": "${workspaceFolder}/bin/GraphC.exe",
|
||||||
"preLaunchTask": "build_exec_dbg",
|
"preLaunchTask": "build_exec_dbg",
|
||||||
"stopAtEntry": false,
|
"stopAtEntry": false,
|
||||||
"cwd": "${workspaceFolder}/bin",
|
"cwd": "${workspaceFolder}/bin",
|
||||||
|
|||||||
14
.vscode/settings.json
vendored
14
.vscode/settings.json
vendored
@ -1,14 +0,0 @@
|
|||||||
{
|
|
||||||
"C_Cpp.codeAnalysis.exclude": {
|
|
||||||
"**/dependencies/": true
|
|
||||||
},
|
|
||||||
"C_Cpp.default.defines": [
|
|
||||||
"SDL_DISABLE_ANALYZE_MACROS",
|
|
||||||
"DEBUG=1"
|
|
||||||
],
|
|
||||||
"C_Cpp.default.includePath": [
|
|
||||||
"dependencies/include/SDL2",
|
|
||||||
"dependencies/imgui",
|
|
||||||
"${default}"
|
|
||||||
]
|
|
||||||
}
|
|
||||||
91
Makefile
Normal file
91
Makefile
Normal file
@ -0,0 +1,91 @@
|
|||||||
|
######################################
|
||||||
|
###### Build tasks #######
|
||||||
|
######################################
|
||||||
|
|
||||||
|
default: build_exec_dbg
|
||||||
|
|
||||||
|
# creates executable using profile info generated by profile
|
||||||
|
build_exec: # profile
|
||||||
|
@cbuild/call_task.sh build_exec 2>&1 | tee -a make_raw.log
|
||||||
|
|
||||||
|
# creates executable with debug info and no optimizations
|
||||||
|
build_exec_dbg:
|
||||||
|
@cbuild/call_task.sh build_exec_dbg 2>&1 | tee make_raw.log
|
||||||
|
|
||||||
|
######################################
|
||||||
|
###### Rebuild dependencies #######
|
||||||
|
######################################
|
||||||
|
|
||||||
|
# recompile kerep.a in the next build task
|
||||||
|
rebuild_kerep:
|
||||||
|
@cbuild/rebuild_dep.sh libkerep.a 2>&1 | tee make_raw.log
|
||||||
|
|
||||||
|
# recompile imgui.a in the next build task
|
||||||
|
rebuild_imgui:
|
||||||
|
@cbuild/rebuild_dep.sh libimgui.a 2>&1 | tee make_raw.log
|
||||||
|
|
||||||
|
rebuild_imnodes:
|
||||||
|
@cbuild/rebuild_dep.sh libimnodes.a 2>&1 | tee make_raw.log
|
||||||
|
|
||||||
|
# writes ttf fonts fron ./fonts/ to C compressed arrays in C source files
|
||||||
|
# builds static library from font arrays definitions
|
||||||
|
embed_fonts:
|
||||||
|
@cbuild/call_task.sh embed_fonts
|
||||||
|
|
||||||
|
rebuild_all: rebuild_kerep rebuild_imgui rebuild_imnodes embed_fonts
|
||||||
|
|
||||||
|
######################################
|
||||||
|
###### Launch tasks #######
|
||||||
|
######################################
|
||||||
|
|
||||||
|
# executes $EXEC_FILE
|
||||||
|
exec: build_exec
|
||||||
|
@cbuild/call_task.sh exec 2>&1 | tee -a make_raw.log
|
||||||
|
|
||||||
|
# executes $EXEC_FILE
|
||||||
|
exec_dbg: build_exec_dbg
|
||||||
|
@cbuild/call_task.sh exec 2>&1 | tee -a make_raw.log
|
||||||
|
|
||||||
|
# executes $EXEC_FILE with valgrind memory checker
|
||||||
|
valgrind: build_exec_dbg
|
||||||
|
@cbuild/call_task.sh valgrind 2>&1 | tee -a make_raw.log
|
||||||
|
|
||||||
|
# generates profiling info
|
||||||
|
profile:
|
||||||
|
@cbuild/call_task.sh profile 2>&1 | tee make_raw.log
|
||||||
|
|
||||||
|
# compiles program with -pg and runs it with gprof
|
||||||
|
# uses gprof2dot python script to generate function call tree (pip install gprof2dot)
|
||||||
|
# requires graphviz (https://www.graphviz.org/download/source/)
|
||||||
|
gprof:
|
||||||
|
@cbuild/call_task.sh gprof 2>&1 | tee make_raw.log
|
||||||
|
|
||||||
|
# compiles program and runs it with callgrind (part of valgrind)
|
||||||
|
# uses gprof2dot python script to generate function call tree (pip install gprof2dot)
|
||||||
|
# requires graphviz (https://www.graphviz.org/download/source/)
|
||||||
|
# P.S. detailed results can be viewed in KCacheGrind
|
||||||
|
callgrind:
|
||||||
|
@cbuild/call_task.sh callgrind 2>&1 | tee make_raw.log
|
||||||
|
|
||||||
|
# compiles executable with sanitizers and executes it to find errors and warnings
|
||||||
|
sanitize:
|
||||||
|
@cbuild/call_task.sh sanitize 2>&1 | tee make_raw.log
|
||||||
|
|
||||||
|
######################################
|
||||||
|
###### Other tasks #######
|
||||||
|
######################################
|
||||||
|
|
||||||
|
# deletes generated files
|
||||||
|
clean:
|
||||||
|
@cbuild/call_task.sh clean 2>&1 | tee make_raw.log
|
||||||
|
|
||||||
|
# removes all unreadable characters copied from stdio
|
||||||
|
fix_log:
|
||||||
|
sed 's/[^[:blank:][:print:]]//g' make_raw.log \
|
||||||
|
| sed 's/\[0;[0-9][0-9]m//g' \
|
||||||
|
| sed 's/\[0;[0-9]m//g' \
|
||||||
|
| sed 's/\[[0-9][0-9]m//g' \
|
||||||
|
| sed 's/\[[0-9]m//g' \
|
||||||
|
| sed 's/ H //g' \
|
||||||
|
| sed 's/\[3gH //g' \
|
||||||
|
> make_fixed.log
|
||||||
49
README.md
49
README.md
@ -5,37 +5,30 @@ GUI is based on [Dear ImGui](https://github.com/ocornut/imgui) and [SDL](https:/
|
|||||||
|
|
||||||
## Installation
|
## Installation
|
||||||
1. Clone the repository
|
1. Clone the repository
|
||||||
```sh
|
```shell
|
||||||
git clone --recurse-submodules https://timerix.ddns.net:3322/Timerix/GraphC.git
|
git clone --recurse-submodules https://github.com/Timerix22/GraphC
|
||||||
```
|
```
|
||||||
2. Install [cbuild](https://timerix.ddns.net:3322/Timerix/cbuild.git)
|
2. Install **SDL2** from package manager or compile it from source.
|
||||||
3. Install **SDL2** from package manager or compile it from source.
|
**If you are using msys, switch to mingw64 shell.**
|
||||||
**If you are using msys, switch to mingw64 sh.**
|
```shell
|
||||||
```sh
|
cd dependencies/SDL2
|
||||||
cd ..
|
|
||||||
git clone https://github.com/libsdl-org/SDL.git
|
|
||||||
cd SDL
|
|
||||||
./configure
|
./configure
|
||||||
make -j [number of cpu threads]
|
make -j [number of cpu threads]
|
||||||
```
|
```
|
||||||
Then you can install it systemwide (on **Linux**):
|
Then you can install it systemwide:
|
||||||
```sh
|
```shell
|
||||||
sudo make install
|
make install
|
||||||
```
|
```
|
||||||
or copy to ./libs (on **Windows**):
|
or copy to ./libs:
|
||||||
```sh
|
```shell
|
||||||
mkdir -p GraphC/libs
|
mkdir -p ../../libs
|
||||||
cp ./build/.libs/SDL2.dll GraphC/libs/
|
cp ./build/.libs/SDL2.dll ../../libs/
|
||||||
```
|
|
||||||
If it doesn't work, read [SDL/INSTALL.txt](https://github.com/libsdl-org/SDL/blob/SDL2/INSTALL.txt) and [SDL/docs/README.md](https://github.com/libsdl-org/SDL/blob/SDL2/docs/README.md).
|
|
||||||
4. Symlink SDL headers directory to `dependencies/include`
|
|
||||||
```sh
|
|
||||||
cd GraphC
|
|
||||||
ln -s SDL2_HEADERS_DIRECTORY_ABSOLUTE_PATH dependencies/include/
|
|
||||||
```
|
|
||||||
Location of the headers can be found by `pkg-config --cppflags --libs sdl2`.
|
|
||||||
Mingw installs SDL2 headers to `/mingw64/include/SDL2`.
|
|
||||||
5. Compile the program
|
|
||||||
```sh
|
|
||||||
cbuild build_exec
|
|
||||||
```
|
```
|
||||||
|
If it didn't work, read [SDL docs](dependencies/SDL2/docs/README.md) and [INSTALL.txt](dependencies/SDL2/INSTALL.txt).
|
||||||
|
|
||||||
|
3. Compile the program
|
||||||
|
```shell
|
||||||
|
make build_exec
|
||||||
|
```
|
||||||
|
|
||||||
|
4. Copy program files from `bin/*` to any directory
|
||||||
|
|||||||
1
cbuild
Submodule
1
cbuild
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 574ce6eab3b65e05888adad95a0211f532dd1125
|
||||||
71
project.config → default.config
Executable file → Normal file
71
project.config → default.config
Executable file → Normal file
@ -1,46 +1,50 @@
|
|||||||
#!/usr/bin/env bash
|
#!/bin/bash
|
||||||
CBUILD_VERSION=2.1.2
|
CBUILD_VERSION=7
|
||||||
CONFIG_VERSION=7
|
CONFIG_VERSION=6
|
||||||
|
|
||||||
PROJECT="GraphC"
|
PROJECT="GraphC"
|
||||||
CMP_C="gcc"
|
CMP_C="gcc"
|
||||||
CMP_CPP="g++"
|
CMP_CPP="g++"
|
||||||
STD_C="c11"
|
STD_C="c11"
|
||||||
STD_CPP="c++17"
|
STD_CPP="c++11"
|
||||||
WARN_C="-Wall -Wno-discarded-qualifiers -Wextra -Wno-unused-parameter"
|
WARN_C="-Wall -Wno-discarded-qualifiers -Wextra -Wno-unused-parameter"
|
||||||
WARN_CPP="-Wall -Wextra -Wno-unused-parameter"
|
WARN_CPP="-Wall -Wextra -Wno-unused-parameter"
|
||||||
SRC_C="$(find src -name '*.c')"
|
SRC_C="$(find src -name '*.c')"
|
||||||
SRC_CPP="$(find src -name '*.cpp')"
|
SRC_CPP="$(find src -name '*.cpp')"
|
||||||
|
#TESTS_C="$( find tests -name '*.c')"
|
||||||
|
#TESTS_CPP="$(find tests -name '*.cpp')"
|
||||||
|
|
||||||
# Directory with dependency configs.
|
# dir with dependeicy dirs
|
||||||
# See cbuild/example_dependency_configs
|
DEPS_BASEDIR="dependencies"
|
||||||
DEPENDENCY_CONFIGS_DIR='dependencies'
|
# EXAMPLE: "dependency_dir='build_task out_dir lib_file'
|
||||||
# List of dependency config files in DEPENDENCY_CONFIGS_DIR separated by space.
|
# other_depndency_dir=..."
|
||||||
ENABLED_DEPENDENCIES='precompiled kerep imgui imnodes'
|
# Dependencies must be declared on separate lines
|
||||||
|
# Values can be override by resetting one of dependencies:
|
||||||
|
# DEPS="$DEPS
|
||||||
|
# dependency_dir='...'"
|
||||||
|
DEPS="kerep='build_static_lib bin libkerep.a'
|
||||||
|
imgui='build_static_lib bin libimgui.a'
|
||||||
|
imnodes='build_static_lib bin libimnodes.a'"
|
||||||
|
|
||||||
# OBJDIR structure:
|
# OBJDIR structure:
|
||||||
# ├── objects/ - Compiled object files. Cleans on each call of build task
|
# ├── objects - dir where compiled *.o files are stored. cleans every call of build task
|
||||||
# ├── static_libs/ - Symbolic links to static libraries used by linker. Cleans on each call of build task.
|
# ├── profile - dir where gcc *.gcda profiling info files stored
|
||||||
# ├── static_libs/ - Symbolic links to dynamic libraries used by linker. Cleans on each call of build task.
|
# ├── libs - there you can put static libs and linker will find them
|
||||||
# └── profile/ - gcc *.gcda profiling info files
|
# └── out - output files are created here and then copied to OUTDIR
|
||||||
OBJDIR="obj"
|
OBJDIR="obj"
|
||||||
OUTDIR="bin"
|
OUTDIR="bin"
|
||||||
STATIC_LIB_FILE="lib$PROJECT.a"
|
|
||||||
|
|
||||||
# header include directories
|
|
||||||
INCLUDE="-I./dependencies/imgui -I./dependencies/include/SDL2"
|
|
||||||
|
|
||||||
# OS-specific options
|
# OS-specific options
|
||||||
case "$OS" in
|
case "$OS" in
|
||||||
WINDOWS)
|
WINDOWS)
|
||||||
EXEC_FILE="$PROJECT.exe"
|
EXEC_FILE="$PROJECT.exe"
|
||||||
SHARED_LIB_FILE="$PROJECT.dll"
|
INCLUDE="-I./dependencies/imgui -I./dependencies/SDL2/include"
|
||||||
LINKER_LIBS="-lopengl32 -lpthread -lws2_32"
|
LINKER_LIBS="-L./libs/ -l:SDL2.dll -lopengl32 -lpthread -lws2_32"
|
||||||
;;
|
;;
|
||||||
LINUX)
|
LINUX)
|
||||||
EXEC_FILE="$PROJECT"
|
EXEC_FILE="$PROJECT"
|
||||||
SHARED_LIB_FILE="$PROJECT.so"
|
INCLUDE="-I./dependencies/imgui -I./dependencies/SDL2/include"
|
||||||
LINKER_LIBS="-lSDL2 -lGL"
|
LINKER_LIBS="-L./libs/ -lSDL2 -lGL"
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
error "operating system $OS has no configuration variants"
|
error "operating system $OS has no configuration variants"
|
||||||
@ -66,20 +70,22 @@ case "$TASK" in
|
|||||||
# -flto applies more optimizations across object files
|
# -flto applies more optimizations across object files
|
||||||
# -flto=auto is needed to multithreaded copilation
|
# -flto=auto is needed to multithreaded copilation
|
||||||
# -fuse-linker-plugin is required to use static libs with lto, it strips away all
|
# -fuse-linker-plugin is required to use static libs with lto, it strips away all
|
||||||
C_ARGS="-O2 -flto=auto -fuse-linker-plugin"
|
C_ARGS="-O2 -flto=auto -fuse-linker-plugin -static"
|
||||||
#-fprofile-use -fprofile-prefix-path=$(realpath $OBJDIR)/objects
|
#-fprofile-use -fprofile-prefix-path=$(realpath $OBJDIR)/objects
|
||||||
CPP_ARGS="$C_ARGS"
|
CPP_ARGS="$C_ARGS"
|
||||||
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
||||||
PRE_TASK_SCRIPT=
|
PRE_TASK_SCRIPT=tasks/pre_build.sh
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
||||||
|
DEPS_BUILD_TASK=build_static_lib
|
||||||
;;
|
;;
|
||||||
# creates executable with debug info and no optimizations
|
# creates executable with debug info and no optimizations
|
||||||
build_exec_dbg)
|
build_exec_dbg)
|
||||||
C_ARGS="-O0 -g -DDEBUG=1"
|
C_ARGS="-O0 -g"
|
||||||
CPP_ARGS="$C_ARGS"
|
CPP_ARGS="$C_ARGS"
|
||||||
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
LINKER_ARGS="$CPP_ARGS $LINKER_LIBS"
|
||||||
PRE_TASK_SCRIPT=
|
PRE_TASK_SCRIPT=tasks/pre_build.sh
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
||||||
|
DEPS_BUILD_TASK=build_static_lib_dbg
|
||||||
;;
|
;;
|
||||||
# executes $EXEC_FILE
|
# executes $EXEC_FILE
|
||||||
exec)
|
exec)
|
||||||
@ -87,7 +93,7 @@ case "$TASK" in
|
|||||||
;;
|
;;
|
||||||
# executes $EXEC_FILE with valgrind memory checker
|
# executes $EXEC_FILE with valgrind memory checker
|
||||||
valgrind)
|
valgrind)
|
||||||
VALGRIND_ARGS="-s --log-file=valgrind.log --read-var-info=yes --track-origins=yes --fullpath-after=$(pwd) --leak-check=full --show-leak-kinds=all"
|
VALGRIND_ARGS="-s --log-file=valgrind.log --read-var-info=yes --track-origins=yes --fullpath-after=$PROJECT/ --leak-check=full --show-leak-kinds=all"
|
||||||
TASK_SCRIPT=cbuild/default_tasks/valgrind.sh
|
TASK_SCRIPT=cbuild/default_tasks/valgrind.sh
|
||||||
;;
|
;;
|
||||||
# generates profiling info
|
# generates profiling info
|
||||||
@ -102,9 +108,10 @@ case "$TASK" in
|
|||||||
C_ARGS="-O2 -flto=auto -fuse-linker-plugin -fprofile-generate -fprofile-prefix-path=$(realpath $OBJDIR)/objects"
|
C_ARGS="-O2 -flto=auto -fuse-linker-plugin -fprofile-generate -fprofile-prefix-path=$(realpath $OBJDIR)/objects"
|
||||||
CPP_ARGS="$C_ARGS"
|
CPP_ARGS="$C_ARGS"
|
||||||
LINKER_ARGS="$CPP_ARGS"
|
LINKER_ARGS="$CPP_ARGS"
|
||||||
PRE_TASK_SCRIPT=
|
PRE_TASK_SCRIPT=tasks/pre_build.sh
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
||||||
POST_TASK_SCRIPT=cbuild/default_tasks/profile.sh
|
POST_TASK_SCRIPT=cbuild/default_tasks/profile.sh
|
||||||
|
DEPS_BUILD_TASK=build_static_lib
|
||||||
;;
|
;;
|
||||||
# compiles program with -pg and runs it with gprof
|
# compiles program with -pg and runs it with gprof
|
||||||
# uses gprof2dot python script to generate function call tree (pip install gprof2dot)
|
# uses gprof2dot python script to generate function call tree (pip install gprof2dot)
|
||||||
@ -115,9 +122,10 @@ case "$TASK" in
|
|||||||
C_ARGS="-O2 -flto=auto -fuse-linker-plugin -pg"
|
C_ARGS="-O2 -flto=auto -fuse-linker-plugin -pg"
|
||||||
CPP_ARGS="$C_ARGS"
|
CPP_ARGS="$C_ARGS"
|
||||||
LINKER_ARGS="$CPP_ARGS"
|
LINKER_ARGS="$CPP_ARGS"
|
||||||
PRE_TASK_SCRIPT=
|
PRE_TASK_SCRIPT=tasks/pre_build.sh
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
||||||
POST_TASK_SCRIPT=cbuild/default_tasks/gprof.sh
|
POST_TASK_SCRIPT=cbuild/default_tasks/gprof.sh
|
||||||
|
DEPS_BUILD_TASK=build_static_lib
|
||||||
;;
|
;;
|
||||||
# compiles executable with sanitizers and executes it to find errors and warnings
|
# compiles executable with sanitizers and executes it to find errors and warnings
|
||||||
sanitize)
|
sanitize)
|
||||||
@ -125,9 +133,10 @@ case "$TASK" in
|
|||||||
C_ARGS="-O0 -g3 -fsanitize=undefined,address"
|
C_ARGS="-O0 -g3 -fsanitize=undefined,address"
|
||||||
CPP_ARGS="$C_ARGS"
|
CPP_ARGS="$C_ARGS"
|
||||||
LINKER_ARGS="$CPP_ARGS"
|
LINKER_ARGS="$CPP_ARGS"
|
||||||
PRE_TASK_SCRIPT=
|
PRE_TASK_SCRIPT=tasks/pre_build.sh
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
||||||
POST_TASK_SCRIPT=cbuild/default_tasks/exec.sh
|
POST_TASK_SCRIPT=cbuild/default_tasks/exec.sh
|
||||||
|
DEPS_BUILD_TASK=build_static_lib
|
||||||
;;
|
;;
|
||||||
# compiles program and runs it with callgrind (part of valgrind)
|
# compiles program and runs it with callgrind (part of valgrind)
|
||||||
# uses gprof2dot python script to generate function call tree (pip install gprof2dot)
|
# uses gprof2dot python script to generate function call tree (pip install gprof2dot)
|
||||||
@ -139,7 +148,7 @@ case "$TASK" in
|
|||||||
C_ARGS="-O2 -flto=auto -fuse-linker-plugin"
|
C_ARGS="-O2 -flto=auto -fuse-linker-plugin"
|
||||||
CPP_ARGS="$C_ARGS"
|
CPP_ARGS="$C_ARGS"
|
||||||
LINKER_ARGS="$CPP_ARGS"
|
LINKER_ARGS="$CPP_ARGS"
|
||||||
PRE_TASK_SCRIPT=
|
PRE_TASK_SCRIPT=tasks/pre_build.sh
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
TASK_SCRIPT=cbuild/default_tasks/build_exec.sh
|
||||||
POST_TASK_SCRIPT=cbuild/default_tasks/callgrind.sh
|
POST_TASK_SCRIPT=cbuild/default_tasks/callgrind.sh
|
||||||
;;
|
;;
|
||||||
@ -149,7 +158,7 @@ case "$TASK" in
|
|||||||
POST_TASK_SCRIPT=tasks/clean_additions.sh
|
POST_TASK_SCRIPT=tasks/clean_additions.sh
|
||||||
;;
|
;;
|
||||||
# nothing to do
|
# nothing to do
|
||||||
"" | no_task)
|
no_task)
|
||||||
;;
|
;;
|
||||||
# unknown task
|
# unknown task
|
||||||
*)
|
*)
|
||||||
2
dependencies/.gitignore
vendored
2
dependencies/.gitignore
vendored
@ -1,2 +0,0 @@
|
|||||||
/include/
|
|
||||||
/precompiled/
|
|
||||||
1
dependencies/SDL2
vendored
Submodule
1
dependencies/SDL2
vendored
Submodule
@ -0,0 +1 @@
|
|||||||
|
Subproject commit 903d888cc31d283ccaaaa7e5b5a324c50a103e87
|
||||||
2
dependencies/imgui
vendored
2
dependencies/imgui
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 02cc7d451c65f249d64e92d267119fb3d624fda6
|
Subproject commit fc74d2ab7d44709d9c3245e323dbfce6a1ac4ac0
|
||||||
12
dependencies/imgui.config
vendored
12
dependencies/imgui.config
vendored
@ -1,12 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
DEP_WORKING_DIR='dependencies/imgui'
|
|
||||||
DEP_PRE_BUILD_COMMAND=''
|
|
||||||
if [[ "$TASK" = *_dbg ]]; then
|
|
||||||
DEP_BUILD_COMMAND='cbuild -c ../imgui.project.config build_static_lib_dbg'
|
|
||||||
else
|
|
||||||
DEP_BUILD_COMMAND='cbuild -c ../imgui.project.config build_static_lib'
|
|
||||||
fi
|
|
||||||
DEP_POST_BUILD_COMMAND=''
|
|
||||||
DEP_CLEAN_COMMAND='cbuild clean -c ../imgui.project.config'
|
|
||||||
DEP_STATIC_OUT_FILES='../bin/libimgui.a'
|
|
||||||
DEP_DYNAMIC_OUT_FILES=''
|
|
||||||
101
dependencies/imgui.project.config
vendored
101
dependencies/imgui.project.config
vendored
@ -1,101 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
CBUILD_VERSION=2.1.2
|
|
||||||
CONFIG_VERSION=1
|
|
||||||
|
|
||||||
PROJECT="imgui"
|
|
||||||
CMP_C="gcc"
|
|
||||||
CMP_CPP="g++"
|
|
||||||
STD_C="c11"
|
|
||||||
STD_CPP="c++11"
|
|
||||||
WARN_C="-Wall -Wno-discarded-qualifiers -Wno-unused-parameter"
|
|
||||||
WARN_CPP="-Wall -Wno-unused-parameter"
|
|
||||||
SRC_C=""
|
|
||||||
SRC_CPP="imgui.cpp
|
|
||||||
imgui_demo.cpp
|
|
||||||
imgui_draw.cpp
|
|
||||||
imgui_tables.cpp
|
|
||||||
imgui_widgets.cpp
|
|
||||||
backends/imgui_impl_sdl2.cpp
|
|
||||||
backends/imgui_impl_opengl3.cpp"
|
|
||||||
|
|
||||||
# Directory with dependency configs.
|
|
||||||
# See cbuild/example_dependency_configs
|
|
||||||
DEPENDENCY_CONFIGS_DIR='dependencies'
|
|
||||||
# List of dependency config files in DEPENDENCY_CONFIGS_DIR separated by space.
|
|
||||||
ENABLED_DEPENDENCIES=''
|
|
||||||
|
|
||||||
# OBJDIR structure:
|
|
||||||
# ├── objects/ - Compiled object files. Cleans on each call of build task
|
|
||||||
# ├── static_libs/ - Symbolic links to static libraries used by linker. Cleans on each call of build task.
|
|
||||||
# ├── static_libs/ - Symbolic links to dynamic libraries used by linker. Cleans on each call of build task.
|
|
||||||
# └── profile/ - gcc *.gcda profiling info files
|
|
||||||
OBJDIR="../obj"
|
|
||||||
OUTDIR="../bin"
|
|
||||||
STATIC_LIB_FILE="lib$PROJECT.a"
|
|
||||||
|
|
||||||
# header include directories
|
|
||||||
INCLUDE="-I. -I../include/SDL2"
|
|
||||||
|
|
||||||
# OS-specific options
|
|
||||||
case "$OS" in
|
|
||||||
WINDOWS)
|
|
||||||
EXEC_FILE="$PROJECT.exe"
|
|
||||||
SHARED_LIB_FILE="lib$PROJECT.dll"
|
|
||||||
;;
|
|
||||||
LINUX)
|
|
||||||
EXEC_FILE="$PROJECT"
|
|
||||||
SHARED_LIB_FILE="lib$PROJECT.so"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
error "operating system $OS has no configuration variants"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# TASKS
|
|
||||||
case "$TASK" in
|
|
||||||
# creates shared library
|
|
||||||
build_shared_lib)
|
|
||||||
C_ARGS="-O2 -fpic -flto -shared"
|
|
||||||
CPP_ARGS="$C_ARGS"
|
|
||||||
LINKER_ARGS="$CPP_ARGS -Wl,-soname,$SHARED_LIB_FILE"
|
|
||||||
PRE_TASK_SCRIPT=
|
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_shared_lib.sh
|
|
||||||
POST_TASK_SCRIPT=
|
|
||||||
;;
|
|
||||||
# creates shared library with debug symbols and no optimizations
|
|
||||||
build_shared_lib_dbg)
|
|
||||||
C_ARGS="-O0 -g3 -fpic -shared"
|
|
||||||
CPP_ARGS="$C_ARGS"
|
|
||||||
LINKER_ARGS="$CPP_ARGS -Wl,-soname,$SHARED_LIB_FILE"
|
|
||||||
PRE_TASK_SCRIPT=
|
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_shared_lib.sh
|
|
||||||
POST_TASK_SCRIPT=
|
|
||||||
;;
|
|
||||||
# creates static library
|
|
||||||
build_static_lib)
|
|
||||||
C_ARGS="-O2"
|
|
||||||
CPP_ARGS="$C_ARGS"
|
|
||||||
PRE_TASK_SCRIPT=
|
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_static_lib.sh
|
|
||||||
POST_TASK_SCRIPT=
|
|
||||||
;;
|
|
||||||
# creates static library with debug symbols and no optimizations
|
|
||||||
build_static_lib_dbg)
|
|
||||||
C_ARGS="-O0 -g3"
|
|
||||||
CPP_ARGS="$C_ARGS"
|
|
||||||
PRE_TASK_SCRIPT=
|
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_static_lib.sh
|
|
||||||
POST_TASK_SCRIPT=
|
|
||||||
;;
|
|
||||||
# deletes generated files
|
|
||||||
clean)
|
|
||||||
TASK_SCRIPT=cbuild/default_tasks/clean.sh
|
|
||||||
;;
|
|
||||||
# nothing to do
|
|
||||||
"" | no_task)
|
|
||||||
;;
|
|
||||||
# unknown task
|
|
||||||
*)
|
|
||||||
error "task <$TASK> not found"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
2
dependencies/imnodes
vendored
2
dependencies/imnodes
vendored
@ -1 +1 @@
|
|||||||
Subproject commit 8563e1655bd9bb1f249e6552cc6274d506ee788b
|
Subproject commit bbdb8be78f6fc1bf1ef842e752ee70f1c3c620a4
|
||||||
12
dependencies/imnodes.config
vendored
12
dependencies/imnodes.config
vendored
@ -1,12 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
DEP_WORKING_DIR='dependencies/imnodes'
|
|
||||||
DEP_PRE_BUILD_COMMAND=''
|
|
||||||
if [[ "$TASK" = *_dbg ]]; then
|
|
||||||
DEP_BUILD_COMMAND='cbuild -c ../imnodes.project.config build_static_lib_dbg'
|
|
||||||
else
|
|
||||||
DEP_BUILD_COMMAND='cbuild -c ../imnodes.project.config build_static_lib'
|
|
||||||
fi
|
|
||||||
DEP_POST_BUILD_COMMAND=''
|
|
||||||
DEP_CLEAN_COMMAND='cbuild clean -c ../imnodes.project.config'
|
|
||||||
DEP_STATIC_OUT_FILES='../bin/libimnodes.a'
|
|
||||||
DEP_DYNAMIC_OUT_FILES=''
|
|
||||||
95
dependencies/imnodes.project.config
vendored
95
dependencies/imnodes.project.config
vendored
@ -1,95 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
CBUILD_VERSION=2.1.2
|
|
||||||
CONFIG_VERSION=1
|
|
||||||
|
|
||||||
PROJECT="imnodes"
|
|
||||||
CMP_C="gcc"
|
|
||||||
CMP_CPP="g++"
|
|
||||||
STD_C="c11"
|
|
||||||
STD_CPP="c++11"
|
|
||||||
WARN_C="-Wall -Wno-discarded-qualifiers -Wno-unused-parameter"
|
|
||||||
WARN_CPP="-Wall -Wno-unused-parameter"
|
|
||||||
SRC_C=""
|
|
||||||
SRC_CPP="imnodes.cpp"
|
|
||||||
|
|
||||||
# Directory with dependency configs.
|
|
||||||
# See cbuild/example_dependency_configs
|
|
||||||
DEPENDENCY_CONFIGS_DIR='dependencies'
|
|
||||||
# List of dependency config files in DEPENDENCY_CONFIGS_DIR separated by space.
|
|
||||||
ENABLED_DEPENDENCIES=''
|
|
||||||
|
|
||||||
# OBJDIR structure:
|
|
||||||
# ├── objects/ - Compiled object files. Cleans on each call of build task
|
|
||||||
# ├── static_libs/ - Symbolic links to static libraries used by linker. Cleans on each call of build task.
|
|
||||||
# ├── static_libs/ - Symbolic links to dynamic libraries used by linker. Cleans on each call of build task.
|
|
||||||
# └── profile/ - gcc *.gcda profiling info files
|
|
||||||
OBJDIR="../obj"
|
|
||||||
OUTDIR="../bin"
|
|
||||||
STATIC_LIB_FILE="lib$PROJECT.a"
|
|
||||||
|
|
||||||
# header include directories
|
|
||||||
INCLUDE="-I. -I../imgui -I../imgui/backends"
|
|
||||||
|
|
||||||
# OS-specific options
|
|
||||||
case "$OS" in
|
|
||||||
WINDOWS)
|
|
||||||
EXEC_FILE="$PROJECT.exe"
|
|
||||||
SHARED_LIB_FILE="lib$PROJECT.dll"
|
|
||||||
;;
|
|
||||||
LINUX)
|
|
||||||
EXEC_FILE="$PROJECT"
|
|
||||||
SHARED_LIB_FILE="lib$PROJECT.so"
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
error "operating system $OS has no configuration variants"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
|
|
||||||
# TASKS
|
|
||||||
case "$TASK" in
|
|
||||||
# creates shared library
|
|
||||||
build_shared_lib)
|
|
||||||
C_ARGS="-O2 -fpic -flto -shared"
|
|
||||||
CPP_ARGS="$C_ARGS"
|
|
||||||
LINKER_ARGS="$CPP_ARGS -Wl,-soname,$SHARED_LIB_FILE"
|
|
||||||
PRE_TASK_SCRIPT=
|
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_shared_lib.sh
|
|
||||||
POST_TASK_SCRIPT=
|
|
||||||
;;
|
|
||||||
# creates shared library with debug symbols and no optimizations
|
|
||||||
build_shared_lib_dbg)
|
|
||||||
C_ARGS="-O0 -g3 -fpic -shared"
|
|
||||||
CPP_ARGS="$C_ARGS"
|
|
||||||
LINKER_ARGS="$CPP_ARGS -Wl,-soname,$SHARED_LIB_FILE"
|
|
||||||
PRE_TASK_SCRIPT=
|
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_shared_lib.sh
|
|
||||||
POST_TASK_SCRIPT=
|
|
||||||
;;
|
|
||||||
# creates static library
|
|
||||||
build_static_lib)
|
|
||||||
C_ARGS="-O2"
|
|
||||||
CPP_ARGS="$C_ARGS"
|
|
||||||
PRE_TASK_SCRIPT=
|
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_static_lib.sh
|
|
||||||
POST_TASK_SCRIPT=
|
|
||||||
;;
|
|
||||||
# creates static library with debug symbols and no optimizations
|
|
||||||
build_static_lib_dbg)
|
|
||||||
C_ARGS="-O0 -g3"
|
|
||||||
CPP_ARGS="$C_ARGS"
|
|
||||||
PRE_TASK_SCRIPT=
|
|
||||||
TASK_SCRIPT=cbuild/default_tasks/build_static_lib.sh
|
|
||||||
POST_TASK_SCRIPT=
|
|
||||||
;;
|
|
||||||
# deletes generated files
|
|
||||||
clean)
|
|
||||||
TASK_SCRIPT=cbuild/default_tasks/clean.sh
|
|
||||||
;;
|
|
||||||
# nothing to do
|
|
||||||
"" | no_task)
|
|
||||||
;;
|
|
||||||
# unknown task
|
|
||||||
*)
|
|
||||||
error "task <$TASK> not found"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
2
dependencies/kerep
vendored
2
dependencies/kerep
vendored
@ -1 +1 @@
|
|||||||
Subproject commit e722cd0353ed08a6bc9789835020bb1271e8e24c
|
Subproject commit 0e370b31ba98ec85720a4a5295b995348c247d3c
|
||||||
14
dependencies/kerep.config
vendored
14
dependencies/kerep.config
vendored
@ -1,14 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
DEP_WORKING_DIR='dependencies/kerep'
|
|
||||||
DEP_PRE_BUILD_COMMAND=''
|
|
||||||
if [[ "$TASK" = *_dbg ]]; then
|
|
||||||
DEP_BUILD_COMMAND='cbuild build_static_lib_dbg'
|
|
||||||
else
|
|
||||||
DEP_BUILD_COMMAND='cbuild build_static_lib'
|
|
||||||
fi
|
|
||||||
DEP_POST_BUILD_COMMAND=''
|
|
||||||
DEP_CLEAN_COMMAND='cbuild clean'
|
|
||||||
# won't be copied to project $OUTDIR
|
|
||||||
DEP_STATIC_OUT_FILES='bin/libkerep.a'
|
|
||||||
# will be copied tp project $OUTDIR
|
|
||||||
DEP_DYNAMIC_OUT_FILES=''
|
|
||||||
20
dependencies/precompiled.config
vendored
20
dependencies/precompiled.config
vendored
@ -1,20 +0,0 @@
|
|||||||
#!/usr/bin/env bash
|
|
||||||
DEP_WORKING_DIR='dependencies/precompiled'
|
|
||||||
DEP_PRE_BUILD_COMMAND=''
|
|
||||||
DEP_BUILD_COMMAND=''
|
|
||||||
DEP_POST_BUILD_COMMAND=''
|
|
||||||
DEP_CLEAN_COMMAND=''
|
|
||||||
# won't be copied to project $OUTDIR
|
|
||||||
DEP_STATIC_OUT_FILES=$(find dependencies/precompiled -name '*.a' | sed 's,dependencies/precompiled/,,')
|
|
||||||
# will be copied tp project $OUTDIR
|
|
||||||
case $OS in
|
|
||||||
WINDOWS)
|
|
||||||
DEP_DYNAMIC_OUT_FILES=$(find dependencies/precompiled -name '*.dll' | sed 's,dependencies/precompiled/,,')
|
|
||||||
;;
|
|
||||||
LINUX)
|
|
||||||
DEP_DYNAMIC_OUT_FILES=$(find dependencies/precompiled -name '*.so' | sed 's,dependencies/precompiled/,,')
|
|
||||||
;;
|
|
||||||
*)
|
|
||||||
error "operating system $OS has no configuration variants"
|
|
||||||
;;
|
|
||||||
esac
|
|
||||||
@ -2,20 +2,8 @@
|
|||||||
|
|
||||||
namespace GraphC::GraphModel {
|
namespace GraphC::GraphModel {
|
||||||
|
|
||||||
|
|
||||||
Attribute::Attribute(id_t _id, Node* _parent_node, Attribute::Type _type, std::string _title)
|
Attribute::Attribute(id_t _id, Node* _parent_node, Attribute::Type _type, std::string _title)
|
||||||
: type(_type), id(_id), parent_node(_parent_node), title(_title)
|
: id(_id), parent_node(_parent_node), type(_type), title(_title)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Attribute::Attribute() : Attribute(id_t_invalid, nullptr, Attribute::Type::Static, "NULL_ATTR")
|
|
||||||
{}
|
|
||||||
|
|
||||||
const RBTree<id_t, Edge*>& Attribute::getIncomingEdges() const {
|
|
||||||
return incoming_edges;
|
|
||||||
}
|
|
||||||
|
|
||||||
const RBTree<id_t, Edge*>& Attribute::getOutgoingEdges() const {
|
|
||||||
return outgoing_edges;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3,10 +3,7 @@
|
|||||||
namespace GraphC::GraphModel {
|
namespace GraphC::GraphModel {
|
||||||
|
|
||||||
Edge::Edge(id_t _id, id_t _from_attr_id, id_t _to_attr_id)
|
Edge::Edge(id_t _id, id_t _from_attr_id, id_t _to_attr_id)
|
||||||
: id(_id), to_attr_id(_to_attr_id), from_attr_id(_from_attr_id)
|
: id(_id), from_attr_id(_from_attr_id), to_attr_id(_to_attr_id)
|
||||||
{}
|
|
||||||
|
|
||||||
Edge::Edge() : Edge(id_t_invalid, id_t_invalid, id_t_invalid)
|
|
||||||
{}
|
{}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
@ -1,168 +1,47 @@
|
|||||||
#include "GraphModel.hpp"
|
#include "GraphModel.hpp"
|
||||||
#include "../UsefulException.hpp"
|
|
||||||
#include "../format.hpp"
|
|
||||||
|
|
||||||
namespace GraphC::GraphModel {
|
namespace GraphC::GraphModel {
|
||||||
|
|
||||||
Graph::Graph()
|
Graph::Graph()
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Graph::Graph(RBTree<id_t, Node>&& _nodes, RBTree<id_t, Edge>&& _edges)
|
Graph::Graph(RBTree<id_t, Node>& _nodes, RBTree<id_t, Edge>& _edges)
|
||||||
: nodes(_nodes), edges(_edges)
|
: nodes(_nodes), edges(_edges)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
|
RBTree<id_t, Node>& Graph::getNodes(){
|
||||||
const RBTree<id_t, Node>& Graph::getNodes() const {
|
|
||||||
return nodes;
|
return nodes;
|
||||||
}
|
}
|
||||||
|
|
||||||
Node* Graph::createNode(Node& n){
|
RBTree<id_t, Edge>& Graph::getEdges(){
|
||||||
Node* result = nullptr;
|
|
||||||
useful_assert(nodes.tryAdd(n.id, n, &result),
|
|
||||||
format("can't create node with id %i", n.id));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
Node* Graph::createNode(Node&& n){
|
|
||||||
return createNode(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Graph::tryGetNode(id_t node_id, Node** result) const {
|
|
||||||
return nodes.tryGet(node_id, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Graph::deleteNode(Node& n){
|
|
||||||
for(const auto& attr_p : n.attributes)
|
|
||||||
deleteAttribute(*attr_p.value);
|
|
||||||
useful_assert(nodes.tryDelete(n.id),
|
|
||||||
format("can't delete node with id %i", n.id));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Graph::deleteNode(Node&& n){
|
|
||||||
deleteNode(n);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Graph::tryDeleteNode(id_t node_id){
|
|
||||||
Node* n = nullptr;
|
|
||||||
if(!nodes.tryGet(node_id, &n))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
deleteNode(*n);
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
const RBTree<id_t, Edge>& Graph::getEdges() const {
|
|
||||||
return edges;
|
return edges;
|
||||||
}
|
}
|
||||||
|
|
||||||
Edge* Graph::createEdge(Attribute& from, Attribute& to){
|
|
||||||
id_t id = id_gen.getNext();
|
|
||||||
Edge* e = nullptr;
|
|
||||||
useful_assert(edges.tryAdd(id, Edge(id, from.id, to.id), &e),
|
|
||||||
format("can't create edge with id %i",id));
|
|
||||||
|
|
||||||
useful_assert(from.incoming_edges.tryAdd(id, e, nullptr),
|
bool tryCreateEdge(Attribute& from, Attribute& to, Edge&& result);
|
||||||
format("edge with id %i already exists in Attribute::incoming_edges", id));
|
bool tryGetEdge(id_t edge_id, Edge&& result);
|
||||||
|
bool tryDeleteEdge(id_t edge_id);
|
||||||
|
|
||||||
useful_assert(to.outgoing_edges.tryAdd(id, e, nullptr),
|
void Graph::deleteNode(id_t node_id){
|
||||||
format("edge with id %i already exists in Attribute::outgoing_edges", id));
|
if(nodes.erase(node_id) < 1)
|
||||||
return e;
|
throw UsefulException("can't erase node with id"+toString_i64(node_id));
|
||||||
}
|
}
|
||||||
|
|
||||||
Edge* Graph::createEdge(Attribute&& from, Attribute&& to){
|
void Graph::deleteEdge(id_t edge_id){
|
||||||
return createEdge(from, to);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Graph::tryCreateEdge(id_t from_attr_id, id_t to_attr_id, Edge** result){
|
|
||||||
Attribute* from;
|
|
||||||
if(!tryGetAttribute(from_attr_id, &from))
|
|
||||||
return false;
|
|
||||||
Attribute* to;
|
|
||||||
if(!tryGetAttribute(to_attr_id, &to))
|
|
||||||
return false;
|
|
||||||
Edge* e = createEdge(*from, *to);
|
|
||||||
if(result)
|
|
||||||
*result = e;
|
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Graph::tryGetEdge(id_t edge_id, Edge** result) const {
|
|
||||||
return edges.tryGet(edge_id, result);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Graph::deleteEdge(Edge& e){
|
|
||||||
Attribute* a = nullptr;
|
|
||||||
useful_assert(tryGetAttribute(e.from_attr_id, &a),
|
|
||||||
format("source attribute with id %i was not found in Graph::nodes", e.from_attr_id));
|
|
||||||
a->outgoing_edges.tryDelete(e.id);
|
|
||||||
|
|
||||||
useful_assert(tryGetAttribute(e.to_attr_id, &a),
|
|
||||||
format("destination attribute with id %i was not found in Graph::nodes", e.to_attr_id));
|
|
||||||
a->incoming_edges.tryDelete(e.id);
|
|
||||||
|
|
||||||
useful_assert(edges.tryDelete(e.id),
|
|
||||||
format("can't delete attribute with id %i", e.id));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Graph::deleteEdge(Edge&& e){
|
|
||||||
deleteEdge(e);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Graph::tryDeleteEdge(id_t edge_id){
|
|
||||||
Edge* e;
|
|
||||||
if(!edges.tryGet(edge_id, &e))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
deleteEdge(*e);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
const RBTree<id_t, Attribute>& Graph::getAttributes() const {
|
bool Graph::tryGetAttribute(id_t attr_id, Attribute*& result){
|
||||||
return attributes;
|
for(auto&& p_node : nodes){
|
||||||
}
|
auto&& node_attrs = p_node.second.getAttributes();
|
||||||
|
auto&& it = node_attrs.find(attr_id);
|
||||||
bool Graph::tryGetAttribute(id_t attr_id, Attribute** result) const {
|
if(it != node_attrs.end()){
|
||||||
return attributes.tryGet(attr_id, result);
|
result = &it->second;
|
||||||
}
|
return true;
|
||||||
|
}
|
||||||
Attribute* Graph::createAttribute(Attribute& a){
|
|
||||||
Attribute* result = nullptr;
|
|
||||||
useful_assert(attributes.tryAdd(a.id, a, &result),
|
|
||||||
format("can't create attribute with id %i to Graph", a.id));
|
|
||||||
useful_assert(a.parent_node->attributes.tryAdd(a.id, result, nullptr),
|
|
||||||
format("can't add attribute with id %i to Node", a.id));
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
Attribute* Graph::createAttribute(Attribute&& a){
|
|
||||||
return createAttribute(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
void Graph::deleteAttribute(Attribute& a){
|
|
||||||
for(const auto& edge_p : a.incoming_edges){
|
|
||||||
useful_assert(edges.tryDelete(edge_p.value->id),
|
|
||||||
format("can't find edge with id %i", edge_p.value->id));
|
|
||||||
}
|
}
|
||||||
for(const auto& edge_p : a.outgoing_edges){
|
return false;
|
||||||
useful_assert(edges.tryDelete(edge_p.value->id),
|
|
||||||
format("can't find edge with id %i", edge_p.value->id));
|
|
||||||
}
|
|
||||||
useful_assert(attributes.tryDelete(a.id),
|
|
||||||
format("can't delete attribute with id %i", a.id));
|
|
||||||
}
|
|
||||||
|
|
||||||
void Graph::deleteAttribute(Attribute&& a){
|
|
||||||
deleteAttribute(a);
|
|
||||||
}
|
|
||||||
|
|
||||||
bool Graph::tryDeleteAttribute(id_t attr_id){
|
|
||||||
Attribute* a;
|
|
||||||
if(!attributes.tryGet(attr_id, &a))
|
|
||||||
return false;
|
|
||||||
|
|
||||||
deleteAttribute(*a);
|
|
||||||
return true;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -9,7 +9,6 @@
|
|||||||
namespace GraphC::GraphModel {
|
namespace GraphC::GraphModel {
|
||||||
|
|
||||||
typedef i32 id_t;
|
typedef i32 id_t;
|
||||||
#define id_t_invalid ((id_t)-1)
|
|
||||||
|
|
||||||
class IdGenerator {
|
class IdGenerator {
|
||||||
id_t next_id=1;
|
id_t next_id=1;
|
||||||
@ -18,50 +17,39 @@ public:
|
|||||||
id_t getNext();
|
id_t getNext();
|
||||||
};
|
};
|
||||||
|
|
||||||
typedef class Node Node;
|
typedef struct Node Node;
|
||||||
typedef class Attribute Attribute;
|
|
||||||
typedef struct Edge Edge;
|
typedef struct Edge Edge;
|
||||||
typedef class Graph Graph;
|
|
||||||
|
|
||||||
class Attribute {
|
class Attribute {
|
||||||
friend class Graph;
|
std::vector<std::shared_ptr<Edge>> incoming_edges;
|
||||||
|
std::vector<std::shared_ptr<Edge>> outgoing_edges;
|
||||||
// pointers to instances in RBTree::edges
|
|
||||||
RBTree<id_t, Edge*> incoming_edges;
|
|
||||||
RBTree<id_t, Edge*> outgoing_edges;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
enum class Type {
|
enum class Type {
|
||||||
Static, Input, Output
|
Input, Output, Static
|
||||||
};
|
};
|
||||||
|
|
||||||
const Attribute::Type type;
|
const Attribute::Type type;
|
||||||
const id_t id;
|
const id_t id;
|
||||||
Node *const parent_node;
|
const Node* parent_node;
|
||||||
std::string title;
|
std::string title;
|
||||||
|
|
||||||
///@warning empty constructor for RBTree null-value node, do not use it
|
|
||||||
Attribute();
|
|
||||||
Attribute(id_t _id, Node* _parent_node, Attribute::Type _type, std::string _title);
|
Attribute(id_t _id, Node* _parent_node, Attribute::Type _type, std::string _title);
|
||||||
|
|
||||||
const RBTree<id_t, Edge*>& getIncomingEdges() const;
|
|
||||||
const RBTree<id_t, Edge*>& getOutgoingEdges() const;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
class Node {
|
class Node {
|
||||||
friend class Graph;
|
RBTree<id_t, Attribute> attributes;
|
||||||
// pointers to Attributes in Graph::attributes
|
|
||||||
RBTree<id_t, Attribute*> attributes;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
const id_t id;
|
const id_t id;
|
||||||
std::string title;
|
std::string title;
|
||||||
|
|
||||||
///@warning empty constructor for RBTree null-value node, do not use it
|
|
||||||
Node();
|
|
||||||
Node(id_t _id, std::string _title);
|
Node(id_t _id, std::string _title);
|
||||||
|
|
||||||
const RBTree<id_t, Attribute*>& getAttributes() const;
|
RBTree<id_t, Attribute>& getAttributes();
|
||||||
|
bool tryCreateAttribute(IdGenerator id_gen, Attribute*& result);
|
||||||
|
bool tryGetAttribute(id_t attr_id, Attribute*& result);
|
||||||
|
bool tryDeleteAttribute(id_t attr_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
struct Edge {
|
struct Edge {
|
||||||
@ -69,63 +57,34 @@ struct Edge {
|
|||||||
const id_t to_attr_id;
|
const id_t to_attr_id;
|
||||||
const id_t from_attr_id;
|
const id_t from_attr_id;
|
||||||
|
|
||||||
///@warning empty constructor for RBTree null-value node, do not use it
|
|
||||||
Edge();
|
|
||||||
Edge(id_t _id, id_t _from_attr_id, id_t _to_attr_id);
|
Edge(id_t _id, id_t _from_attr_id, id_t _to_attr_id);
|
||||||
};
|
};
|
||||||
|
|
||||||
class Graph {
|
class Graph {
|
||||||
|
friend class Attribute;
|
||||||
|
friend class Node;
|
||||||
|
friend class Edge;
|
||||||
|
|
||||||
RBTree<id_t, Node> nodes;
|
RBTree<id_t, Node> nodes;
|
||||||
RBTree<id_t, Edge> edges;
|
RBTree<id_t, Edge> edges;
|
||||||
RBTree<id_t, Attribute> attributes;
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
IdGenerator id_gen;
|
IdGenerator id_gen;
|
||||||
|
|
||||||
Graph();
|
Graph();
|
||||||
Graph(RBTree<id_t, Node>&& _nodes, RBTree<id_t, Edge>&& _edges);
|
Graph(RBTree<id_t, Node>& _nodes, RBTree<id_t, Edge>& _edges);
|
||||||
|
|
||||||
|
RBTree<id_t, Node>& getNodes();
|
||||||
const RBTree<id_t, Node>& getNodes() const;
|
bool tryCreateNode(std::string _title, Node*& result);
|
||||||
|
bool tryGetNode(id_t node_id, Node*& result);
|
||||||
Node* createNode(Node& n);
|
|
||||||
Node* createNode(Node&& n);
|
|
||||||
|
|
||||||
///@param result nullable
|
|
||||||
bool tryGetNode(id_t node_id, Node** result) const;
|
|
||||||
|
|
||||||
void deleteNode(Node& n);
|
|
||||||
void deleteNode(Node&& n);
|
|
||||||
bool tryDeleteNode(id_t node_id);
|
bool tryDeleteNode(id_t node_id);
|
||||||
|
|
||||||
|
RBTree<id_t, Edge>& getEdges();
|
||||||
const RBTree<id_t, Edge>& getEdges() const;
|
bool tryCreateEdge(Attribute& from, Attribute& to, Edge*& result);
|
||||||
|
bool tryGetEdge(id_t edge_id, Edge*& result);
|
||||||
Edge* createEdge(Attribute& from, Attribute& to);
|
|
||||||
Edge* createEdge(Attribute&& from, Attribute&& to);
|
|
||||||
|
|
||||||
///@param result nullable
|
|
||||||
bool tryCreateEdge(id_t from_attr_id, id_t to_attr_id, Edge** result);
|
|
||||||
|
|
||||||
///@param result nullable
|
|
||||||
bool tryGetEdge(id_t edge_id, Edge** result) const;
|
|
||||||
|
|
||||||
void deleteEdge(Edge& e);
|
|
||||||
void deleteEdge(Edge&& e);
|
|
||||||
bool tryDeleteEdge(id_t edge_id);
|
bool tryDeleteEdge(id_t edge_id);
|
||||||
|
|
||||||
|
bool tryGetAttribute(id_t attr_id, Attribute*& result);
|
||||||
const RBTree<id_t, Attribute>& getAttributes() const;
|
|
||||||
|
|
||||||
Attribute* createAttribute(Attribute& attr);
|
|
||||||
Attribute* createAttribute(Attribute&& attr);
|
|
||||||
|
|
||||||
///@param result nullable
|
|
||||||
bool tryGetAttribute(id_t attr_id, Attribute** result) const;
|
|
||||||
|
|
||||||
void deleteAttribute(Attribute& a);
|
|
||||||
void deleteAttribute(Attribute&& a);
|
|
||||||
bool tryDeleteAttribute(id_t attr_id);
|
|
||||||
};
|
};
|
||||||
|
|
||||||
}
|
}
|
||||||
@ -6,11 +6,4 @@ Node::Node(id_t _id, std::string _title)
|
|||||||
: id(_id), title(_title)
|
: id(_id), title(_title)
|
||||||
{}
|
{}
|
||||||
|
|
||||||
Node::Node() : Node(id_t_invalid, "NULL_NODE")
|
|
||||||
{}
|
|
||||||
|
|
||||||
const RBTree<id_t, Attribute*>& Node::getAttributes() const {
|
|
||||||
return attributes;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|||||||
585
src/RBTree.hpp
585
src/RBTree.hpp
@ -1,111 +1,76 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <sstream>
|
#include "../../dependencies/kerep/src/base/base.h"
|
||||||
#include "UsefulException.hpp"
|
#include <map>
|
||||||
|
#include <memory>
|
||||||
|
|
||||||
template<typename TKey, typename TVal>
|
// template<typename TKey, typename TVal>
|
||||||
|
typedef char* TKey;
|
||||||
|
typedef char* TVal;
|
||||||
class RBTree {
|
class RBTree {
|
||||||
enum class Color {
|
enum class Color {
|
||||||
Red, Black
|
Red, Black
|
||||||
};
|
};
|
||||||
|
|
||||||
// public version of struct Node
|
struct Node {
|
||||||
// TreeIterator returns a reference to KVPair to hide all other stuff from users
|
|
||||||
public:
|
|
||||||
struct KVPair {
|
|
||||||
// members are in reverse order to minimize padding and make struct Node smaller
|
|
||||||
|
|
||||||
TVal value;
|
|
||||||
TKey key;
|
TKey key;
|
||||||
|
TVal value;
|
||||||
KVPair(TKey& k, TVal& v) : value(v), key(k)
|
|
||||||
{}
|
|
||||||
|
|
||||||
protected:
|
|
||||||
// special constructor for tree leafs (null nodes)
|
|
||||||
// leaves key and value uninitialized
|
|
||||||
KVPair()
|
|
||||||
{}
|
|
||||||
};
|
|
||||||
|
|
||||||
private:
|
|
||||||
struct Node : public KVPair {
|
|
||||||
// stacks with KVPair::key if it is 32-bit or smaller
|
|
||||||
Color color;
|
Color color;
|
||||||
Node* parent;
|
Node* parent;
|
||||||
Node* left;
|
Node* left = nullptr;
|
||||||
Node* right;
|
Node* right = nullptr;
|
||||||
|
|
||||||
Node(TKey& _key, TVal& _val, Color _color, Node* _parent, Node* _left, Node* _right)
|
Node(TKey _key, TVal _val, Color _color, Node* _parent){
|
||||||
: KVPair(_key, _val), color(_color), parent(_parent), left(_left), right(_right)
|
key = _key;
|
||||||
{}
|
value = _val;
|
||||||
|
color = _color;
|
||||||
Node() : color(Color::Black), parent(this), left(this), right(this)
|
parent = _parent;
|
||||||
{}
|
|
||||||
|
|
||||||
bool isLeaf() const {
|
|
||||||
return parent == this;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
~Node(){
|
~Node(){
|
||||||
if(!left->isLeaf())
|
if(left != nullptr)
|
||||||
delete left;
|
delete left;
|
||||||
if(!right->isLeaf())
|
if(right != nullptr)
|
||||||
delete right;
|
delete right;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// if is leaf returns itself
|
inline Node* getSibling(){
|
||||||
Node* getMinChild() {
|
if(parent == nullptr)
|
||||||
Node* n = this;
|
return nullptr;
|
||||||
while(!n->left->isLeaf())
|
else if(parent->left == this)
|
||||||
n = n->left;
|
return parent->right;
|
||||||
return n;
|
else return parent->left;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// if is leaf returns itself
|
inline Node* getGrandparent(){
|
||||||
Node* getMaxChild() {
|
if(parent == nullptr)
|
||||||
Node* n = this;
|
return nullptr;
|
||||||
while(!n->right->isLeaf())
|
else return parent->parent;
|
||||||
n = n->right;
|
}
|
||||||
return n;
|
|
||||||
|
inline Node* getUncle(){
|
||||||
|
if(parent == nullptr)
|
||||||
|
return nullptr;
|
||||||
|
return parent->getSibling();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Node* root = nullptr;
|
||||||
static Node null_node;
|
|
||||||
static Node* null_node_ptr;
|
|
||||||
Node* root = &null_node;
|
|
||||||
|
|
||||||
|
|
||||||
///@returns null if root is null
|
|
||||||
Node* findParentForKey(TKey key) const {
|
|
||||||
Node* n = root;
|
|
||||||
Node* parent = null_node_ptr;
|
|
||||||
while(n != null_node_ptr){
|
|
||||||
parent = n;
|
|
||||||
if(key < n->key)
|
|
||||||
n = n->left;
|
|
||||||
else if(key > n->key)
|
|
||||||
n = n->right;
|
|
||||||
else return n->parent; // key == n->key
|
|
||||||
}
|
|
||||||
return parent;
|
|
||||||
}
|
|
||||||
|
|
||||||
void rotateLeft(Node* x){
|
void rotateLeft(Node* x){
|
||||||
// 1. get right child of x
|
// 1. get right child of x
|
||||||
Node* y = x->right;
|
Node* y = x->right;
|
||||||
// 2. move y to the position of x
|
// 2. move y to the position of x
|
||||||
y->parent = x->parent;
|
y->parent = x->parent;
|
||||||
if(x->parent != null_node_ptr){ // x != root
|
if (x->parent != nullptr){ // x != root
|
||||||
if(x == x->parent->left)
|
if(x == x->parent->left)
|
||||||
x->parent->left = y;
|
x->parent->left = y;
|
||||||
else x->parent->right = y;
|
else x->parent->right = y;
|
||||||
|
// TODO: maybe should set root to y?
|
||||||
}
|
}
|
||||||
else root = y;
|
|
||||||
// 3. move y.left to x.right if it exists
|
// 3. move y.left to x.right if it exists
|
||||||
x->right = y->left;
|
x->right = y->left;
|
||||||
if(x->right != null_node_ptr)
|
if (x->right != nullptr)
|
||||||
x->right->parent = x;
|
x->right->parent = x;
|
||||||
// 4. move x to y.left
|
// 4. move x to y.left
|
||||||
y->left = x;
|
y->left = x;
|
||||||
@ -117,198 +82,180 @@ private:
|
|||||||
Node* y = x->left;
|
Node* y = x->left;
|
||||||
// 2. move y up
|
// 2. move y up
|
||||||
y->parent = x->parent;
|
y->parent = x->parent;
|
||||||
if(x->parent != null_node_ptr){ // x != root
|
if (x->parent != nullptr){ // x != root
|
||||||
if(x == x->parent->left)
|
if(x == x->parent->left)
|
||||||
x->parent->left = y;
|
x->parent->left = y;
|
||||||
else x->parent->right = y;
|
else x->parent->right = y;
|
||||||
}
|
}
|
||||||
else root = y;
|
|
||||||
// 3. move y.right to x.left if it exists
|
// 3. move y.right to x.left if it exists
|
||||||
x->left = y->right;
|
x->left = y->right;
|
||||||
if(x->left != null_node_ptr)
|
if (x->left != nullptr)
|
||||||
x->left->parent = x;
|
x->left->parent = x;
|
||||||
// 4. move x to y.right
|
// 4. move x to y.right
|
||||||
y->right = x;
|
y->right = x;
|
||||||
x->parent = y;
|
x->parent = y;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
///@returns null if root is null
|
||||||
|
Node* findParentForKey(TKey key){
|
||||||
|
Node* n = root;
|
||||||
|
Node* parent = nullptr;
|
||||||
|
while(n != nullptr){
|
||||||
|
parent = n;
|
||||||
|
if(key < n->key)
|
||||||
|
n = n->left;
|
||||||
|
else if(key > n->key)
|
||||||
|
n = n->right;
|
||||||
|
else return nullptr; // key == n->key
|
||||||
|
}
|
||||||
|
return parent;
|
||||||
|
}
|
||||||
|
|
||||||
|
void fixupInsertion(Node* n){
|
||||||
|
// case 1: n is root -- root must be black
|
||||||
|
if (n->parent == nullptr){
|
||||||
|
n->color = Color::Black;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 2: parent is black -- no requirements mismatch
|
||||||
|
if (n->parent->color == Color::Black)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// case 3: parent and uncle are red -- red nodes must have black parents
|
||||||
|
Node* u = n->getUncle();
|
||||||
|
Node* g = n->getGrandparent();
|
||||||
|
if(u != nullptr && u->color == Color::Red){
|
||||||
|
n->parent->color = Color::Black;
|
||||||
|
u->color = Color::Black;
|
||||||
|
g->color = Color::Red;
|
||||||
|
fixupInsertion(g);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 4: parent is red and uncle is black -- red nodes must have black parents
|
||||||
|
if ((n == n->parent->right) && (n->parent == g->left)) {
|
||||||
|
rotateLeft(n->parent);
|
||||||
|
n = n->left;
|
||||||
|
}
|
||||||
|
else if ((n == n->parent->left) && (n->parent == g->right)) {
|
||||||
|
rotateRight(n->parent);
|
||||||
|
n = n->right;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 5
|
||||||
|
n->parent->color = Color::Black;
|
||||||
|
g->color = Color::Red;
|
||||||
|
if ((n == n->parent->left) && (n->parent == g->left))
|
||||||
|
rotateRight(g);
|
||||||
|
else rotateLeft(g);
|
||||||
|
}
|
||||||
|
|
||||||
|
void fixupDeletion(Node* n){
|
||||||
|
// case 1
|
||||||
|
if(n->parent == nullptr)
|
||||||
|
return;
|
||||||
|
|
||||||
|
// case 2
|
||||||
|
Node* s = n->getSibling();
|
||||||
|
if(s->color == Color::Red){
|
||||||
|
n->parent->color = Color::Red;
|
||||||
|
s->color = Color::Black;
|
||||||
|
if (n == n->parent->left)
|
||||||
|
rotateLeft(n->parent);
|
||||||
|
else rotateRight(n->parent);
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 3
|
||||||
|
if ((n->parent->color == Color::Black) &&
|
||||||
|
(s->color == Color::Black) &&
|
||||||
|
(s->left->color == Color::Black) &&
|
||||||
|
(s->right->color == Color::Black))
|
||||||
|
{
|
||||||
|
s->color = Color::Red;
|
||||||
|
fixupDeletion(n->parent);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 4
|
||||||
|
else if ((n->parent->color == Color::Red) &&
|
||||||
|
(s->color == Color::Black) &&
|
||||||
|
(s->left->color == Color::Black) &&
|
||||||
|
(s->right->color == Color::Black))
|
||||||
|
{
|
||||||
|
s->color = Color::Red;
|
||||||
|
n->parent->color = Color::Black;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 5
|
||||||
|
if(s->color == Color::Black) {
|
||||||
|
if ((n == n->parent->left) &&
|
||||||
|
(s->right->color == Color::Black) &&
|
||||||
|
(s->left->color == Color::Red))
|
||||||
|
{
|
||||||
|
s->color = Color::Red;
|
||||||
|
s->left->color = Color::Black;
|
||||||
|
rotateRight(s);
|
||||||
|
}
|
||||||
|
else if ((n == n->parent->right) &&
|
||||||
|
(s->left->color == Color::Black) &&
|
||||||
|
(s->right->color == Color::Red))
|
||||||
|
{
|
||||||
|
s->color = Color::Red;
|
||||||
|
s->right->color = Color::Black;
|
||||||
|
rotateLeft(s);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// case 6
|
||||||
|
s->color = n->parent->color;
|
||||||
|
n->parent->color = Color::Black;
|
||||||
|
|
||||||
|
if (n == n->parent->left) {
|
||||||
|
s->right->color = Color::Black;
|
||||||
|
rotateLeft(n->parent);
|
||||||
|
} else {
|
||||||
|
s->left->color = Color::Black;
|
||||||
|
rotateRight(n->parent);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void transplantNode(Node* old, Node* neww){
|
void transplantNode(Node* old, Node* neww){
|
||||||
if(old->parent == null_node_ptr)
|
neww->parent = old->parent;
|
||||||
|
if(old->parent == nullptr)
|
||||||
root = neww;
|
root = neww;
|
||||||
else if(old->parent->left == old)
|
else if(old->parent->left == old)
|
||||||
old->parent->left = neww;
|
old->parent->left = neww;
|
||||||
else old->parent->right = neww;
|
else old->parent->right = neww;
|
||||||
if(neww != null_node_ptr)
|
|
||||||
neww->parent = old->parent;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void fixupInsertion(Node* x){
|
// n should be not null
|
||||||
while(x != root && x->parent->color == Color::Red) {
|
Node* getMinimalChild(Node* n){
|
||||||
if(x->parent == x->parent->parent->left) {
|
while(n->left != nullptr)
|
||||||
Node* y = x->parent->parent->right;
|
n = n->left;
|
||||||
// uncle is red
|
return n;
|
||||||
if(y->color == Color::Red) {
|
|
||||||
x->parent->color = Color::Black;
|
|
||||||
y->color = Color::Black;
|
|
||||||
x->parent->parent->color = Color::Red;
|
|
||||||
x = x->parent->parent;
|
|
||||||
}
|
|
||||||
// uncle is black
|
|
||||||
else {
|
|
||||||
if(x == x->parent->right) {
|
|
||||||
// make x a left child
|
|
||||||
x = x->parent;
|
|
||||||
rotateLeft(x);
|
|
||||||
}
|
|
||||||
// recolor and rotate
|
|
||||||
x->parent->color = Color::Black;
|
|
||||||
x->parent->parent->color = Color::Red;
|
|
||||||
rotateRight(x->parent->parent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// mirrored above code
|
|
||||||
else {
|
|
||||||
Node* y = x->parent->parent->left;
|
|
||||||
// uncle is red
|
|
||||||
if(y->color == Color::Red) {
|
|
||||||
x->parent->color = Color::Black;
|
|
||||||
y->color = Color::Black;
|
|
||||||
x->parent->parent->color = Color::Red;
|
|
||||||
x = x->parent->parent;
|
|
||||||
}
|
|
||||||
// uncle is black
|
|
||||||
else {
|
|
||||||
if(x == x->parent->left) {
|
|
||||||
// make x a right child
|
|
||||||
x = x->parent;
|
|
||||||
rotateRight(x);
|
|
||||||
}
|
|
||||||
// recolor and rotate
|
|
||||||
x->parent->color = Color::Black;
|
|
||||||
x->parent->parent->color = Color::Red;
|
|
||||||
rotateLeft(x->parent->parent);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
root->color = Color::Black;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void fixupDeletion(Node* x){
|
// n should be not null
|
||||||
while(x != root && x->color == Color::Black) {
|
Node* getMaximalChild(Node* n){
|
||||||
if(x == x->parent->left) {
|
while(n->right != nullptr)
|
||||||
Node* w = x->parent->right;
|
n = n->right;
|
||||||
if(w->color == Color::Red) {
|
return n;
|
||||||
w->color = Color::Black;
|
|
||||||
x->parent->color = Color::Red;
|
|
||||||
rotateLeft(x->parent);
|
|
||||||
w = x->parent->right;
|
|
||||||
}
|
|
||||||
if(w->left->color == Color::Black && w->right->color == Color::Black) {
|
|
||||||
w->color = Color::Red;
|
|
||||||
x = x->parent;
|
|
||||||
} else {
|
|
||||||
if(w->right->color == Color::Black) {
|
|
||||||
w->left->color = Color::Black;
|
|
||||||
w->color = Color::Red;
|
|
||||||
rotateRight(w);
|
|
||||||
w = x->parent->right;
|
|
||||||
}
|
|
||||||
w->color = x->parent->color;
|
|
||||||
x->parent->color = Color::Black;
|
|
||||||
w->right->color = Color::Black;
|
|
||||||
rotateLeft(x->parent);
|
|
||||||
x = root;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
Node* w = x->parent->left;
|
|
||||||
if(w->color == Color::Red) {
|
|
||||||
w->color = Color::Black;
|
|
||||||
x->parent->color = Color::Red;
|
|
||||||
rotateRight(x->parent);
|
|
||||||
w = x->parent->left;
|
|
||||||
}
|
|
||||||
if(w->right->color == Color::Black && w->left->color == Color::Black) {
|
|
||||||
w->color = Color::Red;
|
|
||||||
x = x->parent;
|
|
||||||
} else {
|
|
||||||
if(w->left->color == Color::Black) {
|
|
||||||
w->right->color = Color::Black;
|
|
||||||
w->color = Color::Red;
|
|
||||||
rotateLeft(w);
|
|
||||||
w = x->parent->left;
|
|
||||||
}
|
|
||||||
w->color = x->parent->color;
|
|
||||||
x->parent->color = Color::Black;
|
|
||||||
w->left->color = Color::Black;
|
|
||||||
rotateRight(x->parent);
|
|
||||||
x = root;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
x->color = Color::Black;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
template<typename TreeIteratorValue>
|
|
||||||
struct TreeIterator {
|
|
||||||
Node* n;
|
|
||||||
|
|
||||||
TreeIterator(TreeIterator const& src){
|
|
||||||
n = src.n;
|
|
||||||
}
|
|
||||||
|
|
||||||
TreeIterator(Node* ptr){
|
|
||||||
n = ptr;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator!=(TreeIterator const& other) const {
|
|
||||||
return n != other.n;
|
|
||||||
}
|
|
||||||
|
|
||||||
bool operator==(TreeIterator const& other) const {
|
|
||||||
return n == other.n;
|
|
||||||
}
|
|
||||||
|
|
||||||
TreeIteratorValue& operator*() const {
|
|
||||||
if(!n->isLeaf())
|
|
||||||
return *n;
|
|
||||||
else throw UsefulException("the caller has tried to get the value of the end of an iterator (null node value)");
|
|
||||||
}
|
|
||||||
|
|
||||||
void operator++() {
|
|
||||||
if(n->isLeaf())
|
|
||||||
return;
|
|
||||||
if(!n->right->isLeaf())
|
|
||||||
n = n->right->getMinChild();
|
|
||||||
else {
|
|
||||||
Node* p = n->parent;
|
|
||||||
while(n == p->right){
|
|
||||||
n = p;
|
|
||||||
p = p->parent;
|
|
||||||
}
|
|
||||||
n = p;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
using iterator = TreeIterator<KVPair>;
|
|
||||||
using const_iterator = TreeIterator<const KVPair>;
|
|
||||||
|
|
||||||
RBTree() {}
|
RBTree() {}
|
||||||
|
|
||||||
~RBTree(){
|
~RBTree(){
|
||||||
if(!root->isLeaf())
|
delete root;
|
||||||
delete root;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
/// @param resultPtr nullable
|
|
||||||
bool tryAdd(TKey key, TVal& value, TVal** resultPtr){
|
bool tryAdd(TKey key, TVal& value, TVal*& result){
|
||||||
if(root == null_node_ptr){
|
if(root == nullptr){
|
||||||
root = new Node(key, value, Color::Black, null_node_ptr, null_node_ptr, null_node_ptr);
|
root = new Node(key, value, Color::Black, nullptr);
|
||||||
if(resultPtr)
|
|
||||||
*resultPtr = &root->value;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -320,35 +267,20 @@ public:
|
|||||||
else nodePtrPtr = &parent->right;
|
else nodePtrPtr = &parent->right;
|
||||||
|
|
||||||
// if a child node already exists at this place, returns false
|
// if a child node already exists at this place, returns false
|
||||||
if(*nodePtrPtr != null_node_ptr){
|
if(*nodePtrPtr != nullptr)
|
||||||
if(resultPtr)
|
|
||||||
*resultPtr = nullptr;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// places newNode to left or right of the parent
|
// places newNode to left or right of the parent
|
||||||
Node* newNode = new Node(key, value, Color::Red, parent, null_node_ptr, null_node_ptr);
|
Node* newNode = new Node(key, value, Color::Red, parent);
|
||||||
if(resultPtr)
|
|
||||||
*resultPtr = &newNode->value;
|
|
||||||
*nodePtrPtr = newNode;
|
*nodePtrPtr = newNode;
|
||||||
// auto-balancing
|
// auto-balancing
|
||||||
fixupInsertion(newNode);
|
fixupInsertion(newNode);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @param resultPtr nullable
|
bool trySet(TKey key, TVal& value){
|
||||||
bool tryAdd(TKey key, TVal&& value, TVal** resultPtr){
|
if(root == nullptr)
|
||||||
return tryAdd(key, value, resultPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// @param resultPtr nullable
|
|
||||||
bool trySet(TKey key, TVal& value, TVal** resultPtr){
|
|
||||||
if(root == null_node_ptr){
|
|
||||||
if(resultPtr)
|
|
||||||
*resultPtr = nullptr;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
Node* parent = findParentForKey(key);
|
Node* parent = findParentForKey(key);
|
||||||
// ptr to parent->right or parent->left
|
// ptr to parent->right or parent->left
|
||||||
@ -358,31 +290,17 @@ public:
|
|||||||
else nodePtrPtr = &parent->right;
|
else nodePtrPtr = &parent->right;
|
||||||
|
|
||||||
// if a child node with the given key doesn't exist, returns false
|
// if a child node with the given key doesn't exist, returns false
|
||||||
if(*nodePtrPtr == null_node_ptr){
|
if(*nodePtrPtr == nullptr)
|
||||||
if(resultPtr)
|
|
||||||
*resultPtr = nullptr;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
// replaces the value of left or right child of the parent
|
// replaces the value of left or right child of the parent
|
||||||
(*nodePtrPtr)->value = value;
|
(*nodePtrPtr)->value = value;
|
||||||
if(resultPtr)
|
|
||||||
*resultPtr = &(*nodePtrPtr)->value;
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @param resultPtr nullable
|
void addOrSet(TKey key, TVal& value){
|
||||||
bool trySet(TKey key, TVal&& value, TVal** resultPtr){
|
if(root == nullptr){
|
||||||
return trySet(key, value, resultPtr);
|
root = new Node(key, value, Color::Black, nullptr);
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
/// @param resultPtr nullable
|
|
||||||
void addOrSet(TKey key, TVal& value, TVal** resultPtr){
|
|
||||||
if(root == null_node_ptr){
|
|
||||||
root = new Node(key, value, Color::Black, null_node_ptr, null_node_ptr, null_node_ptr);
|
|
||||||
if(resultPtr != nullptr)
|
|
||||||
*resultPtr = &root->value;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -394,74 +312,53 @@ public:
|
|||||||
else nodePtrPtr = &parent->right;
|
else nodePtrPtr = &parent->right;
|
||||||
|
|
||||||
// if a child node already exists at this place, sets it's value
|
// if a child node already exists at this place, sets it's value
|
||||||
if(*nodePtrPtr != null_node_ptr){
|
if(*nodePtrPtr != nullptr){
|
||||||
(*nodePtrPtr)->value = value;
|
(*nodePtrPtr)->value = value;
|
||||||
if(resultPtr)
|
|
||||||
*resultPtr = &(*nodePtrPtr)->value;
|
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
// places newNode to left or right of the parent
|
// places newNode to left or right of the parent
|
||||||
Node* newNode = new Node(key, value, Color::Red, parent, null_node_ptr, null_node_ptr);
|
Node* newNode = new Node(key, value, Color::Red, parent);
|
||||||
if(resultPtr != nullptr)
|
|
||||||
*resultPtr = &newNode->value;
|
|
||||||
*nodePtrPtr = newNode;
|
*nodePtrPtr = newNode;
|
||||||
// auto-balancing
|
// auto-balancing
|
||||||
fixupInsertion(newNode);
|
fixupInsertion(newNode);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// @param resultPtr nullable
|
bool tryGet(TKey key, TVal** result){
|
||||||
void addOrSet(TKey key, TVal&& value, TVal** resultPtr){
|
|
||||||
addOrSet(key, value, resultPtr);
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
bool tryGet(TKey key, TVal** resultPtr) const {
|
|
||||||
if(!resultPtr)
|
|
||||||
return false;
|
|
||||||
Node* parent = findParentForKey(key);
|
Node* parent = findParentForKey(key);
|
||||||
Node* n = null_node_ptr;
|
Node* n;
|
||||||
if(parent == null_node_ptr)
|
if(key < parent->key)
|
||||||
n = root;
|
|
||||||
else if(key < parent->key)
|
|
||||||
n = parent->left;
|
n = parent->left;
|
||||||
else n = parent->right;
|
else n = parent->right;
|
||||||
// if there is no node with the given key
|
// if there is no node with the given key
|
||||||
if(n == null_node_ptr){
|
if(n == nullptr)
|
||||||
*resultPtr = nullptr;
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
*resultPtr = &n->value;
|
*result = &n->value;
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
bool tryDelete(TKey key){
|
bool tryDelete(TKey key){
|
||||||
Node* parent = findParentForKey(key);
|
Node* parent = findParentForKey(key);
|
||||||
Node* n = null_node_ptr;
|
Node* n;
|
||||||
if(parent == null_node_ptr)
|
if(key < parent->key)
|
||||||
n = root;
|
|
||||||
else if(key < parent->key)
|
|
||||||
n = parent->left;
|
n = parent->left;
|
||||||
else n = parent->right;
|
else n = parent->right;
|
||||||
// key not found
|
if(n == nullptr) // key not found
|
||||||
if(n == null_node_ptr){
|
|
||||||
return false;
|
return false;
|
||||||
}
|
|
||||||
|
|
||||||
if(n->left == null_node_ptr){
|
if(n->left == nullptr){
|
||||||
transplantNode(n, n->right);
|
transplantNode(n, n->right);
|
||||||
if(n->color == Color::Black && n->right != null_node_ptr)
|
if(n->color == Color::Black)
|
||||||
fixupDeletion(n->right);
|
fixupDeletion(n->right);
|
||||||
}
|
}
|
||||||
else if(n->right == null_node_ptr){
|
else if(n->right == nullptr){
|
||||||
transplantNode(n, n->left);
|
transplantNode(n, n->left);
|
||||||
if(n->color == Color::Black && n->left != null_node_ptr)
|
if(n->color == Color::Black)
|
||||||
fixupDeletion(n->left);
|
fixupDeletion(n->left);
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
Node* minNode = n->right->getMinChild();
|
Node* minNode = getMinimalChild(n->right);
|
||||||
if(minNode != n->right){
|
if(minNode != n->right){
|
||||||
transplantNode(minNode, minNode->right);
|
transplantNode(minNode, minNode->right);
|
||||||
minNode->right = n->right;
|
minNode->right = n->right;
|
||||||
@ -475,76 +372,6 @@ public:
|
|||||||
fixupDeletion(minNode->right);
|
fixupDeletion(minNode->right);
|
||||||
}
|
}
|
||||||
|
|
||||||
// delete node without children
|
|
||||||
n->left = null_node_ptr;
|
|
||||||
n->right = null_node_ptr;
|
|
||||||
delete n;
|
delete n;
|
||||||
return true;
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
iterator begin(){
|
|
||||||
if(root == null_node_ptr)
|
|
||||||
return iterator(null_node_ptr);
|
|
||||||
return iterator(root->getMinChild());
|
|
||||||
}
|
|
||||||
|
|
||||||
iterator end(){
|
|
||||||
return iterator(null_node_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator begin() const {
|
|
||||||
if(root == null_node_ptr)
|
|
||||||
return const_iterator(null_node_ptr);
|
|
||||||
return const_iterator(root->getMinChild());
|
|
||||||
}
|
|
||||||
|
|
||||||
const_iterator end() const {
|
|
||||||
return const_iterator(null_node_ptr);
|
|
||||||
}
|
|
||||||
|
|
||||||
void _generateGraphVizCodeForChildren(std::stringstream& ss, Node* n) const {
|
|
||||||
if(n == null_node_ptr)
|
|
||||||
return;
|
|
||||||
|
|
||||||
if(n->color == Color::Red)
|
|
||||||
ss<<" \""<<n->key<<"\" [color=red]\n";
|
|
||||||
|
|
||||||
if(n->left == null_node_ptr){
|
|
||||||
ss<<" \""<<n->key<<"\" -> \"null\" [side=L]\n";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ss<<" \""<<n->key<<"\" -> \""<<n->left->key<<"\" [side=L]\n";
|
|
||||||
_generateGraphVizCodeForChildren(ss, n->left);
|
|
||||||
}
|
|
||||||
|
|
||||||
if(n->right == null_node_ptr){
|
|
||||||
ss<<" \""<<n->key<<"\" -> \"null\" [side=R]\n";
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
ss<<" \""<<n->key<<"\" -> \""<<n->right->key<<"\" [side=R]\n";
|
|
||||||
_generateGraphVizCodeForChildren(ss, n->right);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
std::string generateGraphVizCode() const {
|
|
||||||
std::stringstream ss;
|
|
||||||
ss<<"digraph {\n"
|
|
||||||
" node [style=filled,color=gray];\n";
|
|
||||||
if(root == null_node_ptr)
|
|
||||||
ss<<" \"null\"\n";
|
|
||||||
else {
|
|
||||||
ss<<" \"null\" -> \""<<root->key<<"\"\n";
|
|
||||||
_generateGraphVizCodeForChildren(ss, root);
|
|
||||||
}
|
|
||||||
ss<<"}";
|
|
||||||
return ss.str();
|
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
template<typename TKey, typename TVal>
|
|
||||||
typename RBTree<TKey, TVal>::Node RBTree<TKey, TVal>::null_node;
|
|
||||||
|
|
||||||
template<typename TKey, typename TVal>
|
|
||||||
typename RBTree<TKey, TVal>::Node* RBTree<TKey, TVal>::null_node_ptr = &RBTree<TKey, TVal>::null_node;
|
|
||||||
|
|||||||
@ -1,12 +1,12 @@
|
|||||||
#include "UsefulException.hpp"
|
#include "UsefulException.hpp"
|
||||||
#include <sstream>
|
#include <sstream>
|
||||||
|
|
||||||
UsefulException_::UsefulException_(const std::string& _message, const std::string& _file, const std::string& _func, int _line_n)
|
UsefulException_::UsefulException_(std::string _message, std::string _file, std::string _func, int _line_n)
|
||||||
: message(_message), file(_file), function(_func), line_n(_line_n)
|
: message(_message), file(_file), function(_func), line_n(_line_n)
|
||||||
{
|
{
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
ss<<message<<'\n';
|
ss<<message<<'\n';
|
||||||
ss<<" at "<<file<<':'<<_line_n<<" in "<<function;
|
ss<<file<<':'<<_line_n<<" in "<<function;
|
||||||
complete_text = ss.str();
|
complete_text = ss.str();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -13,9 +13,7 @@ class UsefulException_ : public std::exception {
|
|||||||
std::string complete_text;
|
std::string complete_text;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
UsefulException_(const std::string& msg, const std::string& _file, const std::string& _func, int line_n);
|
UsefulException_(std::string msg, std::string _file, std::string _func, int line_n);
|
||||||
|
|
||||||
virtual char const* what() const noexcept;
|
virtual char const* what() const noexcept;
|
||||||
};
|
};
|
||||||
|
|
||||||
#define useful_assert(EXPR, ERRMSG) if(!EXPR) throw UsefulException(ERRMSG);
|
|
||||||
|
|||||||
@ -4,7 +4,7 @@
|
|||||||
#include "UsefulException.hpp"
|
#include "UsefulException.hpp"
|
||||||
#include "../dependencies/kerep/src/base/base.h"
|
#include "../dependencies/kerep/src/base/base.h"
|
||||||
|
|
||||||
std::string _format(const std::string& format_str, const size_t args_count, ...){
|
std::string format(const std::string format_str, size_t args_count, ...){
|
||||||
va_list vl;
|
va_list vl;
|
||||||
va_start(vl, args_count);
|
va_start(vl, args_count);
|
||||||
std::stringstream ss;
|
std::stringstream ss;
|
||||||
|
|||||||
@ -1,7 +1,5 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include <string>
|
#include <string>
|
||||||
#include "../dependencies/kerep/src/base/std.h"
|
|
||||||
|
|
||||||
std::string _format(const std::string& format_str, const size_t args_count, ...);
|
std::string format(const std::string format_str, size_t args_count, ...);
|
||||||
#define format(FORMAT_STR, ARGS...) _format(FORMAT_STR, count_args(ARGS) ,##ARGS)
|
|
||||||
|
|||||||
@ -1,179 +0,0 @@
|
|||||||
#include "gui.hpp"
|
|
||||||
#include <algorithm>
|
|
||||||
#include "GraphEditor.hpp"
|
|
||||||
|
|
||||||
namespace GraphC::gui {
|
|
||||||
|
|
||||||
void GraphEditor::drawNode(const GraphModel::Node& node){
|
|
||||||
ImNodes::BeginNode(node.id);
|
|
||||||
ImNodes::BeginNodeTitleBar();
|
|
||||||
ImGui::TextUnformatted(node.title.c_str());
|
|
||||||
ImNodes::EndNodeTitleBar();
|
|
||||||
|
|
||||||
for(auto& a_p : node.getAttributes()){
|
|
||||||
auto&& a = *a_p.value;
|
|
||||||
switch (a.type){
|
|
||||||
case GraphModel::Attribute::Type::Input:
|
|
||||||
ImNodes::BeginInputAttribute(a.id);
|
|
||||||
ImGui::Text("%s", a.title.c_str());
|
|
||||||
ImNodes::EndInputAttribute();
|
|
||||||
break;
|
|
||||||
case GraphModel::Attribute::Type::Output:
|
|
||||||
ImNodes::BeginOutputAttribute(a.id);
|
|
||||||
ImGui::Text("%s", a.title.c_str());
|
|
||||||
ImGui::Indent(40);
|
|
||||||
ImNodes::EndOutputAttribute();
|
|
||||||
break;
|
|
||||||
case GraphModel::Attribute::Type::Static:
|
|
||||||
ImNodes::BeginStaticAttribute(a.id);
|
|
||||||
ImGui::Text("%s", a.title.c_str());
|
|
||||||
ImNodes::EndStaticAttribute();
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
throw "Node::draw() invalid type";
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
static const char* items[]={
|
|
||||||
"static","input", "output"
|
|
||||||
};
|
|
||||||
static int selected_item_i = 0;
|
|
||||||
if(ImGui::Button("add attribute"))
|
|
||||||
ImGui::OpenPopup("new_attribute_popup");
|
|
||||||
|
|
||||||
if(ImGui::BeginPopup("new_attribute_popup")){
|
|
||||||
ImGui::SeparatorText("New attribute properties");
|
|
||||||
|
|
||||||
static char buf[256];
|
|
||||||
ImGui::InputText("label", buf, sizeof(buf));
|
|
||||||
|
|
||||||
if(ImGui::Button("select type"))
|
|
||||||
ImGui::OpenPopup("select_type_popup");
|
|
||||||
ImGui::SameLine();
|
|
||||||
ImGui::TextUnformatted(items[selected_item_i]);
|
|
||||||
|
|
||||||
if(ImGui::BeginPopup("select_type_popup")){
|
|
||||||
for (int i = 0; i < IM_ARRAYSIZE(items); i++)
|
|
||||||
if (ImGui::Selectable(items[i]))
|
|
||||||
selected_item_i = i;
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
if(ImGui::Button("Create attribute")){
|
|
||||||
graph.createAttribute(GraphModel::Attribute(
|
|
||||||
graph.id_gen.getNext(),
|
|
||||||
const_cast<GraphModel::Node*>(&node),
|
|
||||||
(GraphModel::Attribute::Type)selected_item_i,
|
|
||||||
std::string(buf)));
|
|
||||||
|
|
||||||
std::cout<<"ATTRIBUTES:\n";
|
|
||||||
std::cout<<graph.getAttributes().generateGraphVizCode()<<std::endl;
|
|
||||||
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
buf[0] = 0;
|
|
||||||
selected_item_i = 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
ImNodes::EndNode();
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
GraphModel::Node* GraphEditor::CreateExampleNode(const std::string& node_title){
|
|
||||||
GraphModel::Node* n = graph.createNode(GraphModel::Node(graph.id_gen.getNext(), node_title));
|
|
||||||
graph.createAttribute(GraphModel::Attribute(graph.id_gen.getNext(), n, GraphModel::Attribute::Type::Input, "In"));
|
|
||||||
graph.createAttribute(GraphModel::Attribute(graph.id_gen.getNext(), n, GraphModel::Attribute::Type::Output, "Out"));
|
|
||||||
graph.createAttribute(GraphModel::Attribute(graph.id_gen.getNext(), n, GraphModel::Attribute::Type::Static, "Static"));
|
|
||||||
return n;
|
|
||||||
}
|
|
||||||
|
|
||||||
GraphEditor::GraphEditor(const std::string& _title)
|
|
||||||
: title(_title)
|
|
||||||
{
|
|
||||||
// CreateExampleNode("Node A");
|
|
||||||
// CreateExampleNode("Node B");
|
|
||||||
// CreateExampleNode("Node C");
|
|
||||||
// CreateExampleNode("Node D");
|
|
||||||
std::cout<<"NODES:\n";
|
|
||||||
std::cout<<graph.getNodes().generateGraphVizCode()<<std::endl;
|
|
||||||
std::cout<<"ATTRIBUTES:\n";
|
|
||||||
std::cout<<graph.getAttributes().generateGraphVizCode()<<std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GraphEditor::show(){
|
|
||||||
editor_open = true;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GraphEditor::hide(){
|
|
||||||
editor_open = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
void GraphEditor::draw(){
|
|
||||||
if(!editor_open)
|
|
||||||
return;
|
|
||||||
|
|
||||||
ImGui::Begin(title.c_str(), &editor_open);
|
|
||||||
|
|
||||||
ImGui::SetWindowSizeMin(300,300);
|
|
||||||
|
|
||||||
if(ImGui::Button("create node")){
|
|
||||||
ImGui::OpenPopup("create_node_popup");
|
|
||||||
}
|
|
||||||
static char buf[256];
|
|
||||||
if(ImGui::BeginPopup("create_node_popup")){
|
|
||||||
ImGui::SeparatorText("New node properties");
|
|
||||||
ImGui::InputText("label", buf, sizeof(buf));
|
|
||||||
if(ImGui::Button("create node")){
|
|
||||||
graph.createNode(GraphModel::Node(graph.id_gen.getNext(), buf));
|
|
||||||
|
|
||||||
std::cout<<"NODES:\n";
|
|
||||||
std::cout<<graph.getNodes().generateGraphVizCode()<<std::endl;
|
|
||||||
|
|
||||||
buf[0] = 0;
|
|
||||||
ImGui::CloseCurrentPopup();
|
|
||||||
}
|
|
||||||
ImGui::EndPopup();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImNodes::BeginNodeEditor();
|
|
||||||
// draw nodes
|
|
||||||
for(auto& n_p : graph.getNodes()){
|
|
||||||
drawNode(n_p.value);
|
|
||||||
}
|
|
||||||
// draw edges
|
|
||||||
for(auto& p : graph.getEdges()){
|
|
||||||
ImNodes::Link(p.value.id, p.value.to_attr_id, p.value.from_attr_id);
|
|
||||||
}
|
|
||||||
|
|
||||||
ImNodes::EndNodeEditor();
|
|
||||||
|
|
||||||
// handle edge creation
|
|
||||||
GraphModel::id_t from_attr_id, to_attr_id;
|
|
||||||
if (ImNodes::IsLinkCreated(&from_attr_id, &to_attr_id))
|
|
||||||
{
|
|
||||||
if(!graph.tryCreateEdge(from_attr_id, to_attr_id, nullptr)){
|
|
||||||
ImGui::End();
|
|
||||||
throw UsefulException(format("can't create edge from attribute %i to attribute %i", from_attr_id, to_attr_id));
|
|
||||||
}
|
|
||||||
std::cout<<"EDGES:\n";
|
|
||||||
std::cout<<graph.getEdges().generateGraphVizCode()<<std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
// handle edge destruction
|
|
||||||
GraphModel::id_t edge_id;
|
|
||||||
if (ImNodes::IsLinkDestroyed(&edge_id))
|
|
||||||
{
|
|
||||||
if(!graph.tryDeleteEdge(edge_id)){
|
|
||||||
ImGui::End();
|
|
||||||
throw UsefulException(format("can't delete edge with id %i", edge_id));
|
|
||||||
}
|
|
||||||
std::cout<<"EDGES:\n";
|
|
||||||
std::cout<<graph.getEdges().generateGraphVizCode()<<std::endl;
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
104
src/gui/NodeEditor.cpp
Normal file
104
src/gui/NodeEditor.cpp
Normal file
@ -0,0 +1,104 @@
|
|||||||
|
#include "gui.hpp"
|
||||||
|
#include <algorithm>
|
||||||
|
#include "NodeEditor.hpp"
|
||||||
|
|
||||||
|
namespace GraphC::gui {
|
||||||
|
|
||||||
|
void drawNode(GraphModel::Node& node){
|
||||||
|
ImNodes::BeginNode(node.id);
|
||||||
|
ImNodes::BeginNodeTitleBar();
|
||||||
|
ImGui::TextUnformatted(node.title.c_str());
|
||||||
|
ImNodes::EndNodeTitleBar();
|
||||||
|
|
||||||
|
for(GraphModel::Attribute& a : node.attributes)
|
||||||
|
{
|
||||||
|
switch (a.type)
|
||||||
|
{
|
||||||
|
case GraphModel::Attribute::Type::Input:
|
||||||
|
ImNodes::BeginInputAttribute(a.id);
|
||||||
|
ImGui::Text("%s", a.title.c_str());
|
||||||
|
ImNodes::EndInputAttribute();
|
||||||
|
break;
|
||||||
|
case GraphModel::Attribute::Type::Output:
|
||||||
|
ImNodes::BeginOutputAttribute(a.id);
|
||||||
|
ImGui::Text("%s", a.title.c_str());
|
||||||
|
ImGui::Indent(40);
|
||||||
|
ImNodes::EndOutputAttribute();
|
||||||
|
break;
|
||||||
|
case GraphModel::Attribute::Type::Static:
|
||||||
|
ImNodes::BeginStaticAttribute(a.id);
|
||||||
|
ImGui::Text("%s", a.title.c_str());
|
||||||
|
ImNodes::EndStaticAttribute();
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
throw "Node::draw() invalid type";
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ImNodes::EndNode();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
GraphModel::Node CreateExampleNode(GraphModel::id_t* next_id, std::string title){
|
||||||
|
GraphModel::Node a = GraphModel::Node((*next_id)++, title);
|
||||||
|
a.attributes.push_back(GraphModel::Attribute((*next_id)++, &a, GraphModel::Attribute::Type::Input, "In"));
|
||||||
|
a.attributes.push_back(GraphModel::Attribute((*next_id)++, &a, GraphModel::Attribute::Type::Output, "Out"));
|
||||||
|
a.attributes.push_back(GraphModel::Attribute((*next_id)++, &a, GraphModel::Attribute::Type::Static, "Static"));
|
||||||
|
return a;
|
||||||
|
}
|
||||||
|
|
||||||
|
NodeEditor::NodeEditor(std::string _title) : title(_title) {
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeEditor::show(){
|
||||||
|
editor_open = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeEditor::hide(){
|
||||||
|
editor_open = false;
|
||||||
|
}
|
||||||
|
|
||||||
|
void NodeEditor::draw(){
|
||||||
|
if(!editor_open)
|
||||||
|
return;
|
||||||
|
|
||||||
|
ImGui::Begin(title.c_str(), &editor_open);
|
||||||
|
|
||||||
|
ImGui::SetWindowSizeMin(300,300);
|
||||||
|
ImNodes::BeginNodeEditor();
|
||||||
|
// draw nodes
|
||||||
|
for(auto&& p : graph->getNodes()){
|
||||||
|
drawNode(p.second);
|
||||||
|
}
|
||||||
|
// draw edges
|
||||||
|
const auto& edges = graph->getEdges();
|
||||||
|
edges.empl = GraphModel::Edge();
|
||||||
|
for(auto&& p : edges){
|
||||||
|
ImNodes::Link(p.second.id, p.second.to_attr_id, p.second.from_attr_id);
|
||||||
|
}
|
||||||
|
ImNodes::EndNodeEditor();
|
||||||
|
|
||||||
|
// handle edge creation
|
||||||
|
GraphModel::id_t to_attr_id;
|
||||||
|
GraphModel::id_t from_attr_id;
|
||||||
|
if (ImNodes::IsLinkCreated(&from_attr_id, &to_attr_id))
|
||||||
|
{
|
||||||
|
graph->createEdge(graph->getEdge(from_attr_id), graph->getEdge(to_attr_id));
|
||||||
|
}
|
||||||
|
|
||||||
|
// handle edge destruction
|
||||||
|
GraphModel::id_t edge_id;
|
||||||
|
if (ImNodes::IsLinkDestroyed(&edge_id))
|
||||||
|
{
|
||||||
|
auto iter = std::find_if(edges.begin(), edges.end(),
|
||||||
|
[edge_id](const GraphModel::Edge& edge) -> bool {
|
||||||
|
return edge.id == edge_id;
|
||||||
|
});
|
||||||
|
assert(iter != edges.end());
|
||||||
|
edges.erase(iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
ImGui::End();
|
||||||
|
}
|
||||||
|
|
||||||
|
}
|
||||||
@ -6,17 +6,14 @@
|
|||||||
|
|
||||||
namespace GraphC::gui {
|
namespace GraphC::gui {
|
||||||
|
|
||||||
class GraphEditor {
|
class NodeEditor {
|
||||||
std::string title=nullptr;
|
std::string title=nullptr;
|
||||||
bool editor_open=false;
|
bool editor_open=false;
|
||||||
ImNodesContext* editor_context=nullptr;
|
ImNodesContext* editor_context=nullptr;
|
||||||
GraphModel::Graph graph;
|
std::shared_ptr<GraphModel::Graph> graph;
|
||||||
|
|
||||||
void drawNode(const GraphModel::Node& node);
|
|
||||||
GraphModel::Node* CreateExampleNode(const std::string& title);
|
|
||||||
|
|
||||||
public:
|
public:
|
||||||
GraphEditor(const std::string& _title);
|
NodeEditor(std::string _title);
|
||||||
|
|
||||||
void draw();
|
void draw();
|
||||||
void show();
|
void show();
|
||||||
@ -1,9 +1,9 @@
|
|||||||
#include "exceptions.hpp"
|
#include "exceptions.hpp"
|
||||||
#include <SDL.h>
|
#include "../../dependencies/SDL2/include/SDL.h"
|
||||||
|
|
||||||
namespace GraphC::gui {
|
namespace GraphC::gui {
|
||||||
|
|
||||||
SDLException_::SDLException_(const std::string& _file,const std::string& _func, int _line_n)
|
SDLException_::SDLException_(std::string _file, std::string _func, int _line_n)
|
||||||
: UsefulException_(SDL_GetError(), _file, _func, _line_n)
|
: UsefulException_(SDL_GetError(), _file, _func, _line_n)
|
||||||
{
|
{
|
||||||
SDL_ClearError();
|
SDL_ClearError();
|
||||||
|
|||||||
@ -6,9 +6,9 @@ namespace GraphC::gui {
|
|||||||
|
|
||||||
#define SDLException() SDLException_(__FILE__, __func__, __LINE__)
|
#define SDLException() SDLException_(__FILE__, __func__, __LINE__)
|
||||||
|
|
||||||
class SDLException_ : public UsefulException_ {
|
class SDLException_ : UsefulException_ {
|
||||||
public:
|
public:
|
||||||
SDLException_(const std::string& _file, const std::string& _func, int line_n);
|
SDLException_(std::string _file, std::string _func, int line_n);
|
||||||
};
|
};
|
||||||
|
|
||||||
#define SDL_TRY_ZERO(FUNC_CALL) if(FUNC_CALL != 0) throw SDLException();
|
#define SDL_TRY_ZERO(FUNC_CALL) if(FUNC_CALL != 0) throw SDLException();
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "imgui.h"
|
#include "../../dependencies/imgui/imgui.h"
|
||||||
#include "../generated/fonts_embedded.h"
|
#include "../generated/fonts_embedded.h"
|
||||||
|
|
||||||
namespace GraphC::gui::fonts {
|
namespace GraphC::gui::fonts {
|
||||||
|
|||||||
101
src/gui/gui.cpp
101
src/gui/gui.cpp
@ -1,6 +1,6 @@
|
|||||||
#include "gui.hpp"
|
#include "gui.hpp"
|
||||||
#include "backends/imgui_impl_sdl2.h"
|
#include "../../dependencies/imgui/backends/imgui_impl_sdl2.h"
|
||||||
#include "backends/imgui_impl_opengl3.h"
|
#include "../../dependencies/imgui/backends/imgui_impl_opengl3.h"
|
||||||
|
|
||||||
namespace GraphC::gui {
|
namespace GraphC::gui {
|
||||||
|
|
||||||
@ -9,8 +9,8 @@ f32 GUI::getDPI(){
|
|||||||
SDL_GL_GetDrawableSize(sdl_window, &w, &h);
|
SDL_GL_GetDrawableSize(sdl_window, &w, &h);
|
||||||
int sim_w=0, sim_h=0;
|
int sim_w=0, sim_h=0;
|
||||||
SDL_GetWindowSize(sdl_window, &sim_w, &sim_h);
|
SDL_GetWindowSize(sdl_window, &sim_w, &sim_h);
|
||||||
f32 wdpi=(f32)w / sim_w;
|
f32 wdpi=w/sim_w;
|
||||||
f32 hdpi=(f32)h / sim_h;
|
f32 hdpi=h/sim_h;
|
||||||
f32 dpi=SDL_sqrtf(wdpi*wdpi + hdpi*hdpi);
|
f32 dpi=SDL_sqrtf(wdpi*wdpi + hdpi*hdpi);
|
||||||
return dpi;
|
return dpi;
|
||||||
}
|
}
|
||||||
@ -43,11 +43,7 @@ void GUI::init(const char* window_title){
|
|||||||
sdl_window = SDL_CreateWindow(window_title,
|
sdl_window = SDL_CreateWindow(window_title,
|
||||||
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
SDL_WINDOWPOS_CENTERED, SDL_WINDOWPOS_CENTERED,
|
||||||
1280, 720, window_flags);
|
1280, 720, window_flags);
|
||||||
if(sdl_window == nullptr)
|
|
||||||
throw SDLException();
|
|
||||||
gl_context = SDL_GL_CreateContext(sdl_window);
|
gl_context = SDL_GL_CreateContext(sdl_window);
|
||||||
if(gl_context == nullptr)
|
|
||||||
throw SDLException();
|
|
||||||
SDL_TRY_ZERO( SDL_GL_MakeCurrent(sdl_window, gl_context));
|
SDL_TRY_ZERO( SDL_GL_MakeCurrent(sdl_window, gl_context));
|
||||||
SDL_TRY_ZERO( SDL_GL_SetSwapInterval(1)); // Enable vsync
|
SDL_TRY_ZERO( SDL_GL_SetSwapInterval(1)); // Enable vsync
|
||||||
|
|
||||||
@ -79,8 +75,8 @@ void GUI::init(const char* window_title){
|
|||||||
ImNodes::CreateContext();
|
ImNodes::CreateContext();
|
||||||
ImNodes::StyleColorsDark();
|
ImNodes::StyleColorsDark();
|
||||||
ImNodes::PushAttributeFlag(ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
|
ImNodes::PushAttributeFlag(ImNodesAttributeFlags_EnableLinkDetachWithDragClick);
|
||||||
node_editor = new GraphEditor("node editor");
|
node_editor=NodeEditor("node editor");
|
||||||
node_editor->show();
|
node_editor.show();
|
||||||
}
|
}
|
||||||
|
|
||||||
// Wait, poll and handle events (inputs, window resize, etc.)
|
// Wait, poll and handle events (inputs, window resize, etc.)
|
||||||
@ -112,58 +108,20 @@ void GUI::poll_events(u16& frame_updates_requested, bool wait){
|
|||||||
} while (SDL_PollEvent(&event)); // if there are more events, handles them
|
} while (SDL_PollEvent(&event)); // if there are more events, handles them
|
||||||
}
|
}
|
||||||
|
|
||||||
void ImGui_drawErrorWindow(bool* draw_error_window, std::string& msg){
|
|
||||||
ImGui::Begin("ERROR", draw_error_window);
|
|
||||||
ImGui::Text("%s", msg.c_str());
|
|
||||||
ImGui::End();
|
|
||||||
}
|
|
||||||
|
|
||||||
void GUI::draw_ui(){
|
|
||||||
static std::string error_message;
|
|
||||||
static bool draw_error_window = false;
|
|
||||||
try {
|
|
||||||
// Draw UI
|
|
||||||
if(draw_error_window)
|
|
||||||
ImGui_drawErrorWindow(&draw_error_window, error_message);
|
|
||||||
else {
|
|
||||||
draw_bg_window();
|
|
||||||
draw_debug_window();
|
|
||||||
node_editor->draw();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
catch(const std::exception& e){
|
|
||||||
error_message = "Catched exception: " + std::string(e.what());
|
|
||||||
draw_error_window = true;
|
|
||||||
std::cerr<<error_message<<std::endl;
|
|
||||||
}
|
|
||||||
catch(const char* cstr){
|
|
||||||
error_message = "Catched error message (const char*): " + std::string(cstr);
|
|
||||||
draw_error_window = true;
|
|
||||||
std::cerr<<error_message<<std::endl;
|
|
||||||
}
|
|
||||||
catch(const std::string& str){
|
|
||||||
error_message = "Catched error message (std::string): " + str;
|
|
||||||
draw_error_window = true;
|
|
||||||
std::cerr<<error_message<<std::endl;
|
|
||||||
}
|
|
||||||
catch(...){
|
|
||||||
error_message = "Catched unknown error";
|
|
||||||
draw_error_window = true;
|
|
||||||
std::cerr<<error_message<<std::endl;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
void GUI::draw_frame(){
|
void GUI::draw_frame(){
|
||||||
// Start the Dear ImGui frame
|
// Start the Dear ImGui frame
|
||||||
ImGui_ImplOpenGL3_NewFrame();
|
ImGui_ImplOpenGL3_NewFrame();
|
||||||
ImGui_ImplSDL2_NewFrame();
|
ImGui_ImplSDL2_NewFrame();
|
||||||
ImGui::NewFrame();
|
ImGui::NewFrame();
|
||||||
|
ImGuiIO& io = ImGui::GetIO();
|
||||||
|
|
||||||
draw_ui();
|
// Draw UI
|
||||||
|
draw_bg_window();
|
||||||
|
draw_debug_window(io, &main_loop_wait_for_input);
|
||||||
|
node_editor.draw();
|
||||||
|
|
||||||
// Rendering
|
// Rendering
|
||||||
ImGui::Render();
|
ImGui::Render();
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
|
glViewport(0, 0, (int)io.DisplaySize.x, (int)io.DisplaySize.y);
|
||||||
glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
|
glClearColor(clear_color.x * clear_color.w, clear_color.y * clear_color.w, clear_color.z * clear_color.w, clear_color.w);
|
||||||
glClear(GL_COLOR_BUFFER_BIT);
|
glClear(GL_COLOR_BUFFER_BIT);
|
||||||
@ -272,46 +230,15 @@ void GUI::draw_bg_window(){
|
|||||||
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
|
ImGui::DockSpace(dockspace_id, ImVec2(0.0f, 0.0f), dockspace_flags);
|
||||||
|
|
||||||
// MenuBar
|
// MenuBar
|
||||||
if(ImGui::BeginMainMenuBar()){
|
//TODO
|
||||||
if(ImGui::BeginMenu("test")){
|
|
||||||
if(ImGui::MenuItem("throw exception")){
|
|
||||||
ImGui::EndMenu();
|
|
||||||
ImGui::EndMainMenuBar();
|
|
||||||
ImGui::End();
|
|
||||||
throw UsefulException("example exception");
|
|
||||||
}
|
|
||||||
if(ImGui::MenuItem("throw const char*")){
|
|
||||||
ImGui::EndMenu();
|
|
||||||
ImGui::EndMainMenuBar();
|
|
||||||
ImGui::End();
|
|
||||||
throw "cptr";
|
|
||||||
}
|
|
||||||
if(ImGui::MenuItem("throw std::string")){
|
|
||||||
ImGui::EndMenu();
|
|
||||||
ImGui::EndMainMenuBar();
|
|
||||||
ImGui::End();
|
|
||||||
throw std::string("str");
|
|
||||||
}
|
|
||||||
if(ImGui::MenuItem("throw unknown")){
|
|
||||||
ImGui::EndMenu();
|
|
||||||
ImGui::EndMainMenuBar();
|
|
||||||
ImGui::End();
|
|
||||||
throw 111;
|
|
||||||
}
|
|
||||||
ImGui::EndMenu();
|
|
||||||
}
|
|
||||||
ImGui::EndMainMenuBar();
|
|
||||||
}
|
|
||||||
|
|
||||||
ImGui::End();
|
ImGui::End();
|
||||||
}
|
}
|
||||||
|
|
||||||
void GUI::draw_debug_window(){
|
void GUI::draw_debug_window(ImGuiIO& io, bool* main_loop_wait_for_input){
|
||||||
ImGuiIO& io = ImGui::GetIO();
|
|
||||||
|
|
||||||
ImGui::Begin("Debug Options");
|
ImGui::Begin("Debug Options");
|
||||||
ImGui::ColorEdit3("clear_color", (float*)&clear_color);
|
ImGui::ColorEdit3("clear_color", (float*)&clear_color);
|
||||||
ImGui::Checkbox("main_loop_wait_for_input", &main_loop_wait_for_input);
|
ImGui::Checkbox("main_loop_wait_for_input", main_loop_wait_for_input);
|
||||||
ImGui::Text("Application average %.3f ms/frame (%.2f FPS)", 1000.0f / io.Framerate, io.Framerate);
|
ImGui::Text("Application average %.3f ms/frame (%.2f FPS)", 1000.0f / io.Framerate, io.Framerate);
|
||||||
ImGui::Checkbox("Demo Window", &show_demo_window);
|
ImGui::Checkbox("Demo Window", &show_demo_window);
|
||||||
ImGui::Checkbox("Metrics/Debug Window", &show_metrics_window);
|
ImGui::Checkbox("Metrics/Debug Window", &show_metrics_window);
|
||||||
|
|||||||
@ -1,17 +1,14 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "../../dependencies/kerep/src/base/std.h"
|
#include "../../dependencies/kerep/src/base/base.h"
|
||||||
#include "../../dependencies/kerep/src/kprint/kprintf.h"
|
#include "../../dependencies/SDL2/include/SDL.h"
|
||||||
#include <SDL.h>
|
#include "../../dependencies/SDL2/include/SDL_opengl.h"
|
||||||
#include <SDL_opengl.h>
|
#include "../../dependencies/imgui/imgui.h"
|
||||||
#include "imgui.h"
|
|
||||||
#include "../format.hpp"
|
#include "../format.hpp"
|
||||||
#include "GraphEditor.hpp"
|
#include "NodeEditor.hpp"
|
||||||
#include "imgui_extensions.hpp"
|
#include "imgui_extensions.hpp"
|
||||||
#include "fonts.hpp"
|
#include "fonts.hpp"
|
||||||
#include "exceptions.hpp"
|
#include "exceptions.hpp"
|
||||||
#include <iostream>
|
|
||||||
#include <string>
|
|
||||||
|
|
||||||
/// converts hex color to float vector
|
/// converts hex color to float vector
|
||||||
#define RGBAHexToF(R8,G8,B8,A8) ImVec4(((u8)35)/255.0f, ((u8)35)/255.0f, ((u8)50)/255.0f, ((u8)255)/255.0f)
|
#define RGBAHexToF(R8,G8,B8,A8) ImVec4(((u8)35)/255.0f, ((u8)35)/255.0f, ((u8)50)/255.0f, ((u8)255)/255.0f)
|
||||||
@ -34,9 +31,9 @@ private:
|
|||||||
bool main_loop_wait_for_input=true;
|
bool main_loop_wait_for_input=true;
|
||||||
bool show_demo_window = false;
|
bool show_demo_window = false;
|
||||||
bool show_metrics_window = false;
|
bool show_metrics_window = false;
|
||||||
SDL_Window* sdl_window = nullptr;
|
SDL_Window* sdl_window;
|
||||||
SDL_GLContext gl_context = nullptr;
|
SDL_GLContext gl_context;
|
||||||
GraphEditor* node_editor = nullptr;
|
NodeEditor node_editor = NodeEditor("new editor");
|
||||||
|
|
||||||
public:
|
public:
|
||||||
void init(const char* window_title);
|
void init(const char* window_title);
|
||||||
@ -48,8 +45,7 @@ private:
|
|||||||
void destroy();
|
void destroy();
|
||||||
void poll_events(u16& frame_updates_requested, bool wait);
|
void poll_events(u16& frame_updates_requested, bool wait);
|
||||||
void draw_frame();
|
void draw_frame();
|
||||||
void draw_ui();
|
void draw_debug_window(ImGuiIO &io, bool *main_loop_wait_for_input);
|
||||||
void draw_debug_window();
|
|
||||||
void draw_bg_window();
|
void draw_bg_window();
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@ -1,6 +1,6 @@
|
|||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
#include "imgui.h"
|
#include "../../dependencies/imgui/imgui.h"
|
||||||
|
|
||||||
namespace ImGui {
|
namespace ImGui {
|
||||||
|
|
||||||
|
|||||||
20
src/main.cpp
20
src/main.cpp
@ -1,8 +1,10 @@
|
|||||||
#include <iostream>
|
|
||||||
// SDL redefines main function for compatibility.
|
|
||||||
// THe following define disables this feature.
|
|
||||||
#define SDL_MAIN_HANDLED
|
|
||||||
#include "gui/gui.hpp"
|
#include "gui/gui.hpp"
|
||||||
|
#include <iostream>
|
||||||
|
|
||||||
|
// SDL for some reason redefines main
|
||||||
|
#ifdef main
|
||||||
|
#undef main
|
||||||
|
#endif
|
||||||
|
|
||||||
int main(const int argc, const char* const* argv){
|
int main(const int argc, const char* const* argv){
|
||||||
if(setlocale(LC_CTYPE, "C.UTF-8")!=0)
|
if(setlocale(LC_CTYPE, "C.UTF-8")!=0)
|
||||||
@ -21,16 +23,16 @@ int main(const int argc, const char* const* argv){
|
|||||||
std::cerr<<"Catched exception: "<<e.what()<<std::endl;
|
std::cerr<<"Catched exception: "<<e.what()<<std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
catch(const char* cstr){
|
catch(const char* msg){
|
||||||
std::cerr<<"Catched error message (const char*): "<<cstr<<std::endl;
|
std::cerr<<"Catched exception message: "<<msg<<std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
catch(const std::string& str){
|
catch(std::string& msg){
|
||||||
std::cerr<<"Catched error message (std::string): "<<str<<std::endl;
|
std::cerr<<"Catched exception message: "<<msg<<std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
catch(...){
|
catch(...){
|
||||||
std::cerr<<"Catched unknown error"<<std::endl;
|
std::cerr<<"Catched unknown exception"<<std::endl;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
3
tasks/clean_additions.sh
Executable file → Normal file
3
tasks/clean_additions.sh
Executable file → Normal file
@ -1,3 +1,4 @@
|
|||||||
#!/usr/bin/env bash
|
#!/usr/bin/bash
|
||||||
|
|
||||||
try_delete_dir_or_file fonts/generated
|
try_delete_dir_or_file fonts/generated
|
||||||
|
try_delete_dir_or_file libs/fonts_embedded.a
|
||||||
|
|||||||
2
tasks/embed_fonts.sh
Executable file → Normal file
2
tasks/embed_fonts.sh
Executable file → Normal file
@ -1,4 +1,4 @@
|
|||||||
#!/usr/bin/env bash
|
#!/bin/bash
|
||||||
cd fonts
|
cd fonts
|
||||||
SRC_C=""
|
SRC_C=""
|
||||||
HEADER="generated/fonts_embedded.h"
|
HEADER="generated/fonts_embedded.h"
|
||||||
|
|||||||
22
tasks/pre_build.sh
Normal file
22
tasks/pre_build.sh
Normal file
@ -0,0 +1,22 @@
|
|||||||
|
#!/bin/bash
|
||||||
|
|
||||||
|
# compile fonts
|
||||||
|
if [ ! -f libs/fonts_embedded.a ]; then
|
||||||
|
if ! make embed_fonts; then
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
set -x
|
||||||
|
# copy precompiled static libs to objects
|
||||||
|
static_libs=$(find "libs/" -name '*.a')
|
||||||
|
[[ -n "$static_libs" ]] && cp $static_libs "$OBJDIR/libs/"
|
||||||
|
|
||||||
|
# copy precompiled shared libs to outdir
|
||||||
|
if [ "$OS" == 'WINDOWS' ]; then
|
||||||
|
dynamic_libs=$(find "libs/" -name '*.dll')
|
||||||
|
else
|
||||||
|
dynamic_libs=$(find "libs/" -name '*.so')
|
||||||
|
fi
|
||||||
|
[[ -n "$dynamic_libs" ]] && cp $dynamic_libs "$OUTDIR/"
|
||||||
|
set +x
|
||||||
Loading…
Reference in New Issue
Block a user