Compare commits

...
Sign in to create a new pull request.

248 commits
master ... tmp2

Author SHA1 Message Date
IlyaShurupov
15127c5122 Cleanup widgets 2024-06-26 22:54:10 +03:00
IlyaShurupov
9e7704a446 New DockspaceWidget Stable 2024-06-26 08:42:29 +03:00
IlyaShurupov
7158be5890 dockspce widget initial 2024-06-25 18:34:38 +03:00
IlyaShurupov
559c91a144 widgets cleanups 2024-06-25 08:48:16 +03:00
IlyaShurupov
b8f125b472 gui updates 2024-06-24 22:29:08 +03:00
IlyaShurupov
05ac11b24c awidgets 2024-06-23 17:57:14 +03:00
IlyaShurupov
378ff3f568 dirty 2024-06-21 10:26:57 +03:00
IlyaShurupov
8f62c8f387 new widgets 2024-06-20 17:17:20 +03:00
Ilya Shurupov
3dce41ea39
Update cmake-single-platform.yml 2024-06-19 12:51:43 +03:00
Ilya Shurupov
1cfa41b787
Update cmake-single-platform.yml 2024-06-19 12:47:10 +03:00
Ilya Shurupov
85a27a8975
Update cmake-single-platform.yml 2024-06-19 12:44:03 +03:00
Ilya Shurupov
06a02222ff
Update cmake-single-platform.yml 2024-06-19 12:41:32 +03:00
Ilya Shurupov
4dafc07b08
Update cmake-single-platform.yml 2024-06-19 12:36:59 +03:00
IlyaShurupov
9160e343c3 add oidn 2024-06-19 12:29:02 +03:00
IlyaShurupov
7321acfb3d fix ray tracer projection plane 2024-06-18 23:47:19 +03:00
IlyaShurupov
29df264479 update todo 2024-06-18 19:38:01 +03:00
IlyaShurupov
e8001cd95b 3D editor stable with path tracer 2024-06-18 19:36:47 +03:00
IlyaShurupov
19706ed738 Editor multyrender initial 2024-06-18 18:20:14 +03:00
IlyaShurupov
119e610db6 3D scene stable 2024-06-18 17:59:14 +03:00
IlyaShurupov
5d96d6905f clean up 2024-06-18 17:33:39 +03:00
IlyaShurupov
a0a40f1d04 Use scene module in editor 2024-06-18 17:26:44 +03:00
IlyaShurupov
55f5537a67 3D Scene initial 2024-06-18 17:16:23 +03:00
IlyaShurupov
3fd3211f46 Update TODO regargin 3d framework 2024-06-18 15:53:35 +03:00
IlyaShurupov
3d09f86258 Add albedo output to the raytracer 2024-06-18 15:45:51 +03:00
IlyaShurupov
bafe6a7f43 Resize frame buffer method added 2024-06-18 14:48:26 +03:00
IlyaShurupov
787681d320 use x11 as windowing platform with glfw for now 2024-06-18 13:40:35 +03:00
Ilya Shurupov
e45cf0ff46
Update cmake-single-platform.yml 2024-06-16 00:25:33 -07:00
Ilya Shurupov
ab8d1a86a4
Update cmake-single-platform.yml 2024-06-16 00:23:24 -07:00
Ilya Shurupov
54dbfab71c
Update cmake-single-platform.yml 2024-06-16 00:21:47 -07:00
elushaX
bedbe25876 Windows update 2024-06-16 07:17:34 +03:00
IlyaShurupov
947d465d11 updating submodule 2024-06-05 14:56:59 +03:00
IlyaShurupov
d80dfd895d Update widgets 2024-05-07 12:04:36 +03:00
IlyaShurupov
eb079e1386 update widgets 2024-05-06 16:33:35 +03:00
IlyaShurupov
c41dcf9efa update todo 2024-05-06 11:56:24 +03:00
IlyaShurupov
9cfae3fe3e Update widgets module. Raster example initial. 2024-05-06 11:49:43 +03:00
Ilya Shurupov
9e339defd6
Update TODO 2024-04-10 05:23:16 -07:00
IlyaShurupov
47ad484089 profiling avl 2024-04-08 16:16:43 +03:00
IlyaShurupov
aafecb8359 AVL Tree refactor 2024-04-08 16:16:37 +03:00
Ilya Shurupov
be6b821a40
Update TODO 2024-04-02 01:25:15 -07:00
IlyaShurupov
738ce1d914 dont copy node data in tree delete operation - just swap nodes 2024-04-01 17:04:34 +03:00
IlyaShurupov
6148ff15d2 update numeric key interface 2024-04-01 14:10:40 +03:00
IlyaShurupov
7c7171f470 remove extra layer of redirection in avl tree 2024-04-01 13:57:10 +03:00
IlyaShurupov
86f81fb534 Tree. remove redunant function 2024-04-01 13:46:13 +03:00
IlyaShurupov
7332e72bb2 Method object refactor 2024-03-25 13:57:31 +03:00
IlyaShurupov
add66e6cac remove initializer callbacks from method object 2024-03-25 11:40:56 +03:00
IlyaShurupov
acaa086943 clean up null object 2024-03-25 11:36:29 +03:00
IlyaShurupov
55daf0f303 Separate objects context and interface 2024-03-25 11:20:15 +03:00
IlyaShurupov
e937d189df new object creation interface 2024-03-25 10:25:25 +03:00
IlyaShurupov
c737f41d8a fix typos 2024-03-25 09:23:25 +03:00
IlyaShurupov
7927226484 remove macros use in objects mofule 2024-03-24 22:17:08 +03:00
IlyaShurupov
0fb9326c08 fix warnings 2024-03-24 10:13:18 +03:00
IlyaShurupov
5d9e270aa9 clean up object module 2024-03-23 13:08:36 +03:00
IlyaShurupov
4c66704830 dont use NULL macro 2024-03-23 12:16:44 +03:00
IlyaShurupov
9a9262f6d0 Apply cpp naming to files 2024-03-23 12:09:51 +03:00
IlyaShurupov
430ba869d0 remove objects readme 2024-03-22 17:36:13 +03:00
IlyaShurupov
fe908fe0bc Restore buildbot status 2024-03-22 17:33:29 +03:00
IlyaShurupov
d9618e862e leak fix 2024-03-22 16:51:03 +03:00
IlyaShurupov
569ef734c4 Update TODO 2024-03-22 16:19:56 +03:00
IlyaShurupov
893a07e924 RIP tp::Strings 2024-03-22 16:13:42 +03:00
IlyaShurupov
aa53a4addb see ya later allocator 2024-03-22 14:05:25 +03:00
elushaX
d7bc7e10ab
Update README.MD 2024-03-21 05:06:54 -07:00
elushaX
b986cb2eff
Create LICENSE 2024-03-21 04:34:47 -07:00
elushaX
223f32a2b8
Delete LICENSE 2024-03-21 04:28:13 -07:00
IlyaShurupov
0a239578a1 update readme 2024-03-21 13:57:27 +03:00
IlyaShurupov
c908c7b397 update readme 2024-03-21 11:12:03 +03:00
IlyaShurupov
fb9b714353 add Oscript showcase 2024-03-21 11:07:43 +03:00
IlyaShurupov
de70d4b00f Edit readme 2024-03-20 22:30:09 +03:00
elushaX
5f0ce77fca Add color sliders to sketch3d 2024-03-20 20:00:52 -07:00
IlyaShurupov
70daeeea54 Updating README 2024-03-20 17:52:39 +03:00
IlyaShurupov
476da8bb92 Graphics refactor finished 2024-03-20 11:31:50 +03:00
IlyaShurupov
37b4993b70 osg stable 2024-03-20 10:05:57 +03:00
IlyaShurupov
f3bc272eae Widget Example added 2024-03-20 10:01:05 +03:00
elushaX
b2f5c0193a stable 2024-03-20 00:47:46 -07:00
Ilusha
752243c7e9 tmp 2024-03-19 20:17:47 +03:00
Ilusha
29280949a8 graphics frame rate fixed 2024-03-19 16:39:18 +03:00
Ilusha
e41714c2bb tmp 2024-03-19 17:35:02 +03:00
IlyaShurupov
59b1d0b89a tmp 2024-03-19 11:52:22 +03:00
IlyaShurupov
b342f4fd8c Graphics Example Stable 2024-03-19 11:37:55 +03:00
IlyaShurupov
bb5cbfdfe2 Graphics Refactor Initial 2024-03-19 11:21:58 +03:00
IlyaShurupov
87d8ce84dc Adding new gui to Sketch3d 2024-03-18 15:48:27 +03:00
IlyaShurupov
ccdc8efd99 Map invalid iterator fix 2024-03-18 11:56:05 +03:00
IlyaShurupov
bcaef2489a Small cleanup 2024-03-18 11:51:29 +03:00
IlyaShurupov
3cdc5fbbef Fix bugs. Sketch3D stable. 2024-03-18 11:16:03 +03:00
Ilusha
0f4a67e244 Unstable & with drawing restored 2024-03-18 09:55:38 +03:00
Ilusha
11402f577a A little clean up 2024-03-18 09:55:38 +03:00
Ilusha
0f6fa035aa CCompiled and runed with working visuals 2024-03-18 09:55:38 +03:00
Ilusha
57d5bc61ed trying to compile 2024-03-18 09:55:38 +03:00
Ilusha
b8bab2264f Sketch ini 2024-03-18 09:55:38 +03:00
IlyaShurupov
be0177b1b0 Linux fixes 2024-03-18 09:55:12 +03:00
Ilusha
e6f535fe6e fix raytracer 2024-03-16 20:57:46 +03:00
Ilusha
1ead32d84a tmp 2024-03-16 12:51:09 +03:00
Ilusha
65cb26a627 tmp 2024-03-15 23:42:10 +03:00
Ilusha
00d8fa0886 Use UnitTest-Cpp library for testing 2024-03-15 17:22:33 +03:00
Ilusha
ecaa2bbdfb Recovering from github accound ban 2024-03-15 11:31:41 +03:00
Ilusha
c2ad9ce501 tmp 2024-03-14 09:00:14 +03:00
Ilusha
aa2d8f1200 new testing framework 2024-03-14 09:00:03 +03:00
Ilusha
5d94ddd774 tmp 2024-03-14 08:00:35 +03:00
Ilusha
da74d27135 tmp 2024-03-13 14:20:50 +03:00
Ilusha
37ae4b2abb add parser chech for precedence in arithmetic expressions 2024-03-13 14:10:18 +03:00
Ilusha
afe32d6014 Fixing lalr on windows 2024-03-12 07:33:11 -07:00
Ilusha
ffafeba6c2
Update cmake.yml 2024-03-09 10:49:15 +03:00
Ilusha
80fcbe4e2c
try clang 14 2024-03-09 10:44:51 +03:00
Ilusha
d7d809c222
try clang 16 in buildbot 2024-03-09 10:42:09 +03:00
Ilusha
8ac49dc50b
Update cmake.yml 2024-03-09 10:35:45 +03:00
Ilusha
cce9609ced Adding windows build information 2024-03-09 10:29:02 +03:00
Ilusha
ac4f08c67c Edit todo and status texts 2024-03-07 13:28:59 +03:00
Ilusha
23e7ecb812 Fix interval tree 2024-03-07 12:45:24 +03:00
Ilusha
20ac8620e6 stable 2024-03-07 12:33:57 +03:00
IlyaShurupov
b906e0e66c tmp 2024-03-07 12:33:57 +03:00
IlyaShurupov
49c67eb028 parser error handling 2024-03-07 12:33:57 +03:00
IlyaShurupov
fdb861b299 Parser done implementing 2024-03-07 12:33:57 +03:00
IlyaShurupov
828096de17 tmp 2024-03-07 12:33:57 +03:00
IlyaShurupov
e628e7c1e2 grammar done 2024-03-07 12:33:57 +03:00
IlyaShurupov
ad543c304d tmp 2024-03-07 12:33:57 +03:00
IlyaShurupov
ed3421321c tmp 2024-03-07 12:33:57 +03:00
Ilusha
f666416696 Replace object parser with lalr library 2024-03-07 12:33:46 +03:00
IlyaShurupov
3ba4bef93b small fix 2024-03-07 12:31:48 +03:00
IlyaShurupov
3bed74df87 parsing loop closed 2024-03-07 12:31:48 +03:00
IlyaShurupov
63b0560375 fix compile errors 2024-03-07 12:31:48 +03:00
IlyaShurupov
1d9ef2aa6c cfg automata ini 2024-03-07 12:31:48 +03:00
IlyaShurupov
35387395eb cfg accepting 2024-03-07 12:31:48 +03:00
IlyaShurupov
e6d77c639b refactor regular automata 2024-03-07 12:31:48 +03:00
IlyaShurupov
a9a810c197 CFG compiler ini 2024-03-07 12:31:48 +03:00
IlyaShurupov
4f88c45c9e tmp 2024-03-07 12:31:48 +03:00
IlyaShurupov
81a2247bf2 tmp 2024-03-07 12:31:48 +03:00
IlyaShurupov
dd6b63acb1 reg automata fixes 2024-03-07 12:31:48 +03:00
IlyaShurupov
41aa8daeb2 tmp 2024-03-07 12:31:48 +03:00
Ilusha
1f1dc001a1 tmp 2024-03-07 12:31:26 +03:00
IlyaShurupov
93b02416de refactor and reuse Automatas. TODO : add test for automatas 2024-03-07 12:27:48 +03:00
IlyaShurupov
312419936e tmp 2024-03-07 12:27:47 +03:00
IlyaShurupov
d2bb8cdd6a tmp 2024-03-07 12:27:47 +03:00
IlyaShurupov
7112002e30 Reuse Regular Automata functionality 2024-03-07 12:27:47 +03:00
IlyaShurupov
656da1fd76 Make parser template class 2024-03-07 12:27:47 +03:00
IlyaShurupov
38957e678b TODO : Make RE Grammar template independent. Difine Unified grammar format. 2024-03-07 12:27:47 +03:00
IlyaShurupov
7ed6b1f33c tmp 2024-03-07 12:27:47 +03:00
IlyaShurupov
060aaecbeb Adding implementation comments to Language 2024-03-07 12:27:47 +03:00
IlyaShurupov
fae4d83f97 Language Initial 2024-03-07 12:27:47 +03:00
IlyaShurupov
14cb588948 Fix avl tree destructor 2024-03-01 19:03:31 +03:00
IlyaShurupov
7d8cf66b27 Adding more tests for interval tree 2024-02-14 10:50:01 +03:00
IlyaShurupov
a3399fdc56 Interval Tree added 2024-02-13 19:07:46 +03:00
IlyaShurupov
7932887f43 Update ImGui 2024-02-03 10:46:29 +03:00
IlyaShurupov
3b50001daf Refactor lib view 2024-02-03 10:46:29 +03:00
Ilusha
83d51d3e83 ini 2024-02-03 10:46:29 +03:00
Ilusha
f7f0d6e5be Merge branch 'master' of https://github.com/IlyaShurupov/Modules 2024-01-17 22:49:56 +03:00
Ilusha
f146ddd307 Remove mutex class and use std 2024-01-17 22:42:48 +03:00
Ilusha
69cdf43909 Small fixes from windows 2024-01-17 16:14:47 -08:00
Ilusha
7298858c96
Update WindowsPlatform.yml 2024-01-17 08:37:51 -08:00
Ilusha
dec6a9dc73
Update WindowsPlatform.yml 2024-01-17 08:36:38 -08:00
Ilusha
db73ffb439
Create WindowsPlatform.yml 2024-01-17 08:34:25 -08:00
Ilusha
34a8d4eafd Adding support for windows and fixing some errors 2024-01-16 19:58:50 +03:00
IlyaShurupov
2722a25036 Fix build errors 2024-01-10 16:10:58 +03:00
IlyaShurupov
81e16e1c50 Exclude glew from manual build duo to errors. Using precompiled packages. 2024-01-10 15:47:47 +03:00
Ilusha
f7fd0c5942
Update cmake.yml change alsa package name 2024-01-10 10:57:43 +00:00
Ilusha
023c3908e0
Update cmake.yml add alsa dep 2024-01-10 10:54:08 +00:00
IlyaShurupov
a5f4d7149a Refactor! 2024-01-10 12:05:31 +03:00
IlyaShurupov
5d7a343a20 Filtering 2023-11-30 15:57:14 +03:00
IlyaShurupov
d5ff875497 Neet fixes 2023-11-30 15:19:40 +03:00
IlyaShurupov
231b30b2cb Adding Music Playback 2023-11-29 19:42:17 +03:00
IlyaShurupov
7b325244c5 Side panel added 2023-11-29 14:36:59 +03:00
IlyaShurupov
c7d3b15758 LibraryViewer 2023-11-28 23:22:04 +03:00
IlyaShurupov
5a55011911 CMake fixes 2023-10-28 15:56:52 +03:00
IlyaShurupov
b7a89b714e Num Rec app and save & loading 2023-10-26 16:27:43 +03:00
IlyaShurupov
fc20f3594d Number recognition Tuning 2023-10-26 00:52:40 +03:00
IlyaShurupov
826713c212 NumRec Fixes 2023-10-25 20:41:48 +03:00
IlyaShurupov
0542b7ba2e BackProp Fixes 2023-10-25 13:14:45 +03:00
IlyaShurupov
efbb09f8ba BackProp Initial 2023-10-23 13:38:00 +03:00
IlyaShurupov
744c01c5d0 Apply formating to all files. CLeanup 2023-10-22 20:23:29 +03:00
IlyaShurupov
43e374f269 Complex toy classes & DataAnalysis initial 2023-10-21 23:20:20 +03:00
IlyaShurupov
93a90e0291 RT Multisampling 2023-10-19 19:11:29 +03:00
IlyaShurupov
3396e69b47 Save multiple buffers from RayTracer 2023-10-18 20:13:07 +03:00
IlyaShurupov
7af12ee1a0 Adding simple test for RT 2023-10-18 19:05:51 +03:00
IlyaShurupov
2e0d0e0050 Adding progress bar for rt application 2023-10-18 13:45:47 +03:00
IlyaShurupov
414d4e6411 Primitive sampling 2023-10-18 12:05:01 +03:00
IlyaShurupov
97f79a6483 Adding normals 2023-10-17 20:51:25 +03:00
IlyaShurupov
cfb4c0cfcc RT Todo 2023-10-17 12:32:12 +03:00
IlyaShurupov
c284a12ade Fix issue with submodule mapping for lua 2023-10-16 23:10:14 +03:00
IlyaShurupov
3e9365b1ee Adding scene files 2023-10-16 22:38:45 +03:00
IlyaShurupov
517dc83c85 Adding lua scene description 2023-10-16 22:09:20 +03:00
IlyaShurupov
e00ab4059c tmp 2023-10-16 16:24:31 +03:00
IlyaShurupov
0e41a6e4fd Simple Normals Rendering 2023-10-16 13:38:56 +03:00
IlyaShurupov
97525efacb Bug fixes 2023-10-16 00:02:32 +03:00
IlyaShurupov
94d47ba390 RayTracer Initial Framework setup 2023-10-15 23:25:48 +03:00
IlyaShurupov
8d990a0132 Update Clang Format 2023-09-03 10:53:20 +03:00
IlushaShurupov
2810e06b3e Adding outdated source code into master 2023-08-20 11:27:47 +03:00
IlushaShurupov
5cf467a421 Updated TODO 2023-08-14 20:53:34 +03:00
IlushaShurupov
01b6f9099c LR(1) Parser Initial 2023-08-14 20:06:32 +03:00
IlushaShurupov
616441e049 Checking for non productive rules and loops in cfg 2023-08-12 09:39:06 +03:00
IlushaShurupov
b205438601 CFG remove unused rules 2023-08-12 08:27:50 +03:00
IlushaShurupov
e6d9439ba9 Adding simple test fot cf grammar 2023-08-12 08:08:47 +03:00
IlushaShurupov
0a886bd8a8 Fixing list copy and grammar sentence generation 2023-08-11 18:57:39 +03:00
IlushaShurupov
43fe34dcbf Improve module initialization log 2023-08-11 16:42:47 +03:00
IlushaShurupov
7d49642376 Fixin cfg 2023-08-11 16:37:51 +03:00
IlushaShurupov
01b7d96ebd Fixin map 2023-08-11 16:21:30 +03:00
IlushaShurupov
6fcfa075f8 Generate sentences from cf grammar. Fix list initialization from copy constructor 2023-08-11 16:04:02 +03:00
IlushaShurupov
d888aeb2b4 Fixing tokenizer bug 2023-08-10 18:36:56 +03:00
IlushaShurupov
92f34e2a99 CF Grammar improvements 2023-08-10 18:35:48 +03:00
IlushaShurupov
424787c735 CF Grammar Initial 2023-08-10 18:35:40 +03:00
IlushaShurupov
eb712a352d Parser Initial 2023-08-10 18:35:29 +03:00
IlushaShurupov
5fab9ee507 Adding some tokinizer checks for strings and comments 2023-08-10 18:35:17 +03:00
IlushaShurupov
9c8771a378 Editing TODO 2023-08-07 19:03:17 +03:00
Ilusha
9a7e44a96d
Update cmake.yml - sudo apt-get update before installing pacages 2023-08-07 18:56:03 +03:00
IlushaShurupov
112fea2f04 Adding objects GUI initial. Changing TODO. Some fixes along side 2023-08-07 18:37:11 +03:00
IlushaShurupov
f9d62c324d "Added new test 'Complex' and improved error debugging"
This revision adds a complex test to the 'TestInterpreter.cpp' file to test functionalities such as classes, variable initializations, loops, conditionals and methods in the interpreter. The token parser has also been updated with a reset method in the 'parser.cpp' file for cleaning up any previous state before parsing a new script. This ensures the parser starts fresh for each new parse request. It also improves the debugging process in 'function.cpp' by printing the description of parser errors. Few completed tasks are removed from the TODO list.
2023-08-03 21:15:27 +03:00
IlushaShurupov
55571ca3dd Load and destroy methods revised for proper reference counting
The update enhances object management by involving scope-based reference counting. The change affects loading and destruction operations in the Object and several other classes, ensuring the release or retention of objects adhere to their usage context. A function for logging type data has also been introduced to provide better clarity during debugging. Also, tests in script & interpreter have been altered to run in separate module initializations to avoid cross-test interference. Overall, it provides better memory management and dependable tests.
2023-08-01 20:06:34 +03:00
IlushaShurupov
b06e1da529 Add Interpreter tests and improve Parser error logging
A set of tests for the InterpreterObject has been added to enhance its reliability and maintainability. The tests check the essential functionalities such as its creation, execution, saving, loading, and destruction. Furthermore, the error logging for the Parser has been improved, now providing more precise location of detected errors. The changes improve the robustness and debugability of the code.
2023-08-01 18:57:36 +03:00
IlushaShurupov
0cefb47b66 Refactor save size calculation with SaveSizeCounter
SaveSizeCounter is introduced and used for calculating the save size of objects. The previous method of calculating save size directly in each class was replaced with a call to the SaveSizeCounter's calc method. This results in a cleaner, more maintainable code as the size calculation logic is now centralized in one class. It is more efficient and scalable as any changes to the calculation can be made in one place and will be reflected everywhere.
2023-08-01 07:41:09 +03:00
IlushaShurupov
a918c83ec1 Objects adding dict test & fixes 2023-07-31 22:10:46 +03:00
IlushaShurupov
2c8e1470d1 Adding Simple Objest test. Fixes some bugs 2023-07-31 20:16:05 +03:00
IlushaShurupov
64e1f78739 Objects Compiled 2023-07-31 08:04:14 +03:00
IlushaShurupov
ba95747ef9 Merge branch 'Archiver' 2023-07-30 08:32:21 +03:00
IlyaShurupov
3575cbc543 Archiver Initial 2023-07-30 08:28:31 +03:00
IlushaShurupov
01ba8160ef Generating permutations and small buffer checks 2023-07-26 23:30:38 +03:00
IlushaShurupov
939e365a4f Objects Initial 2023-07-25 19:13:27 +03:00
IlushaShurupov
803ce23169 Objects Initial 2023-07-25 08:11:19 +03:00
IlushaShurupov
00bc875846 Freeze on no memory available 2023-07-24 20:39:28 +03:00
IlushaShurupov
5f186164a0 Graphics Animations & Renaming 2023-07-23 22:11:14 +03:00
Ilusha
3a68e70f03 Update cmake.yml to build Graphics 2023-07-23 17:05:35 +03:00
IlushaShurupov
e9c6a97a07 Reorganize a little 2023-07-23 16:50:51 +03:00
IlushaShurupov
3770c72ec0 Adding nanovg 2023-07-23 15:32:02 +03:00
IlushaShurupov
c4a7f91d56 New placement header 2023-07-23 15:32:02 +03:00
IlushaShurupov
6db1406d68 Graphics module Initial (And some more fixes embedded) 2023-07-23 15:31:34 +03:00
Ilusha
e81449eddf
Update cmake.yml - checkout submodules 2023-07-22 20:36:06 +03:00
IlushaShurupov
7595ae3926 Small changes 2023-07-22 20:32:03 +03:00
IlushaShurupov
e9dbee6667 Restructure Storage Module -> Connection module 2023-07-21 19:55:31 +03:00
IlushaShurupov
fa4d1d72dc Merge branch 'Storage' 2023-07-21 18:57:17 +03:00
IlushaShurupov
0301f608bd Fixed bug in map 2023-07-20 22:31:36 +03:00
IlushaShurupov
a543568e1d Restructure 2023-07-20 00:10:29 +03:00
IlushaShurupov
576a3565f7 Command Line INterpreter with fixes 2023-07-19 21:29:57 +03:00
IlushaShurupov
62cb2bb8b7 Fix File test 2023-07-18 23:48:54 +03:00
IlushaShurupov
8e00882bb3 Networking Initial 2023-07-18 23:37:04 +03:00
IlushaShurupov
df3767df29 Storage initial 2023-07-18 23:36:51 +03:00
IlushaShurupov
90998e2279 CommandLine parser initial 2023-07-18 22:37:53 +03:00
IlushaShurupov
6bca7431b7 Adding Strings tests 2023-07-17 22:32:55 +03:00
Ilusha
91b00817e3
Update cmake.yml 2023-07-17 20:49:19 +03:00
Ilusha
d80ea40848
Update cmake.yml 2023-07-17 20:45:05 +03:00
Ilusha
bedd88be2e
Try coverage cmake.yml 2023-07-17 20:43:45 +03:00
IlushaShurupov
bc892da992 Fixes 2023-07-16 18:28:24 +03:00
IlushaShurupov
fabceb52d3 Update Todo 2023-07-15 20:43:24 +03:00
IlushaShurupov
b68539cc0c Tokenizer Test 2023-07-15 20:03:52 +03:00
IlushaShurupov
44bad77e93 Tokenizer (No tests) 2023-07-15 18:58:31 +03:00
IlushaShurupov
e63843c6bb Remove Cmd Arg parser for now 2023-07-15 13:43:55 +03:00
IlushaShurupov
692994c2d3 Tokenizer Initial 2023-07-15 13:43:55 +03:00
IlushaShurupov
facc17ec1b Buffer 2d (No tests) 2023-07-15 13:43:23 +03:00
IlushaShurupov
4c9691e192 Remove old testing 2023-07-15 11:15:54 +03:00
IlushaShurupov
c75cb9fb48 Testing 2023-07-15 11:12:10 +03:00
IlushaShurupov
d362d8c3b3 Removing TextEditor from strings for now 2023-07-15 11:12:10 +03:00
IlushaShurupov
eb9210de1c Strings Initial 2023-07-15 11:12:10 +03:00
EgorPanteleev
9cf541a6ba
Update README.MD (#1) 2023-07-13 20:14:38 +03:00
347 changed files with 280221 additions and 6652 deletions

View file

@ -1,66 +1,211 @@
# Generated from CLion C/C++ Code Style settings
---
BasedOnStyle: LLVM
AccessModifierOffset: -2
AlignAfterOpenBracket: Align
AlignConsecutiveAssignments: None
AlignAfterOpenBracket: BlockIndent
AlignArrayOfStructures: None
AlignConsecutiveAssignments:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveBitFields:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveDeclarations:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignConsecutiveMacros:
Enabled: false
AcrossEmptyLines: false
AcrossComments: false
AlignCompound: false
PadOperators: false
AlignEscapedNewlines: Left
AlignOperands: Align
AllowAllArgumentsOnNextLine: false
AllowAllConstructorInitializersOnNextLine: false
AllowAllParametersOfDeclarationOnNextLine: false
AllowShortBlocksOnASingleLine: Always
AllowShortCaseLabelsOnASingleLine: false
AlignTrailingComments: true
AllowAllArgumentsOnNextLine: true
AllowAllConstructorInitializersOnNextLine: true
AllowAllParametersOfDeclarationOnNextLine: true
AllowShortBlocksOnASingleLine: Never
AllowShortCaseLabelsOnASingleLine: true
AllowShortEnumsOnASingleLine: true
AllowShortFunctionsOnASingleLine: All
AllowShortIfStatementsOnASingleLine: Always
AllowShortIfStatementsOnASingleLine: AllIfsAndElse
AllowShortLambdasOnASingleLine: All
AllowShortLoopsOnASingleLine: true
AllowShortLoopsOnASingleLine: false
AlwaysBreakAfterDefinitionReturnType: None
AlwaysBreakAfterReturnType: None
AlwaysBreakBeforeMultilineStrings: false
AlwaysBreakTemplateDeclarations: Yes
BreakBeforeBraces: Custom
AttributeMacros:
- __capability
BinPackArguments: false
BinPackParameters: false
BitFieldColonSpacing: Both
BraceWrapping:
AfterCaseLabel: false
AfterClass: false
AfterControlStatement: Never
AfterCaseLabel: true
AfterClass: true
AfterControlStatement: Always
AfterEnum: false
AfterFunction: false
AfterNamespace: false
AfterObjCDeclaration: false
AfterStruct: false
AfterUnion: false
AfterExternBlock: false
BeforeCatch: false
BeforeElse: false
BeforeLambdaBody: false
BeforeWhile: false
IndentBraces: false
SplitEmptyFunction: false
SplitEmptyFunction: true
SplitEmptyRecord: true
SplitEmptyNamespace: true
BreakAfterJavaFieldAnnotations: false
BreakBeforeBinaryOperators: None
BreakBeforeBraces: Attach
BreakBeforeConceptDeclarations: Always
BreakBeforeTernaryOperators: true
BreakConstructorInitializers: BeforeColon
BreakConstructorInitializers: AfterColon
BreakInheritanceList: BeforeColon
ColumnLimit: 0
BreakStringLiterals: true
ColumnLimit: 120
CommentPragmas: "^ IWYU pragma:"
CompactNamespaces: false
ContinuationIndentWidth: 4
ConstructorInitializerAllOnOneLineOrOnePerLine: false
ConstructorInitializerIndentWidth: 2
ContinuationIndentWidth: 2
Cpp11BracedListStyle: false
DeriveLineEnding: true
DerivePointerAlignment: false
DisableFormat: false
EmptyLineAfterAccessModifier: Never
EmptyLineBeforeAccessModifier: LogicalBlock
ExperimentalAutoDetectBinPacking: false
FixNamespaceComments: false
ForEachMacros:
- foreach
- Q_FOREACH
- BOOST_FOREACH
IfMacros:
- KJ_IF_MAYBE
IncludeBlocks: Preserve
IncludeCategories:
- Regex: ^"(llvm|llvm-c|clang|clang-c)/
Priority: 2
SortPriority: 0
CaseSensitive: false
- Regex: ^(<|"(gtest|gmock|isl|json)/)
Priority: 3
SortPriority: 0
CaseSensitive: false
- Regex: .*
Priority: 1
SortPriority: 0
CaseSensitive: false
IncludeIsMainRegex: (Test)?$
IncludeIsMainSourceRegex: ""
IndentAccessModifiers: false
IndentCaseBlocks: true
IndentCaseLabels: true
IndentExternBlock: AfterExternBlock
IndentGotoLabels: true
IndentPPDirectives: None
IndentRequiresClause: true
IndentWidth: 2
IndentWrappedFunctionNames: false
InsertBraces: false
InsertTrailingCommas: None
JavaScriptQuotes: Leave
JavaScriptWrapImports: true
KeepEmptyLinesAtTheStartOfBlocks: true
MaxEmptyLinesToKeep: 2
LambdaBodyIndentation: Signature
Language: Cpp
MacroBlockBegin: ""
MacroBlockEnd: ""
MaxEmptyLinesToKeep: 1
NamespaceIndentation: All
ObjCBinPackProtocolList: Auto
ObjCBlockIndentWidth: 2
ObjCBreakBeforeNestedBlockParam: true
ObjCSpaceAfterProperty: false
ObjCSpaceBeforeProtocolList: true
PPIndentWidth: -1
PackConstructorInitializers: Never
PenaltyBreakAssignment: 2
PenaltyBreakBeforeFirstCallParameter: 19
PenaltyBreakComment: 300
PenaltyBreakFirstLessLess: 120
PenaltyBreakOpenParenthesis: 0
PenaltyBreakString: 1000
PenaltyBreakTemplateDeclaration: 10
PenaltyExcessCharacter: 1000000
PenaltyIndentedWhitespace: 0
PenaltyReturnTypeOnItsOwnLine: 60
PointerAlignment: Left
ReflowComments: false
QualifierAlignment: Leave
ReferenceAlignment: Pointer
ReflowComments: true
RemoveBracesLLVM: false
RequiresClausePosition: OwnLine
SeparateDefinitionBlocks: Leave
ShortNamespaceLines: 1
SortIncludes: Never
SortJavaStaticImport: Before
SortUsingDeclarations: true
SpaceAfterCStyleCast: true
SpaceAfterLogicalNot: false
SpaceAfterTemplateKeyword: false
SpaceAfterTemplateKeyword: true
SpaceAroundPointerQualifiers: Default
SpaceBeforeAssignmentOperators: true
SpaceBeforeCaseColon: false
SpaceBeforeCpp11BracedList: false
SpaceBeforeCtorInitializerColon: true
SpaceBeforeInheritanceColon: true
SpaceBeforeParens: ControlStatements
SpaceBeforeRangeBasedForLoopColon: false
SpaceBeforeParensOptions:
AfterControlStatements: true
AfterForeachMacros: true
AfterFunctionDeclarationName: false
AfterFunctionDefinitionName: false
AfterIfMacros: true
AfterOverloadedOperator: false
AfterRequiresInClause: false
AfterRequiresInExpression: false
BeforeNonEmptyParentheses: false
SpaceBeforeRangeBasedForLoopColon: true
SpaceBeforeSquareBrackets: false
SpaceInEmptyBlock: false
SpaceInEmptyParentheses: false
SpacesBeforeTrailingComments: 0
SpacesInAngles: false
SpacesBeforeTrailingComments: 1
SpacesInAngles: Never
SpacesInCStyleCastParentheses: false
SpacesInContainerLiterals: false
SpacesInConditionalStatement: false
SpacesInContainerLiterals: true
SpacesInLineCommentPrefix:
Minimum: 1
Maximum: -1
SpacesInParentheses: false
SpacesInSquareBrackets: false
Standard: Latest
StatementAttributeLikeMacros:
- Q_EMIT
StatementMacros:
- Q_UNUSED
- QT_REQUIRE_VERSION
TabWidth: 2
UseTab: Always
UseCRLF: false
UseTab: ForContinuationAndIndentation
WhitespaceSensitiveMacros:
- STRINGIZE
- PP_STRINGIZE
- BOOST_PP_STRINGIZE
- NS_SWIFT_NAME
- CF_SWIFT_NAME

16
.cproject Normal file
View file

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<?fileVersion 4.0.0?><cproject storage_type_id="org.eclipse.cdt.core.XmlProjectDescriptionStorage">
<storageModule moduleId="org.eclipse.cdt.core.settings">
<cconfiguration id="org.eclipse.cdt.core.default.config.612128043">
<storageModule buildSystemId="org.eclipse.cdt.core.defaultConfigDataProvider" id="org.eclipse.cdt.core.default.config.612128043" moduleId="org.eclipse.cdt.core.settings" name="Configuration">
<externalSettings/>
<extensions/>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.externalSettings"/>
</cconfiguration>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.pathentry">
<pathentry excluding="**/CMakeFiles/**" kind="out" path="build"/>
</storageModule>
<storageModule moduleId="org.eclipse.cdt.core.LanguageSettingsProviders"/>
</cproject>

View file

@ -0,0 +1,428 @@
<mxfile host="Electron" modified="2023-10-29T20:02:24.324Z" agent="Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) draw.io/22.0.3 Chrome/114.0.5735.289 Electron/25.8.4 Safari/537.36" etag="26yH0Gc3erZ3uKcA6DFE" version="22.0.3" type="device">
<diagram name="Page-1" id="8edUMiMEU_fADqxzhr4b">
<mxGraphModel dx="1062" dy="-128" grid="0" gridSize="10" guides="1" tooltips="1" connect="1" arrows="1" fold="1" page="0" pageScale="1" pageWidth="850" pageHeight="1100" background="none" math="0" shadow="0">
<root>
<mxCell id="0" />
<mxCell id="1" parent="0" />
<mxCell id="Knp0EVw5rfMEdcPhjhnq-158" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="Knp0EVw5rfMEdcPhjhnq-22" target="Knp0EVw5rfMEdcPhjhnq-141" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<UserObject label="User Regular Language Rulles" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-22">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="380" y="1237" width="179" height="60" as="geometry" />
</mxCell>
</UserObject>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-157" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="Knp0EVw5rfMEdcPhjhnq-53" target="Knp0EVw5rfMEdcPhjhnq-146" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<UserObject label="User Context Free Language Rulles" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-53">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="482" y="1610" width="179" height="60" as="geometry" />
</mxCell>
</UserObject>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-116" value="Compiler API Rulles To parse Regular grammar Rulles" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;startSize=23;" parent="1" vertex="1">
<mxGeometry x="175" y="1351" width="384" height="158" as="geometry">
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
</mxGeometry>
</mxCell>
<UserObject label="RE Compiler API Rulles" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-124">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-116" vertex="1">
<mxGeometry x="24" y="37.5" width="332" height="46.5" as="geometry" />
</mxCell>
</UserObject>
<UserObject label="CF Compiler API Rulles" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-125">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-116" vertex="1">
<mxGeometry x="24" y="98.5" width="336" height="46.5" as="geometry" />
</mxCell>
</UserObject>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-126" value="CF Parser" style="swimlane;whiteSpace=wrap;html=1;startSize=23;" parent="1" vertex="1">
<mxGeometry x="2269" y="1405" width="999" height="823" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-13" value="Acceptor" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;" parent="Knp0EVw5rfMEdcPhjhnq-126" vertex="1">
<mxGeometry x="416" y="171" width="293" height="203" as="geometry">
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-34" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="Knp0EVw5rfMEdcPhjhnq-13" source="Knp0EVw5rfMEdcPhjhnq-14" target="Knp0EVw5rfMEdcPhjhnq-19" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-35" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="Knp0EVw5rfMEdcPhjhnq-13" source="Knp0EVw5rfMEdcPhjhnq-14" target="Knp0EVw5rfMEdcPhjhnq-18" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-36" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="Knp0EVw5rfMEdcPhjhnq-13" source="Knp0EVw5rfMEdcPhjhnq-14" target="Knp0EVw5rfMEdcPhjhnq-20" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<UserObject label="Automation" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-14">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-13" vertex="1">
<mxGeometry x="92" y="81.5" width="120" height="60" as="geometry" />
</mxCell>
</UserObject>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-18" value="SymbolStream" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-13" vertex="1">
<mxGeometry x="103.5" y="42" width="97" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-19" value="AST" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-13" vertex="1">
<mxGeometry x="131.5" y="159" width="41" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-20" value="Tables" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-13" vertex="1">
<mxGeometry x="15" y="98.5" width="53" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-54" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;" parent="Knp0EVw5rfMEdcPhjhnq-126" source="Knp0EVw5rfMEdcPhjhnq-37" target="Knp0EVw5rfMEdcPhjhnq-13" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-55" value="Get Symbol" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="Knp0EVw5rfMEdcPhjhnq-54" vertex="1" connectable="0">
<mxGeometry x="-0.5956" y="-1" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-137" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;" parent="Knp0EVw5rfMEdcPhjhnq-126" source="Knp0EVw5rfMEdcPhjhnq-37" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="953.4782608695655" y="398.6521739130435" as="targetPoint" />
<Array as="points">
<mxPoint x="563" y="733" />
<mxPoint x="919" y="733" />
<mxPoint x="919" y="399" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-37" value="Acceptor" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;" parent="Knp0EVw5rfMEdcPhjhnq-126" vertex="1">
<mxGeometry x="416" y="490" width="293" height="203" as="geometry">
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-38" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="Knp0EVw5rfMEdcPhjhnq-37" source="Knp0EVw5rfMEdcPhjhnq-41" target="Knp0EVw5rfMEdcPhjhnq-43" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-39" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="Knp0EVw5rfMEdcPhjhnq-37" source="Knp0EVw5rfMEdcPhjhnq-41" target="Knp0EVw5rfMEdcPhjhnq-42" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-40" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="Knp0EVw5rfMEdcPhjhnq-37" source="Knp0EVw5rfMEdcPhjhnq-41" target="Knp0EVw5rfMEdcPhjhnq-44" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<UserObject label="Automation" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-41">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-37" vertex="1">
<mxGeometry x="92" y="81.5" width="120" height="60" as="geometry" />
</mxCell>
</UserObject>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-42" value="SymbolStream" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-37" vertex="1">
<mxGeometry x="103.5" y="42" width="97" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-43" value="AST" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-37" vertex="1">
<mxGeometry x="131.5" y="159" width="41" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-44" value="Tables" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-37" vertex="1">
<mxGeometry x="15" y="98.5" width="53" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-59" value="Finate State Automation" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="Knp0EVw5rfMEdcPhjhnq-126" vertex="1">
<mxGeometry x="721" y="175.5" width="146" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-60" value="Push Down Automation" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="Knp0EVw5rfMEdcPhjhnq-126" vertex="1">
<mxGeometry x="726" y="490" width="143" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-131" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;" parent="Knp0EVw5rfMEdcPhjhnq-126" source="Knp0EVw5rfMEdcPhjhnq-82" target="Knp0EVw5rfMEdcPhjhnq-37" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-134" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;" parent="Knp0EVw5rfMEdcPhjhnq-126" source="Knp0EVw5rfMEdcPhjhnq-82" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="24.947368421052943" y="591.5" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-82" value="CFG Compiler" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;" parent="Knp0EVw5rfMEdcPhjhnq-126" vertex="1">
<mxGeometry x="93" y="448.5" width="281" height="286" as="geometry">
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-88" value="CF Comp Rules" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-82" vertex="1">
<mxGeometry x="7" y="130" width="103" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-90" value="Tables" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-82" vertex="1">
<mxGeometry x="210" y="132.5" width="53" height="26" as="geometry" />
</mxCell>
<UserObject label="LL" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-91">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-82" vertex="1">
<mxGeometry x="116" y="51.75" width="83" height="46.5" as="geometry" />
</mxCell>
</UserObject>
<UserObject label="Canonical" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-92">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-82" vertex="1">
<mxGeometry x="116" y="119.75" width="83" height="46.5" as="geometry" />
</mxCell>
</UserObject>
<UserObject label="LALR" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-93">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-82" vertex="1">
<mxGeometry x="116" y="187.75" width="83" height="46.5" as="geometry" />
</mxCell>
</UserObject>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-132" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;" parent="Knp0EVw5rfMEdcPhjhnq-126" source="Knp0EVw5rfMEdcPhjhnq-94" target="Knp0EVw5rfMEdcPhjhnq-13" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-133" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;" parent="Knp0EVw5rfMEdcPhjhnq-126" source="Knp0EVw5rfMEdcPhjhnq-94" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="24.947368421052943" y="272.5" as="targetPoint" />
</mxGeometry>
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-94" value="RE Compiler" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;startSize=23;" parent="Knp0EVw5rfMEdcPhjhnq-126" vertex="1">
<mxGeometry x="122" y="228.25" width="260" height="88.5" as="geometry">
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-95" value="RE Compiler Rulles" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-94" vertex="1">
<mxGeometry x="13" y="33.75" width="123" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-96" value="Tables" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-94" vertex="1">
<mxGeometry x="187" y="39.5" width="53" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-154" value="Sentence" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;" parent="Knp0EVw5rfMEdcPhjhnq-126" vertex="1">
<mxGeometry x="21" y="149.5" width="69" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-56" style="edgeStyle=orthogonalEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;" parent="Knp0EVw5rfMEdcPhjhnq-126" source="Knp0EVw5rfMEdcPhjhnq-13" target="Knp0EVw5rfMEdcPhjhnq-154" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="94" y="166" as="targetPoint" />
<Array as="points">
<mxPoint x="626" y="104" />
<mxPoint x="281" y="104" />
<mxPoint x="281" y="166" />
</Array>
</mxGeometry>
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-57" value="Get Symbol" style="edgeLabel;html=1;align=center;verticalAlign=middle;resizable=0;points=[];" parent="Knp0EVw5rfMEdcPhjhnq-56" vertex="1" connectable="0">
<mxGeometry x="-0.0483" relative="1" as="geometry">
<mxPoint as="offset" />
</mxGeometry>
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-127" value="Compiler API Rulles To parse Regular grammar Rulles" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;startSize=23;" parent="1" vertex="1">
<mxGeometry x="285" y="1720" width="385" height="158" as="geometry">
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
</mxGeometry>
</mxCell>
<UserObject label="RE Compiler API Rulles" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-128">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-127" vertex="1">
<mxGeometry x="24" y="37.5" width="340" height="46.5" as="geometry" />
</mxCell>
</UserObject>
<UserObject label="CF Compiler API Rulles" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-129">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-127" vertex="1">
<mxGeometry x="24" y="98.5" width="340" height="46.5" as="geometry" />
</mxCell>
</UserObject>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-162" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="Knp0EVw5rfMEdcPhjhnq-130" target="Knp0EVw5rfMEdcPhjhnq-151" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<UserObject label="User Sentence" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-130">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1063" y="1056" width="120" height="60" as="geometry" />
</mxCell>
</UserObject>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-138" value="CF Parser" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;" parent="1" vertex="1">
<mxGeometry x="622" y="1273" width="337" height="173" as="geometry">
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-139" value="CF AST Rulles for Tokenizer" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-138" vertex="1">
<mxGeometry x="19" y="80" width="168" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-140" value="CF AST Rulles for an acceptor" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-138" vertex="1">
<mxGeometry x="19" y="125" width="180" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-141" value="CF Sentence" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-138" vertex="1">
<mxGeometry x="19" y="37" width="88" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-142" value="AST" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-138" vertex="1">
<mxGeometry x="265" y="73.5" width="41" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-143" value="CF Parser" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;" parent="1" vertex="1">
<mxGeometry x="714" y="1645" width="337" height="173" as="geometry">
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-144" value="CF AST Rulles for Tokenizer" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-143" vertex="1">
<mxGeometry x="19" y="80" width="168" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-145" value="CF AST Rulles for an acceptor" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-143" vertex="1">
<mxGeometry x="19" y="125" width="180" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-146" value="CF Sentence" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-143" vertex="1">
<mxGeometry x="19" y="37" width="88" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-147" value="AST" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-143" vertex="1">
<mxGeometry x="265" y="73.5" width="41" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-148" value="CF Parser" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;" parent="1" vertex="1">
<mxGeometry x="1391" y="1401" width="337" height="173" as="geometry">
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-149" value="RE Compiler API Rulles for FSA" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-148" vertex="1">
<mxGeometry x="36" y="79.75" width="189" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-150" value="CF Compiler API Rulles for an PDA acceptor" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-148" vertex="1">
<mxGeometry x="36" y="124" width="255" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-151" value="CF Sentence" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-148" vertex="1">
<mxGeometry x="19" y="37" width="88" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-152" value="Sentence AST" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" parent="Knp0EVw5rfMEdcPhjhnq-148" vertex="1">
<mxGeometry x="229" y="35" width="95" height="26" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-155" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="Knp0EVw5rfMEdcPhjhnq-129" target="Knp0EVw5rfMEdcPhjhnq-145" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-156" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="Knp0EVw5rfMEdcPhjhnq-128" target="Knp0EVw5rfMEdcPhjhnq-144" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-159" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="Knp0EVw5rfMEdcPhjhnq-124" target="Knp0EVw5rfMEdcPhjhnq-139" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-160" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" parent="1" source="Knp0EVw5rfMEdcPhjhnq-125" target="Knp0EVw5rfMEdcPhjhnq-140" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-165" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="1" source="B2JnEC1cqt8830IlIT0b-3" target="Knp0EVw5rfMEdcPhjhnq-149" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-166" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="1" source="B2JnEC1cqt8830IlIT0b-1" target="Knp0EVw5rfMEdcPhjhnq-150" edge="1">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="Knp0EVw5rfMEdcPhjhnq-167" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" parent="1" source="Knp0EVw5rfMEdcPhjhnq-152" target="Knp0EVw5rfMEdcPhjhnq-168" edge="1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="1909.9999999999995" y="1483" as="targetPoint" />
</mxGeometry>
</mxCell>
<UserObject label="User AST" treeRoot="1" id="Knp0EVw5rfMEdcPhjhnq-168">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;fillColor=#d5e8d4;strokeColor=#82b366;" parent="1" vertex="1">
<mxGeometry x="1977" y="1190" width="120" height="60" as="geometry" />
</mxCell>
</UserObject>
<mxCell id="B2JnEC1cqt8830IlIT0b-2" value="" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" edge="1" parent="1" source="Knp0EVw5rfMEdcPhjhnq-147" target="B2JnEC1cqt8830IlIT0b-1">
<mxGeometry relative="1" as="geometry">
<mxPoint x="1020" y="1732" as="sourcePoint" />
<mxPoint x="1408" y="1535" as="targetPoint" />
</mxGeometry>
</mxCell>
<UserObject label="AST to CF Compiler API" treeRoot="1" id="B2JnEC1cqt8830IlIT0b-1">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;" vertex="1" parent="1">
<mxGeometry x="1117" y="1613" width="197" height="46.5" as="geometry" />
</mxCell>
</UserObject>
<mxCell id="B2JnEC1cqt8830IlIT0b-4" value="" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" edge="1" parent="1" source="Knp0EVw5rfMEdcPhjhnq-142" target="B2JnEC1cqt8830IlIT0b-3">
<mxGeometry relative="1" as="geometry">
<mxPoint x="1032" y="1311" as="sourcePoint" />
<mxPoint x="1408" y="1490" as="targetPoint" />
</mxGeometry>
</mxCell>
<UserObject label="AST to RE Compiler API" treeRoot="1" id="B2JnEC1cqt8830IlIT0b-3">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;" vertex="1" parent="1">
<mxGeometry x="1107" y="1470.5" width="197" height="46.5" as="geometry" />
</mxCell>
</UserObject>
<mxCell id="B2JnEC1cqt8830IlIT0b-41" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" edge="1" parent="1" source="B2JnEC1cqt8830IlIT0b-42" target="B2JnEC1cqt8830IlIT0b-56">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<UserObject label="Language Grammar &lt;br&gt;(CF RE United Format)" treeRoot="1" id="B2JnEC1cqt8830IlIT0b-42">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="422" y="2209" width="179" height="60" as="geometry" />
</mxCell>
</UserObject>
<mxCell id="B2JnEC1cqt8830IlIT0b-45" value="Grammar For CF RE United Grammar Format" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;startSize=23;" vertex="1" parent="1">
<mxGeometry x="253" y="2439" width="384" height="158" as="geometry">
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
</mxGeometry>
</mxCell>
<UserObject label="RE Compiler API Rulles" treeRoot="1" id="B2JnEC1cqt8830IlIT0b-46">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-45">
<mxGeometry x="24" y="37.5" width="332" height="46.5" as="geometry" />
</mxCell>
</UserObject>
<UserObject label="CF Compiler API Rulles" treeRoot="1" id="B2JnEC1cqt8830IlIT0b-47">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-45">
<mxGeometry x="24" y="98.5" width="336" height="46.5" as="geometry" />
</mxCell>
</UserObject>
<mxCell id="B2JnEC1cqt8830IlIT0b-51" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" edge="1" parent="1" source="B2JnEC1cqt8830IlIT0b-52" target="B2JnEC1cqt8830IlIT0b-66">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<UserObject label="User Sentence" treeRoot="1" id="B2JnEC1cqt8830IlIT0b-52">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="422" y="2132" width="180" height="60" as="geometry" />
</mxCell>
</UserObject>
<mxCell id="B2JnEC1cqt8830IlIT0b-53" value="CF Parser" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;" vertex="1" parent="1">
<mxGeometry x="700" y="2361" width="337" height="173" as="geometry">
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="B2JnEC1cqt8830IlIT0b-54" value="CF AST Rulles for Tokenizer" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-53">
<mxGeometry x="19" y="80" width="168" height="26" as="geometry" />
</mxCell>
<mxCell id="B2JnEC1cqt8830IlIT0b-55" value="CF AST Rulles for an acceptor" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-53">
<mxGeometry x="19" y="125" width="180" height="26" as="geometry" />
</mxCell>
<mxCell id="B2JnEC1cqt8830IlIT0b-56" value="CF Sentence" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-53">
<mxGeometry x="19" y="37" width="88" height="26" as="geometry" />
</mxCell>
<mxCell id="B2JnEC1cqt8830IlIT0b-57" value="AST" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-53">
<mxGeometry x="265" y="73.5" width="41" height="26" as="geometry" />
</mxCell>
<mxCell id="B2JnEC1cqt8830IlIT0b-63" value="CF Parser" style="swimlane;rounded=0;swimlaneLine=0;fontColor=default;fontSize=14;" vertex="1" parent="1">
<mxGeometry x="1415" y="2271" width="337" height="173" as="geometry">
<mxRectangle x="453" y="256" width="50" height="44" as="alternateBounds" />
</mxGeometry>
</mxCell>
<mxCell id="B2JnEC1cqt8830IlIT0b-64" value="RE Compiler API Rulles for FSA" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-63">
<mxGeometry x="36" y="79.75" width="189" height="26" as="geometry" />
</mxCell>
<mxCell id="B2JnEC1cqt8830IlIT0b-65" value="CF Compiler API Rulles for an PDA acceptor" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-63">
<mxGeometry x="36" y="124" width="255" height="26" as="geometry" />
</mxCell>
<mxCell id="B2JnEC1cqt8830IlIT0b-66" value="CF Sentence" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-63">
<mxGeometry x="19" y="37" width="88" height="26" as="geometry" />
</mxCell>
<mxCell id="B2JnEC1cqt8830IlIT0b-67" value="Sentence AST" style="text;html=1;align=center;verticalAlign=middle;resizable=0;points=[];autosize=1;strokeColor=none;fillColor=none;rounded=0;" vertex="1" parent="B2JnEC1cqt8830IlIT0b-63">
<mxGeometry x="229" y="35" width="95" height="26" as="geometry" />
</mxCell>
<mxCell id="B2JnEC1cqt8830IlIT0b-70" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" edge="1" parent="1" source="B2JnEC1cqt8830IlIT0b-46" target="B2JnEC1cqt8830IlIT0b-54">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="B2JnEC1cqt8830IlIT0b-71" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;startArrow=none;endArrow=none;" edge="1" parent="1" source="B2JnEC1cqt8830IlIT0b-47" target="B2JnEC1cqt8830IlIT0b-55">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="B2JnEC1cqt8830IlIT0b-72" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" edge="1" parent="1" source="B2JnEC1cqt8830IlIT0b-79" target="B2JnEC1cqt8830IlIT0b-64">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="B2JnEC1cqt8830IlIT0b-73" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" edge="1" parent="1" source="B2JnEC1cqt8830IlIT0b-77" target="B2JnEC1cqt8830IlIT0b-65">
<mxGeometry relative="1" as="geometry" />
</mxCell>
<mxCell id="B2JnEC1cqt8830IlIT0b-74" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" edge="1" parent="1" source="B2JnEC1cqt8830IlIT0b-67" target="B2JnEC1cqt8830IlIT0b-75">
<mxGeometry relative="1" as="geometry">
<mxPoint x="1933.9999999999995" y="2353" as="targetPoint" />
</mxGeometry>
</mxCell>
<UserObject label="User AST" treeRoot="1" id="B2JnEC1cqt8830IlIT0b-75">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;fillColor=#d5e8d4;strokeColor=#82b366;" vertex="1" parent="1">
<mxGeometry x="2001" y="2060" width="120" height="60" as="geometry" />
</mxCell>
</UserObject>
<mxCell id="B2JnEC1cqt8830IlIT0b-76" value="" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" edge="1" parent="1" source="B2JnEC1cqt8830IlIT0b-57" target="B2JnEC1cqt8830IlIT0b-77">
<mxGeometry relative="1" as="geometry">
<mxPoint x="1044" y="2601.5" as="sourcePoint" />
<mxPoint x="1432" y="2405" as="targetPoint" />
</mxGeometry>
</mxCell>
<UserObject label="AST to CF Compiler API" treeRoot="1" id="B2JnEC1cqt8830IlIT0b-77">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;" vertex="1" parent="1">
<mxGeometry x="1141" y="2483" width="197" height="46.5" as="geometry" />
</mxCell>
</UserObject>
<mxCell id="B2JnEC1cqt8830IlIT0b-78" value="" style="edgeStyle=elbowEdgeStyle;orthogonalLoop=1;jettySize=auto;html=1;endArrow=none;endFill=0;" edge="1" parent="1" source="B2JnEC1cqt8830IlIT0b-57" target="B2JnEC1cqt8830IlIT0b-79">
<mxGeometry relative="1" as="geometry">
<mxPoint x="1056" y="2181" as="sourcePoint" />
<mxPoint x="1432" y="2360" as="targetPoint" />
</mxGeometry>
</mxCell>
<UserObject label="AST to RE Compiler API" treeRoot="1" id="B2JnEC1cqt8830IlIT0b-79">
<mxCell style="whiteSpace=wrap;html=1;align=center;treeFolding=1;treeMoving=1;newEdgeStyle={&quot;edgeStyle&quot;:&quot;elbowEdgeStyle&quot;,&quot;startArrow&quot;:&quot;none&quot;,&quot;endArrow&quot;:&quot;none&quot;};labelBackgroundColor=none;rounded=0;" vertex="1" parent="1">
<mxGeometry x="1151" y="2371" width="197" height="46.5" as="geometry" />
</mxCell>
</UserObject>
</root>
</mxGraphModel>
</diagram>
</mxfile>

BIN
.docs/Gallery/Oscript.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 MiB

BIN
.docs/Gallery/RayTracer.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 416 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 30 KiB

BIN
.docs/Gallery/Sketch3D.gif Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 MiB

16
.docs/Gallery/oscript.txt Normal file
View file

@ -0,0 +1,16 @@
method myLogFunction(value) {
print value;
}
myLogFunction("hello");
var i = 10;
if (i == 10) {
while (i > 0) {
print i;
i = i - 1;
}
} else {
print "still doin' heavy calculations...";
}

17
.github/workflows/WindowsPlatform.yml vendored Normal file
View file

@ -0,0 +1,17 @@
name: Windows
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
jobs:
build:
runs-on: self-hosted
steps:
- uses: actions/checkout@v3
#- name: Build
#run: echo hello

View file

@ -0,0 +1,62 @@
# This starter workflow is for a CMake project running on a single platform. There is a different starter workflow if you need cross-platform coverage.
# See: https://github.com/actions/starter-workflows/blob/main/ci/cmake-multi-platform.yml
name: CMake on a single platform
on:
push:
branches: [ "master" ]
pull_request:
branches: [ "master" ]
env:
# Customize the CMake build type here (Release, Debug, RelWithDebInfo, etc.)
BUILD_TYPE: Release
jobs:
build:
# The CMake configure and build commands are platform agnostic and should work equally well on Windows or Mac.
# You can convert this to a matrix build if you need cross-platform coverage.
# See: https://docs.github.com/en/free-pro-team@latest/actions/learn-github-actions/managing-complex-workflows#using-a-build-matrix
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v3
- name: Sutup Dependencies
run: |
sudo apt-get update
sudo apt-get install python3 python-is-python3
sudo apt-get install -y libx11-dev libgl1-mesa-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev
sudo apt-get install -y clang-15
sudo apt-get install -y libasound2-dev libglew-dev
sudo apt-get install -y portaudio19-dev
sudo apt-get install -y libwayland-dev libxkbcommon-dev
- name: install OpenImageDenoise
run: |
sudo snap install ispc
sudo apt-get install -y libtbb-dev
git clone --recursive https://github.com/RenderKit/oidn.git
cd oidn
mkdir build; cd build; cmake ..; make -j;
sudo make install
- name: Update repository
run: |
git submodule update --init --recursive
- name: Configure CMake
# Configure CMake in a 'build' subdirectory. `CMAKE_BUILD_TYPE` is only required if you are using a single-configuration generator such as make.
# See https://cmake.org/cmake/help/latest/variable/CMAKE_BUILD_TYPE.html?highlight=cmake_build_type
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
- name: Build
# Build your program with the given configuration
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -- -j$(nproc)
- name: Test
working-directory: ${{github.workspace}}/build
# Execute tests defined by the CMake configuration.
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ctest -C ${{env.BUILD_TYPE}}

View file

@ -20,23 +20,45 @@ jobs:
steps:
- uses: actions/checkout@v3
- name: Install LLVM
run: sudo apt-get install -y llvm
- name: Set LLVM Toolchain
- name: Setup
shell: bash
run: |
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++ 10
sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 20
# If your submodules are configured to use SSH instead of HTTPS please uncomment the following line
# git config --global url."https://github.com/".insteadOf "git@github.com:"
auth_header="$(git config --local --get http.https://github.com/.extraheader)"
git submodule sync --recursive
git -c "http.extraheader=$auth_header" -c protocol.version=2 submodule update --init --force --recursive --depth=1
sudo apt-get update
sudo apt-get install python3 python-is-python3
sudo apt-get install -y libx11-dev libgl1-mesa-dev libxrandr-dev libxinerama-dev libxcursor-dev libxi-dev
sudo apt-get install -y clang-15
sudo apt-get install -y libasound2-dev libglew-dev
sudo apt-get install -y portaudio19-dev
#cd Externals/glew/
#make extensions
sudo apt update
#- name: Set LLVM Toolchain
#run: |
# sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/g++ 10
# sudo update-alternatives --install /usr/bin/c++ c++ /usr/bin/clang++ 20
- name: Configure CMake
run: cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
run: |
gcc -v
clang++-15 -v
CC=clang-15 CXX=clang++-15 cmake -B ${{github.workspace}}/build -DCMAKE_BUILD_TYPE=${{env.BUILD_TYPE}}
- name: Build
run: cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}}
run: CC=clang CXX=clang++ cmake --build ${{github.workspace}}/build --config ${{env.BUILD_TYPE}} -v -j
- name: Test
working-directory: ${{github.workspace}}/build
# Execute tests defined by the CMake configuration.
# See https://cmake.org/cmake/help/latest/manual/ctest.1.html for more detail
run: ctest -C ${{env.BUILD_TYPE}}
run: ctest -j -C ${{env.BUILD_TYPE}}

5
.gitignore vendored
View file

@ -2,6 +2,11 @@
*tmp*
bin
build*
*build*
lib
install
.vscode
out
.vs
*.bkp
*.$*

21
.gitmodules vendored Normal file
View file

@ -0,0 +1,21 @@
[submodule "Externals/imgui"]
path = Externals/imgui
url = https://github.com/elushaX/imgui.git
[submodule "Externals/lua"]
path = Externals/lua
url = https://github.com/elushaX/lua.git
[submodule "Externals/unittest-cpp"]
path = Externals/unittest-cpp
url = https://github.com/elushaX/unittest-cpp.git
[submodule "Externals/glfw"]
path = Externals/glfw
url = https://github.com/elushaX/glfw.git
[submodule "Externals/nanovg"]
path = Externals/nanovg
url = https://github.com/elushaX/nanovg.git
[submodule "Externals/lalr"]
path = Externals/lalr
url = https://github.com/elushaX/lalr.git
[submodule "Externals/asio"]
path = Externals/asio
url = https://github.com/elushaX/asio.git

20
.project Normal file
View file

@ -0,0 +1,20 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>Modules</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.cdt.core.cBuilder</name>
<triggers>clean,full,incremental,</triggers>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.cdt.core.cnature</nature>
<nature>org.eclipse.cdt.core.ccnature</nature>
<nature>org.eclipse.cdt.cmake.core.cmakeNature</nature>
</natures>
</projectDescription>

View file

@ -3,20 +3,18 @@ cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_STANDARD 23)
project(Allocator)
project(Language)
### ---------------------- Static Library --------------------- ###
file(GLOB SOURCES "./private/*.cpp")
file(GLOB HEADERS "./public/*.hpp")
file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp")
file(GLOB HEADERS "./public/*.hpp" "./public/*/*.hpp")
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
target_link_libraries(${PROJECT_NAME} PUBLIC Utils)
target_include_directories(${PROJECT_NAME} PUBLIC public/)
target_link_libraries(${PROJECT_NAME} PUBLIC Strings)
### -------------------------- Tests -------------------------- ###
enable_testing()
file(GLOB TEST_SOURCES "./tests/*.cpp")
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils)
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} UnitTest++)
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/lib)

View file

@ -0,0 +1,36 @@
#include "Grammar.hpp"
using namespace tp;
ContextFreeGrammar::Arg::Arg(const String& id, bool terminal, bool epsilon) {
mId = id;
mIsTerminal = terminal;
mIsEpsilon = epsilon;
}
const String& ContextFreeGrammar::Arg::getId() const { return mId; }
bool ContextFreeGrammar::Arg::operator==(const Arg& in) const {
return (mId == in.mId) && (mIsEpsilon == in.mIsEpsilon) && (mIsTerminal == in.mIsTerminal);
}
ContextFreeGrammar::Rule::Rule(const String& id, const InitialierList<Arg>& args) {
mId = id;
mArgs = args;
}
bool ContextFreeGrammar::Rule::operator==(const Rule& in) const { return (mId == in.mId) && (mArgs == in.mArgs); }
bool ContextFreeGrammar::Rule::isProductive() const {
for (auto arg : mArgs) {
if (arg->getId() == mId) return false;
}
return true;
}
void ContextFreeGrammar::addRule(const Rule& rule) { mRules.append(rule); }
void ContextFreeGrammar::addRule(const String& id, const InitialierList<Arg>& args) { addRule(Rule(id, args)); }
void ContextFreeGrammar::setStart(const String& startRule) { mStartTerminal = startRule; }

View file

@ -0,0 +1,8 @@
#include "LanguageCommon.hpp"
#include "Strings.hpp"
using namespace tp;
static ModuleManifest* sModuleDependencies[] = { &gModuleStrings, nullptr };
ModuleManifest tp::gModuleLanguage = ModuleManifest("Language", nullptr, nullptr, sModuleDependencies);

View file

@ -0,0 +1,249 @@
#pragma once
#include "Utils.hpp"
#include "List.hpp"
#include "Map.hpp"
#include "Tree.hpp"
namespace tp {
// Non-Deterministic Finite-State Automata
template <typename tAlphabetType, typename tStateType>
class FiniteStateAutomation {
public:
struct State;
public:
class Transition {
friend FiniteStateAutomation;
public:
enum Type { ANY, EPSILON, SYMBOL };
public:
Transition(Type type, State* state, tAlphabetType symbol = tAlphabetType()) {
mState = state;
mType = type;
mSymbol = symbol;
}
[[nodiscard]] bool isTransition(const tAlphabetType& symbol) const {
return (mType == ANY || mType == EPSILON) || (mSymbol == symbol);
}
[[nodiscard]] bool doesConsumes(const tAlphabetType& symbol) const {
return (mType == ANY || (mType == SYMBOL && mSymbol == symbol));
}
[[nodiscard]] bool isEpsilon() const { return mType == EPSILON; }
const State* getState() const { return mState; }
const tAlphabetType& getSymbol() const { return mSymbol; }
private:
State* mState = nullptr;
Type mType;
tAlphabetType mSymbol;
};
class State {
friend FiniteStateAutomation;
public:
State() = default;
public:
void setValue(const tStateType& stateValue) { mStateVal = stateValue; }
void setAcceptance(bool isAccepting) { mIsAccepting = isAccepting; }
[[nodiscard]] bool isAccepting() const { return mIsAccepting; }
const tStateType& getStateVal() const { return mStateVal; }
[[nodiscard]] const Buffer<Transition>* getTransitions() const { return &mTransitions; }
private:
Buffer<Transition> mTransitions{};
tStateType mStateVal = tStateType();
bool mIsAccepting = false;
};
private:
List<State> mStates;
State* mStartState = nullptr;
Range<ualni> mAlphabetRange = { ENV_UALNI_MAX, ENV_UALNI_MIN };
public:
FiniteStateAutomation() = default;
State* addState(const tStateType& state, bool accepting) {
auto node = mStates.newNode();
node->data.mIsAccepting = accepting;
node->data.mStateVal = state;
mStates.pushBack(node);
return &node->data;
}
void addTransition(State* from, State* to, const tAlphabetType& symbol) {
from->mTransitions.append(Transition(Transition::SYMBOL, to, symbol));
if (mAlphabetRange.mBegin < ualni(symbol)) mAlphabetRange.mBegin = ualni(symbol);
if (mAlphabetRange.mEnd > ualni(symbol)) mAlphabetRange.mEnd = ualni(symbol);
}
void addEpsilonTransition(State* from, State* to) { from->mTransitions.append(Transition(Transition::SYMBOL, to)); }
void addAnyTransition(State* from, State* to) { from->mTransitions.append(Transition(Transition::ANY, to)); }
void setStartState(State* start) { mStartState = start; }
[[nodiscard]] State* getStartState() const { return mStartState; }
[[nodiscard]] bool isValid() const {
if (!mStartState) {
return false;
}
return true;
}
[[nodiscard]] ualni numStates() const { return mStates.length(); }
[[nodiscard]] const List<State>* getStates() const { return &mStates; }
[[nodiscard]] Range<ualni> getAlphabetRange() const { return mAlphabetRange; }
private:
typedef AvlTree<AvlNumericKey<State*>, bool> StatesSet;
// Expands initial set with states that are reachable from initial set with no input consumption (E-transitions)
static void expandSet(StatesSet& set) {
List<State*> workingSet;
set.forEach([&](AvlNumericKey<State*>& key, bool) { workingSet.pushBack(key.val); });
while (workingSet.length()) {
auto first = workingSet.first()->data;
set.insert(first, {});
for (auto transition : first->mTransitions) {
if (!transition->isEpsilon()) continue;
if (set.find(transition->mState)) continue;
workingSet.pushBack(transition->mState);
}
workingSet.popFront();
}
}
// States that are reachable from initial set with symbol transition
static void findMoveSet(StatesSet& from, StatesSet& moveSet, tAlphabetType symbol) {
from.forEach([&](AvlNumericKey<State*>& key, bool) {
for (auto transition : key.val->mTransitions) {
if (transition->isEpsilon()) continue;
if (!transition->isTransition(symbol)) continue;
if (moveSet.find(transition->mState)) continue;
moveSet.insert(transition->mState, {});
}
});
}
public:
bool makeDeterministic() {
if (!isValid()) return false;
struct GroupKey {
const StatesSet* group;
static ualni hash(GroupKey key) { return 0; }
bool operator==(const GroupKey& key) const { return false; }
};
struct GroupInfo {
StatesSet* group = nullptr;
AvlTree<AvlNumericKey<StatesSet*>, tAlphabetType> transitions;
State* newState = nullptr;
bool accepting = false;
tStateType stateVal = tStateType();
};
Buffer<StatesSet> groups = { {} };
Map<GroupKey, GroupInfo, DefaultAllocator, GroupKey::hash> groupInfos;
groups.first().insert(getStartState(), false);
expandSet(groups.first());
groupInfos.put({ &groups.first() }, { &groups.first() });
// 1) find new states
List<StatesSet*> workingSet;
workingSet.pushBack(&groups.first());
while (workingSet.length()) {
StatesSet* group = workingSet.first()->data;
GroupInfo* info = &groupInfos.get({ group });
for (auto symbol : getAlphabetRange()) {
// calculate new possible state
StatesSet potentialGroup;
findMoveSet(*group, potentialGroup, tAlphabetType(symbol));
expandSet(potentialGroup);
if (!potentialGroup.size()) continue;
// find existing or create group
StatesSet* targetGroup = nullptr;
auto iter = groupInfos.presents({ &potentialGroup });
if (iter) {
targetGroup = groupInfos.getSlotVal(iter).group;
} else {
targetGroup = &groups.append(potentialGroup);
groupInfos.put({ targetGroup }, { targetGroup });
workingSet.pushBack(targetGroup);
}
// assert transition is added
info->transitions.insert(targetGroup, tAlphabetType(symbol));
}
workingSet.popFront();
}
// 2) find new states termination values
for (auto group : groupInfos) {
GroupInfo* info = &group->val;
ualni accepting = 0;
info->group->forEach([&](AvlNumericKey<State*>& key, bool) {
if (key.val->mIsAccepting) {
accepting++;
info->accepting = true;
info->stateVal = key.val->mStateVal;
}
});
if (!accepting) {
info->accepting = false;
info->stateVal = info->group->head()->key.val->mStateVal;
}
}
// 3) transfer
mStates.removeAll();
// create states
for (auto group : groupInfos) {
group->val.newState = addState(group->val.stateVal, group->val.accepting);
}
// create transitions
for (auto group : groupInfos) {
auto functor = [&](AvlNumericKey<StatesSet*> targetGroupKey, tAlphabetType symbol) {
GroupInfo* targetGroup = &groupInfos.get({ (StatesSet*) targetGroupKey.val });
addTransition(group->val.newState, targetGroup->newState, symbol);
};
group->val.transitions.forEach(functor);
}
return true;
}
};
}

View file

@ -0,0 +1,137 @@
#pragma once
#include "Strings.hpp"
#include "Automata.hpp"
#include "Buffer2D.hpp"
namespace tp {
template <typename tAlphabetType, typename tStateType>
class ContextFreeAutomata {
struct Action {
enum Type { SHIFT, REDUCE, TRAP } type = TRAP;
ualni num = 0; // state to shift (shift action) or pop count (reduce action)
};
public:
struct StackItem {
ualni state = 0;
tAlphabetType symbol;
Buffer<StackItem*> leafs;
};
struct AcceptResult {
bool accepted = false;
ualni advancedIdx = 0;
const StackItem* ast = nullptr;
};
public:
ContextFreeAutomata() = default;
AcceptResult accept(const tAlphabetType* stream, ualni size) {
mCurrentState = mStartState;
mStack.append(&mItems.append({ mCurrentState, {}, {} }));
ualni advancedIdx = 0;
while (advancedIdx < size) {
const tAlphabetType& symbol = *(stream + advancedIdx);
if (!(symbol >= mRange.mBegin && symbol < mRange.mEnd)) {
return { false, advancedIdx, nullptr };
}
const Action& action = mTable.get({ ualni(symbol - mRange.mBegin), mCurrentState });
if (action.type == Action::TRAP) {
return { false, advancedIdx, nullptr };
}
if (action.type == Action::SHIFT) {
mStack.last()->symbol = symbol;
mStack.append(&mItems.append({ mCurrentState, {}, {} }));
mCurrentState = action.num;
}
if (mTable.get({ 0, mCurrentState }).type == Action::REDUCE) {
StackItem* newItem = &mItems.append(StackItem{});
for (auto iter : Range<ualni>(action.num)) {
newItem->leafs.append(mStack.last());
mCurrentState = mStack.last()->state;
mStack.pop();
}
if (!mStack.size()) {
if (advancedIdx == size) {
return { true, advancedIdx, newItem };
} else {
return { false, advancedIdx, {} };
}
}
mStack.append(&mItems.append({ mCurrentState, {}, {} }));
}
advancedIdx++;
}
return { false, advancedIdx, nullptr };
}
public:
typedef FiniteStateAutomation<tAlphabetType, tStateType> Automata;
typedef Automata::State AutomataState;
void construct(const Automata& automata) {
mRange = automata.getAlphabetRange();
const ualni numStates = automata.numStates();
const ualni numSymbols = mRange.idxDiff();
mTable.reserve({ numSymbols, numStates });
mTable.assign(Action{ Action::TRAP, 0 });
Map<const AutomataState*, ualni> states;
ualni stateIndex = 0;
for (auto state : *automata.getStates()) {
states.put(&state.data(), { stateIndex });
stateIndex++;
}
stateIndex = 0;
for (auto state : *automata.getStates()) {
if (&state.data() == automata.getStartState()) {
mStartState = stateIndex;
}
if (state->isAccepting()) {
ASSERT(state->getTransitions()->size() == 0)
for (auto symbolIndex : Range<ualni>(numSymbols)) {
mTable.set({ stateIndex, symbolIndex }, { Action::REDUCE, state->getStateVal().numArgs() });
}
} else {
for (auto transition : *state->getTransitions()) {
ualni symbolIndex = ualni(transition->getSymbol()) - mRange.mBegin;
ualni targetStateIndex = states.get(transition->getState());
mTable.set({ stateIndex, symbolIndex }, { Action::SHIFT, targetStateIndex });
}
}
stateIndex++;
}
}
private:
Buffer2D<Action> mTable;
Buffer<StackItem> mItems;
Buffer<StackItem*> mStack;
ualni mStartState = 0;
ualni mCurrentState = 0;
Range<ualni> mRange;
};
}

View file

@ -0,0 +1,181 @@
#pragma once
#include "Automata.hpp"
#include "Grammar.hpp"
namespace tp {
class ContextFreeCompiler {
public:
struct SymbolVal {
SymbolVal() = default;
SymbolVal(ualni aId, ualni aStart, ualni aLen) {
id = aId;
start = aStart;
len = aLen;
};
SymbolVal(ualni val) { id = val; }
operator ualni() const { return id; }
bool operator==(const SymbolVal& in) const { return in.id == id; }
SymbolVal& operator=(const SymbolVal& in) = default;
ualni id = 0;
ualni start = 0;
ualni len = 0;
};
struct Item {
const ContextFreeGrammar::Rule* mRule = nullptr;
ualni mAdvanceIdx = 0;
ualni numArgs() const { return 0; }
};
struct Symbol {
String mId;
bool mIsTerminal = false;
};
private:
struct NonTerminal {
Buffer<ContextFreeGrammar::Rule*> rules;
Map<String, NonTerminal*> references;
Map<String, NonTerminal*> referencing;
public:
[[nodiscard]] bool isProductive() const {
for (auto rule : rules) {
if (rule->isProductive()) return true;
}
return false;
}
[[nodiscard]] bool isLooped(Map<String, ualni>& processed, const String& id) const {
for (auto ref : referencing) {
if (processed.presents(ref->key)) return true;
}
processed.put(id, {});
for (auto ref : referencing) {
if (ref->val->isLooped(processed, ref->key)) return true;
}
return false;
}
};
public:
bool compile(const ContextFreeGrammar& grammar, FiniteStateAutomation<SymbolVal, Item>& automata) {
if (!init(grammar)) return false;
return true;
}
[[nodiscard]] const Buffer<Symbol>* getSymbols() const { return &mSymbols; }
[[nodiscard]] SymbolVal getSymbolId(const String& name) const { return mSymbolLookup.get(name); }
private:
bool init(const ContextFreeGrammar& grammar) {
if (!grammar.getRules()->size()) {
return false;
}
for (auto rule : *grammar.getRules()) {
if (!rule->getArgs()->size()) {
return false;
}
}
findNonTerminals(grammar);
for (auto nonTerminal : mNonTerminals) {
for (auto rule : nonTerminal->val.rules) {
for (auto arg : *rule->getArgs()) {
if (arg->isTerminal() || arg->isEpsilon()) continue;
if (!mNonTerminals.presents(arg->getId())) {
printf("Referenced non-terminal '%s' is not defined\n", arg->getId().read());
return false;
}
}
}
}
findAllReferences(grammar);
for (auto nonTerminal : mNonTerminals) {
if (!nonTerminal->val.references.size() && nonTerminal->key != grammar.getStartTerminal()) {
printf("Non-terminal '%s' is defined but not used\n", nonTerminal->key.read());
return false;
}
}
for (auto nonTerminal : mNonTerminals) {
if (!nonTerminal->val.isProductive()) {
printf("Non-terminal '%s' is not productive\n", nonTerminal->val.rules.first()->getId().read());
return false;
}
}
Map<String, ualni> processed;
if (mNonTerminals.get(grammar.getStartTerminal()).isLooped(processed, grammar.getStartTerminal())) {
printf("Note that grammar is looped.\n");
return false;
}
initSymbols(grammar);
return true;
}
void findNonTerminals(const ContextFreeGrammar& grammar) {
for (auto rule : *grammar.getRules()) {
if (!mNonTerminals.presents(rule->getId())) {
mNonTerminals.put(rule->getId(), {});
}
auto nonTerminal = &mNonTerminals.get(rule->getId());
nonTerminal->rules.append(&rule.data());
}
}
void findAllReferences(const ContextFreeGrammar& grammar) {
for (auto nonTerminal : mNonTerminals) {
for (auto rule : nonTerminal->val.rules) {
for (auto arg : *rule->getArgs()) {
if (arg->isTerminal() || arg->isEpsilon()) continue;
NonTerminal* reference = &mNonTerminals.get(arg->getId());
nonTerminal->val.referencing.put(arg->getId(), reference);
reference->references.put(nonTerminal->key, &nonTerminal->val);
}
}
}
}
void initSymbols(const ContextFreeGrammar& grammar) {
for (auto nonTerminal : mNonTerminals) {
mSymbols.append({ nonTerminal->key, false });
mSymbolLookup.put(nonTerminal->key, SymbolVal(mSymbols.size() - 1));
for (auto rule : nonTerminal->val.rules) {
for (auto arg : *rule->getArgs()) {
if (arg->isEpsilon() || arg->isTerminal()) continue;
if (mTerminals.presents(arg->getId())) continue;
mTerminals.put(arg->getId(), {});
mSymbols.append({ nonTerminal->key, true });
mSymbolLookup.put(nonTerminal->key, SymbolVal(mSymbols.size() - 1));
}
}
}
}
private:
Map<String, NonTerminal> mNonTerminals;
Map<String, bool> mTerminals;
Buffer<Symbol> mSymbols;
Map<String, SymbolVal> mSymbolLookup;
};
}

View file

@ -0,0 +1,224 @@
#pragma once
#include "Buffer.hpp"
#include "LanguageCommon.hpp"
#include "Map.hpp"
#include "Strings.hpp"
namespace tp {
class ContextFreeGrammar {
public:
struct Arg {
friend class Rule;
public:
Arg() = default;
explicit Arg(const String& id, bool terminal = true, bool epsilon = false);
public:
bool operator==(const Arg& in) const;
[[nodiscard]] const String& getId() const;
[[nodiscard]] bool isTerminal() const { return mIsTerminal; }
[[nodiscard]] bool isEpsilon() const { return mIsEpsilon; }
private:
String mId;
bool mIsTerminal = false;
bool mIsEpsilon = false;
};
class Rule {
public:
Rule() = default;
Rule(const String& id, const InitialierList<Arg>& args);
public:
bool operator==(const Rule& in) const;
[[nodiscard]] bool isProductive() const;
[[nodiscard]] const String& getId() const { return mId; }
[[nodiscard]] const Buffer<Arg>* getArgs() const { return &mArgs; }
private:
String mId;
Buffer<Arg> mArgs;
};
public:
ContextFreeGrammar() = default;
public:
void addRule(const Rule& rule);
void addRule(const String& id, const InitialierList<Arg>& args);
void setStart(const String& startRule);
[[nodiscard]] const Buffer<Rule>* getRules() const { return &mRules; }
[[nodiscard]] const String& getStartTerminal() const { return mStartTerminal; }
public:
Buffer<Rule> mRules;
String mStartTerminal;
bool mIsLooped = false;
};
template <typename tAlphabetType, typename tTokType>
class RegularGrammar {
public:
struct Node {
enum Type {
NONE,
ANY,
OR,
IF,
CLASS,
COMPOUND,
REPEAT,
VAL,
} mType = NONE;
explicit Node(Type type) :
mType(type) {}
virtual ~Node() = default;
};
class ValueNode : public Node {
public:
explicit ValueNode(tAlphabetType val) :
mVal(val),
Node(Node::VAL) {}
~ValueNode() override = default;
public:
tAlphabetType mVal;
};
class CompoundNode : public Node {
public:
CompoundNode() :
Node(Node::COMPOUND) {}
CompoundNode(const InitialierList<const Node*>& nodes) :
Node(Node::COMPOUND) {
mSequence = nodes;
}
~CompoundNode() override {
for (auto iter : mSequence) {
delete iter.data();
}
mSequence.clear();
}
public:
Buffer<const Node*> mSequence;
};
class AlternationNode : public Node {
public:
AlternationNode() :
Node(Node::OR) {}
AlternationNode(const Node* a, const Node* b) :
Node(Node::OR) {
mFirst = a;
mSecond = b;
}
~AlternationNode() override {
delete mFirst;
delete mSecond;
}
public:
const Node* mFirst = nullptr;
const Node* mSecond = nullptr;
};
class IfNode : public Node {
public:
IfNode() :
Node(Node::IF) {}
explicit IfNode(const Node* a) :
Node(Node::IF) {
mNode = a;
}
~IfNode() override { delete mNode; }
public:
const Node* mNode = nullptr;
};
class AnyNode : public Node {
public:
AnyNode() :
Node(Node::ANY) {}
~AnyNode() override = default;
};
class RepetitionNode : public Node {
public:
RepetitionNode() :
Node(Node::REPEAT) {}
explicit RepetitionNode(const Node* rep, bool plus = false) :
Node(Node::REPEAT) {
mNode = rep;
mPlus = plus;
}
~RepetitionNode() override { delete mNode; }
public:
Node* mNode = nullptr;
bool mPlus = false;
};
class ClassNode : public Node {
public:
ClassNode() :
Node(Node::CLASS) {}
explicit ClassNode(const Buffer<Range<tAlphabetType>>& ranges, bool exclude = false) :
Node(Node::CLASS) {
mExclude = exclude;
mRanges = ranges;
}
~ClassNode() override { mRanges.removeAll(); }
public:
Buffer<Range<tAlphabetType>> mRanges;
bool mExclude = false;
};
public:
RegularGrammar() = default;
~RegularGrammar() {
for (auto rule : mRules) {
delete rule->t1;
}
}
void addRule(const Node* node, tTokType id) { mRules.append({ node, id }); }
public:
const Node* seq(const InitialierList<const Node*>& nodes) { return new CompoundNode(nodes); }
const Node* val(tAlphabetType in) { return new ValueNode(in); }
const Node* alt(const Node* a, const Node* b) { return new AlternationNode(a, b); }
const Node* may(const Node* a) { return new IfNode(a); }
const Node* any() { return new AnyNode(); }
const Node* rep(const Node* rep, bool plus = false) { return new RepetitionNode(rep, plus); }
const Node* ranges(const Buffer<Range<tAlphabetType>>& ranges, bool exclude = false) {
return new ClassNode(ranges, exclude);
}
public:
Buffer<Pair<const Node*, tTokType>> mRules;
};
}

View file

@ -0,0 +1,7 @@
#pragma once
#include "Module.hpp"
namespace tp {
extern ModuleManifest gModuleLanguage;
}

View file

@ -0,0 +1,107 @@
#pragma once
#include "RegularCompiler.hpp"
#include "RegularAutomata.hpp"
#include "ContextFreeCompiler.hpp"
#include "ContextFreeAutomata.hpp"
namespace tp {
template <typename tAlphabetType, typename tTokenType, tTokenType tInTransition, ualni MinSymbol, ualni MaxSymbol>
class Parser {
typedef RegularGrammar<tAlphabetType, tTokenType> RegularGrammar;
typedef RegularCompiler<tAlphabetType, tTokenType, tInTransition, MinSymbol, MaxSymbol> RegularCompiler;
typedef FiniteStateAutomation<tAlphabetType, tTokenType> RegularGraph;
typedef RegularAutomata<tAlphabetType, tTokenType> RegularAutomata;
// ContextFreeGrammar;
// ContextFreeCompiler;
typedef FiniteStateAutomation<ContextFreeCompiler::SymbolVal, ContextFreeCompiler::Item> ContextFreeGraph;
typedef ContextFreeAutomata<ContextFreeCompiler::SymbolVal, ContextFreeCompiler::Item> ContextFreeAutomata;
public:
struct ParseResult {
bool accepted = false;
const ContextFreeAutomata::StackItem* ast = nullptr;
};
public:
Parser() = default;
public:
bool compileTables(
const ContextFreeGrammar& cfGrammar,
const RegularGrammar& reGrammar,
const Map<String, tTokenType>& contextFreeToRegular
) {
// Compile Regular Grammar
{
RegularGraph graph;
RegularCompiler compiler;
compiler.compile(graph, reGrammar);
graph.makeDeterministic();
mRegularAutomata.construct(graph);
}
// compile context free grammar
{
ContextFreeGraph graph;
ContextFreeCompiler compiler;
compiler.compile(cfGrammar, graph);
graph.makeDeterministic();
mContextFreeAutomata.construct(graph);
// make glue
for (auto symbol : *compiler.getSymbols()) {
auto symbolId = compiler.getSymbolId(symbol->mId);
if (symbol->mIsTerminal) {
auto iter = contextFreeToRegular.presents(symbol->mId);
if (!iter) return false;
mGrammarGlue.put(contextFreeToRegular.getSlotVal(iter), symbolId);
} else {
mAstNames.put(symbolId, symbol->mId);
}
}
}
return true;
}
ParseResult parse(const tAlphabetType* sentence, ualni sentenceLength) {
// get tokens stream
Buffer<ContextFreeCompiler::SymbolVal> tokens;
const tAlphabetType* sentenceIter = sentence;
ualni lengthIter = sentenceLength;
while (lengthIter) {
auto result = mRegularAutomata.accept(sentenceIter, lengthIter);
if (!result.accepted) {
return { false, nullptr };
}
tokens.append(ContextFreeCompiler::SymbolVal(
mGrammarGlue.get(result.state), ualni(sentenceIter - sentence), result.advancedIdx
));
sentenceIter += result.advancedIdx;
lengthIter -= result.advancedIdx;
}
ContextFreeAutomata::AcceptResult result = mContextFreeAutomata.accept(tokens.getBuff(), tokens.size());
return { result.accepted, result.ast };
}
public:
// save load compiled tables
RegularAutomata mRegularAutomata;
ContextFreeAutomata mContextFreeAutomata;
Map<tTokenType, ContextFreeCompiler::SymbolVal> mGrammarGlue;
Map<ContextFreeCompiler::SymbolVal, String> mAstNames;
};
}

View file

@ -0,0 +1,101 @@
#pragma once
#include "Strings.hpp"
#include "Automata.hpp"
#include "Buffer2D.hpp"
namespace tp {
template <typename tAlphabetType, typename tStateType>
class RegularAutomata {
public:
struct AcceptResult {
bool accepted = false;
ualni advancedIdx = 0;
tStateType state = tStateType();
};
public:
RegularAutomata() = default;
AcceptResult accept(const tAlphabetType* stream, ualni size) {
mCurrentState = mStartState;
ualni advancedIdx = 0;
while (advancedIdx < size) {
const tAlphabetType& symbol = *(stream + advancedIdx);
if (!(symbol >= mSymbolRange.mBegin && symbol < mSymbolRange.mEnd)) {
return { false, advancedIdx, {} };
}
mCurrentState = mTable.get({ (ualni) (symbol - mSymbolRange.mBegin), mCurrentState });
if (mCurrentState == mStates.size()) {
return { false, advancedIdx, {} };
}
if (mStates[mCurrentState].first) {
return { true, advancedIdx, mStates[mCurrentState].second };
}
advancedIdx++;
}
return { false, advancedIdx, {} };
}
public:
void construct(const FiniteStateAutomation<tAlphabetType, tStateType>& automata) {
const auto range = automata.getAlphabetRange();
mSymbolRange = { tAlphabetType(range.mBegin), tAlphabetType(range.mEnd) };
auto range_len = ualni(mSymbolRange.mEnd - mSymbolRange.mBegin);
auto sizeX = range_len ? range_len : 1;
auto sizeY = (ualni) (automata.numStates());
mTable.reserve({ sizeX, sizeY });
mTable.assign(automata.numStates());
mStates.reserve(sizeY);
ualni idx = 0;
for (auto state : *automata.getStates()) {
mStates[idx] = { state->isAccepting(), state->getStateVal() };
idx++;
}
idx = 0;
for (auto state : *automata.getStates()) {
if (&state.data() == automata.getStartState()) {
mStartState = mCurrentState = idx;
}
idx++;
}
ualni stateIdx = 0;
for (auto state : *automata.getStates()) {
for (auto transition : *state->getTransitions()) {
ualni stateIdx2 = 0;
for (auto state2 : *automata.getStates()) {
if (transition->getState() == &state2.data()) break;
stateIdx2++;
}
auto const code = transition->getSymbol();
mTable.set({ (ualni) (code - mSymbolRange.mBegin), (ualni) stateIdx }, stateIdx2);
}
stateIdx++;
}
}
private:
Buffer2D<ualni> mTable;
Buffer<Pair<bool, tStateType>> mStates;
ualni mCurrentState = 0;
ualni mStartState = 0;
Range<tAlphabetType> mSymbolRange = { 0, 0 };
};
}

View file

@ -0,0 +1,208 @@
#pragma once
#include "Grammar.hpp"
#include "Automata.hpp"
namespace tp {
template <typename tAlphabetType, typename tStateType, tStateType tInTransition, ualni tMinSymbol, ualni tMaxSymbol>
class RegularCompiler {
typedef FiniteStateAutomation<tAlphabetType, tStateType> Graph;
typedef typename Graph::State Vertex;
typedef RegularGrammar<tAlphabetType, tStateType> Grammar;
struct Node {
Vertex* left = nullptr;
Vertex* right = nullptr;
};
private:
Graph* mGraph = nullptr;
public:
struct CompileError {
uhalni mRuleIndex = 0;
tStateType mRuleState;
const char* description = nullptr;
[[nodiscard]] bool isError() const { return description; }
};
CompileError mError;
void compile(Graph& graph, const tAlphabetType* regex, tStateType state) {
mGraph = &graph;
compileUtil(regex, state);
}
void compile(Graph& aGraph, const Grammar& grammar) {
mGraph = &aGraph;
auto left = addVertex();
auto right = addVertex();
halni idx = 0;
for (auto rule : grammar.mRules) {
auto node = compileUtil(rule.data().first, rule.data().second);
if (!(node.left && node.right)) {
mError.mRuleIndex = idx;
return;
}
transitionAny(left, node.left);
transitionAny(node.right, right);
idx++;
}
mGraph->setStartState(left);
}
private:
Node compileUtil(const Grammar::Node* astNode, tStateType state) {
auto node = compileNode(astNode, nullptr, nullptr);
node.right->setValue(state);
node.right->setAcceptance(true);
mGraph->setStartState(node.left);
return node;
}
Node compileVal(Grammar::ValueNode* val, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
auto left = aLeft ? aLeft : addVertex();
auto right = aRight ? aRight : addVertex();
transitionVal(left, right, val->mVal);
return { left, right };
}
Node compileAlternation(const Grammar::AlternationNode* alt, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
auto first_node = compileNode(alt->mFirst, aLeft, aRight);
auto second_node = compileNode(alt->mSecond);
transitionAny(first_node.left, second_node.left);
transitionAny(second_node.right, first_node.right);
return first_node;
}
Node compileAny(const Grammar::AnyNode*, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
auto left = aLeft ? aLeft : addVertex();
auto right = aRight ? aRight : addVertex();
transitionAny(left, right, true);
return { left, right };
}
Node compileRepeat(const Grammar::RepetitionNode* repeat, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
if (repeat->mPlus) {
auto middle = addVertex();
auto left_node = compileNode(repeat->mNode, aLeft, middle);
auto right_node = compileNode(repeat->mNode, middle, aRight);
transitionAny(right_node.right, right_node.left);
transitionAny(right_node.left, right_node.right);
return { left_node.left, right_node.right };
} else {
auto node = compileNode(repeat->mNode, aLeft, aRight);
transitionAny(node.right, node.left);
transitionAny(node.left, node.right);
return node;
}
}
Node compileIf(const Grammar::IfNode* ifNode, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
auto node = compileNode(ifNode->mNode, aLeft, aRight);
transitionAny(node.left, node.right);
return node;
}
Node compileClass(const Grammar::ClassNode* node, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
auto left = aLeft ? aLeft : addVertex();
auto right = aRight ? aRight : addVertex();
if (node->mRanges.size() == 1) {
auto const& range = node->mRanges.first();
transitionRange(left, right, { ualni(range.mBegin), ualni(range.mEnd) }, node->mExclude);
return { left, right };
}
for (auto range : node->mRanges) {
auto middle = addVertex();
transitionRange(left, middle, { ualni(range->mBegin), ualni(range->mEnd) }, node->mExclude);
transitionAny(middle, right);
}
return { left, right };
}
Node compileCompound(const Grammar::CompoundNode* compound, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
Vertex* left = nullptr;
Vertex* rigth = nullptr;
ualni idx = 0;
for (auto child : compound->mSequence) {
auto pass_left = idx == 0 ? aLeft : rigth;
auto pass_right = idx == compound->mSequence.size() - 1 ? aRight : nullptr;
auto node = compileNode(child.data(), pass_left, pass_right);
if (!left) left = node.left;
rigth = node.right;
idx++;
}
return { left, rigth };
}
Node compileNode(const Grammar::Node* node, Vertex* aLeft = nullptr, Vertex* aRight = nullptr) {
switch (node->mType) {
case Grammar::Node::CLASS: return compileClass((typename Grammar::ClassNode*) node, aLeft, aRight);
case Grammar::Node::COMPOUND: return compileCompound((typename Grammar::CompoundNode*) node, aLeft, aRight);
case Grammar::Node::IF: return compileIf((typename Grammar::IfNode*) node, aLeft, aRight);
case Grammar::Node::REPEAT: return compileRepeat((typename Grammar::RepetitionNode*) node, aLeft, aRight);
case Grammar::Node::ANY: return compileAny((typename Grammar::AnyNode*) node, aLeft, aRight);
case Grammar::Node::OR: return compileAlternation((typename Grammar::AlternationNode*) node, aLeft, aRight);
case Grammar::Node::VAL: return compileVal((typename Grammar::ValueNode*) node, aLeft, aRight);
case Grammar::Node::NONE: break;
}
ASSERT(0)
return {};
}
void transitionAny(Vertex* from, Vertex* to, bool consumes = false) {
for (auto symbol : Range<ualni>(tMinSymbol, tMaxSymbol)) {
transitionVal(from, to, symbol);
}
}
void transitionVal(Vertex* from, Vertex* to, tAlphabetType val) { mGraph->addTransition(from, to, val); }
void transitionRange(Vertex* from, Vertex* to, Range<ualni> range, bool exclude) {
if (exclude) {
Range<ualni> first = { tMinSymbol, range.mBegin - 1 };
Range<ualni> second = { range.mEnd + 1, tMaxSymbol };
if (first.valid()) {
for (auto symbol : first) {
transitionVal(from, to, symbol);
}
}
if (second.valid()) {
for (auto symbol : second) {
transitionVal(from, to, symbol);
}
}
} else {
for (auto symbol : range) {
transitionVal(from, to, symbol);
}
}
}
Vertex* addVertex() { return mGraph->addState(tInTransition, false); }
};
}

View file

@ -0,0 +1,69 @@
#pragma once
#include "Parser.hpp"
namespace tp {
// Gives ability to express grammar in the Unified Format as sentence
template <typename tAlphabetType>
class SimpleParser {
enum UGTokens : alni { InTransition = -1, TestSeq };
typedef Parser<tAlphabetType, UGTokens, InTransition, 0, 127> UGParser;
typedef Parser<tAlphabetType, alni, -1, 0, 127> UserParser;
public:
SimpleParser() {
// Grammar for unified grammar format sentence that tables compiled from
// Define Context-Free grammar
ContextFreeGrammar contextFreeGrammar;
{
// use existing CF grammar interface
contextFreeGrammar.addRule("a", { ContextFreeGrammar::Arg("") });
contextFreeGrammar.setStart("a");
}
// Define Regular grammar
RegularGrammar<tAlphabetType, UGTokens> regularGrammar;
{
// this is basically ast from existing tokenizer
regularGrammar.addRule(regularGrammar.seq({ regularGrammar.val('a'), regularGrammar.val('b') }), TestSeq);
}
Map<String, UGTokens> terminalsMap;
terminalsMap.put("TestSeq", TestSeq);
mUnifiedGrammarParser.compileTables(contextFreeGrammar, regularGrammar, terminalsMap);
}
public:
void compileTables(const tAlphabetType* grammar, ualni grammarLength) {
mUnifiedGrammarParser.parse(grammar, grammarLength);
// compile each ast into RegularGrammar and ContextFree Grammar api instructions
ContextFreeGrammar userContextFreeGrammar;
RegularGrammar<tAlphabetType, alni> userRegularGrammar;
// ...
// split ast into RE and CF part
// generate and execute grammar api commands
// use existing tokenizer code to create RE transition matrix
// ...
// compile tables from user grammar
Map<String, alni> terminalsMap;
terminalsMap.put("TestSeq", 0);
mUserParser.compileTables(userContextFreeGrammar, userRegularGrammar, terminalsMap);
}
UserParser::ParseResult parse(const tAlphabetType* grammar, ualni grammarLength) {
return mUserParser.parse(grammar, grammarLength);
}
private:
UGParser mUnifiedGrammarParser;
UserParser mUserParser;
};
}

View file

@ -0,0 +1,43 @@
#pragma once
// #include "SimpleParser.hpp"
const char* gGrammar = R"(
# Grammar in the CF-RE United Format (Defined by language module)
Rules : {
ScopeList : ScopeList Scope | Scope ;
Scope : \ScopeBegin StatementList \ScopeEnd;
StatementList : StatementList Statement \StatementEnd;
StatementList : Statement \StatementEnd;
Statement : \StatementBody;
}
Terminals : {
Space : " " | "\t" | "\n" | "\r";
ScopeBegin : "{";
ScopeEnd : "}";
StatementEnd : ";";
StatementBody : "a" | "b";
}
Start : Scope;
Ignore : Space;
)";
const char* gSentence = R"(
{}
{ }
{
a;
a ; a ;
}
{
a;
a;
}
)";

View file

@ -0,0 +1,45 @@
#include "Test.hpp"
/*
using namespace tp;
void testAutomation() {
FiniteStateAutomation<char, int> automata;
auto start = automata.addState(0, false);
auto end = automata.addState(1, true);
automata.addTransition(start, end, 'a');
automata.setStartState(start);
automata.makeDeterministic();
}
void test() {
auto parser = SimpleParser<int1>();
parser.compileTables(gGrammar, String::Logic::calcLength(gGrammar));
auto result = parser.parse(gSentence, String::Logic::calcLength(gSentence));
}
int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleLanguage, nullptr };
tp::ModuleManifest testModule("Test", nullptr, nullptr, deps);
if (!testModule.initialize()) {
return 1;
}
testAutomation();
test();
testModule.deinitialize();
}
*/
int main() { return 0; }

24
3DEditor/CMakeLists.txt Normal file
View file

@ -0,0 +1,24 @@
project(3DEditor)
### ---------------------- Externals --------------------- ###
set(BINDINGS_INCLUDE ../Externals/glfw/include ../Externals)
set(BINDINGS_LIBS glfw Imgui)
### ---------------------- Static Library --------------------- ###
file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp")
file(GLOB HEADERS "./public/*.hpp" "./public/*/*.hpp")
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
target_include_directories(${PROJECT_NAME} PUBLIC ./public/ ${BINDINGS_INCLUDE} ./ext/)
target_link_libraries(${PROJECT_NAME} PUBLIC Widgets RasterRender RayTracer)
target_link_libraries(${PROJECT_NAME} PRIVATE ${BINDINGS_LIBS})
target_link_libraries(${PROJECT_NAME} PRIVATE OpenImageDenoise)
### -------------------------- Applications -------------------------- ###
file(GLOB APP_SOURCES "./applications/*.cpp")
add_executable(3DEditorApp ${APP_SOURCES})
target_link_libraries(3DEditorApp ${PROJECT_NAME})
file(COPY "rsc" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/")
file(COPY "rsc/Font.ttf" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/")

View file

@ -0,0 +1,42 @@
#include "EditorWidget.hpp"
#include "GraphicApplication.hpp"
using namespace tp;
class EditorGUI : public Application {
public:
EditorGUI() {
auto canvas = this->mGraphics->getCanvas();
mGui = new EditorWidget(canvas, &mEditor);
mEditor.loadDefaults();
// mScene.mCamera.lookAtPoint({ 0, 0, 0 }, { 3, 3, 2 }, { 0, 0, 1 });
}
~EditorGUI() override { delete mGui; }
void processFrame(EventHandler* eventHandler) override {
auto rec = RectF({ 0, 0 }, mWindow->getSize());
mGui->setArea(rec);
mGui->setVisible(true);
mGui->updateConfigWrapper(mWidgetManager);
mGui->procWrapper(*eventHandler, rec);
}
void drawFrame(Canvas* canvas) override { mGui->drawWrapper(*canvas); }
private:
Editor mEditor;
WidgetManager mWidgetManager;
EditorWidget* mGui;
};
int main() {
EditorGUI gui;
gui.run();
}

View file

@ -0,0 +1,40 @@
#include "Editor.hpp"
#include "OpenImageDenoise/oidn.hpp"
#include <iostream>
using namespace tp;
void Editor::denoise() {
auto& out = mPathTracerBuffers;
// Initialize OIDN device
oidn::DeviceRef device = oidn::newDevice(oidn::DeviceType::CPU);
device.commit();
// Define buffer size
const int channels = 4; // ARGB
const auto size = out.color.size();
// Create the denoising filter
oidn::FilterRef filter = device.newFilter("RT"); // Use the 'RT' filter for path tracing
// Set the input and output buffer (same buffer for in-place denoising)
filter.setImage("color", out.color.getBuff(), oidn::Format::Float3, size.x, size.y, 0, sizeof(float) * channels); // ARGB
filter.setImage("output", out.color.getBuff(), oidn::Format::Float3, size.x, size.y, 0, sizeof(float) * channels); // ARGB
// Set additional parameters if needed
filter.set("hdr", false); // Assuming the input image is not HDR
// Commit the filter
filter.commit();
// Execute the filter
filter.execute();
// Check for errors
const char* errorMessage;
if (device.getError(errorMessage) != oidn::Error::None) {
std::cerr << "Error: " << errorMessage << std::endl;
}
}

118
3DEditor/private/Editor.cpp Normal file
View file

@ -0,0 +1,118 @@
#include "Editor.hpp"
#include "GraphicsApi.hpp"
using namespace tp;
Editor::Editor() {
{ // create path tracer gpu texture
glGenTextures(1, &mPathRenderTexture);
glBindTexture(GL_TEXTURE_2D, mPathRenderTexture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_REPEAT);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA32F, 100, 100, 0, GL_RGBA, GL_FLOAT, nullptr);
glBindTexture(GL_TEXTURE_2D, 0);
}
}
void Editor::renderViewport() {
switch (mRenderType) {
case RenderType::RASTER:
mRasterRenderer.render(mScene, mScene.mRenderSettings.size);
break;
case RenderType::PATH_TRACER:
{
// TODO : include in render viewport method
// renderPathFrame();
break;
}
default:
break;
}
}
uint4 Editor::getViewportTexID() {
switch (mRenderType) {
case RenderType::PATH_TRACER:
return mPathRenderTexture;
case RenderType::RASTER:
return mRasterRenderer.getRenderBufferID();
default:
return 0;
}
}
void Editor::loadDefaults() {
mScene.load("rsc/scene/script.lua");
}
void Editor::setViewportSize(const Vec2F& size) {
// TODO remove
// mScene.mCamera.rotate(0.01f, 0.0);
mScene.mRenderSettings.size = size;
mRasterRenderer.getRenderBuffer()->resize(size);
mScene.mCamera.setRatio(size.y / size.x);
}
Editor::~Editor() {
glDeleteTextures(1, &mPathRenderTexture);
}
void Editor::renderPathFrame() {
mPathRenderer.render(mScene, mPathTracerBuffers, mScene.mRenderSettings);
sendBuffersToGPU();
}
void Editor::sendBuffersToGPU() {
glBindTexture(GL_TEXTURE_2D, mPathRenderTexture);
const auto size = mPathTracerBuffers.color.size();
glTexImage2D(
GL_TEXTURE_2D,
0,
GL_RGBA32F,
(GLsizei) size.x,
(GLsizei) size.y,
0,
GL_RGBA,
GL_FLOAT,
mPathTracerBuffers.color.getBuff()
);
glBindTexture(GL_TEXTURE_2D, 0);
}
void Editor::denoisePathRenderBuffers() {
denoise();
sendBuffersToGPU();
}
void Editor::setRenderType(Editor::RenderType type) {
mRenderType = type;
}
void Editor::navigationOrbit(const Vec2F& delta) {
mScene.mCamera.rotate(delta.x, delta.y);
}
void Editor::navigationPan(const Vec2F& pos, const Vec2F& prevPos) {
mScene.mCamera.move(pos, prevPos);
}
void Editor::navigationZoom(halnf factor) {
mScene.mCamera.zoom(factor);
}
void Editor::navigationReset() {
mScene.mCamera.lookAtPoint({ 0, 0, 0 }, { 1, 5, 1 }, { 0, 0, 1 });
}

View file

@ -0,0 +1,47 @@
#pragma once
#include "RayTracer.hpp"
#include "RasterRender.hpp"
namespace tp {
class Editor {
public:
enum class RenderType { RASTER, PATH_TRACER };
public:
Editor();
~Editor();
void loadDefaults();
uint4 getViewportTexID();
void setViewportSize(const Vec2F& size);
void renderViewport();
void renderPathFrame();
void setRenderType(RenderType type);
void denoisePathRenderBuffers();
void navigationOrbit(const Vec2F& delta);
void navigationPan(const Vec2F& pos, const Vec2F& prevPos);
void navigationZoom(halnf factor);
void navigationReset();
private:
void sendBuffersToGPU();
void denoise();
private:
Scene mScene;
RenderType mRenderType = RenderType::RASTER;
RasterRender mRasterRenderer;
RayTracer mPathRenderer;
RayTracer::OutputBuffers mPathTracerBuffers;
uint4 mPathRenderTexture = 0;
};
}

View file

@ -0,0 +1,140 @@
#include "Widgets.hpp"
#include "Editor.hpp"
namespace tp {
class ViewportWidget : public Widget {
public:
explicit ViewportWidget(Canvas* canvas, Editor* editor) {
mEditor = editor;
mImage = canvas->createImageFromTextId(mEditor->getViewportTexID(), { 0, 0 });
mCanvas = canvas;
}
~ViewportWidget() { mCanvas->deleteImageHandle(mImage); }
void eventProcess(const Events& events) override { mEditor->setViewportSize(this->mArea.size); }
void eventDraw(Canvas& canvas) override {
mEditor->renderViewport();
canvas.updateTextureID(mImage, mEditor->getViewportTexID());
canvas.drawImage(this->mArea, &mImage, PI);
}
public:
Editor* mEditor;
Canvas* mCanvas = nullptr;
Canvas::ImageHandle mImage;
};
class EditorWidget : public WorkspaceWidget {
public:
EditorWidget(Canvas* canvas, Editor* editor) :
mViewport(canvas, editor) {
mEditor = editor;
mDockSpace.addSideWidget(&mNavigationMenu, DockSpaceWidget::RIGHT);
mDockSpace.addSideWidget(&mRenderMenu, DockSpaceWidget::LEFT);
mDockSpace.setCenterWidget(&mViewport);
// Render
{
mRenderPathTracer.setLabel("Render with Path Tracer");
mRenderRaster.setLabel("Render with Raster");
mRenderDeNoise.setLabel("Denoise (IntelOpenImage)");
mRenderMenu.addWidgetToMenu(&mRenderPathTracer);
mRenderMenu.addWidgetToMenu(&mRenderRaster);
mRenderMenu.addWidgetToMenu(&mRenderDeNoise);
mRenderMenu.setLabel("Render");
}
// Navigation
{
mNavigationPan.setLabel("Pan");
mNavigationOrbit.setLabel("Orbit");
mNavigationZoom.setLabel("Zoom");
mNavigationReset.setLabel("Reset");
mNavigationMenu.addWidgetToMenu(&mNavigationPan);
mNavigationMenu.addWidgetToMenu(&mNavigationOrbit);
mNavigationMenu.addWidgetToMenu(&mNavigationZoom);
mNavigationMenu.addWidgetToMenu(&mNavigationReset);
mNavigationMenu.setLabel("Navigation");
}
mRenderPathTracer.mCallback = [this]() {
mEditor->renderPathFrame();
mEditor->setRenderType(Editor::RenderType::PATH_TRACER);
};
mRenderRaster.mCallback = [this]() { mEditor->setRenderType(Editor::RenderType::RASTER); };
mRenderDeNoise.mCallback = [this]() { mEditor->denoisePathRenderBuffers(); };
mNavigationOrbit.mCallback = [this]() { mNavigationType = ORBIT; };
mNavigationPan.mCallback = [this]() { mNavigationType = PAN; };
mNavigationZoom.mCallback = [this](){ mNavigationType = ZOOM; };
mNavigationReset.mCallback = [this]() { mEditor->navigationReset(); };
}
void eventProcess(const Events& events) override {
// navigation
{
const auto& activeArea = mViewport.mArea;
if (this->isHolding() && activeArea.isInside(events.getPointer())) {
switch (mNavigationType) {
case ORBIT: mEditor->navigationOrbit(events.getPointerDelta() / activeArea.size * 3); break;
case PAN:
{
auto pointer = (((events.getPointer() - activeArea.pos) / activeArea.size) - 0.5f) * 2;
auto prevPointer = (((events.getPointerPrev() - activeArea.pos) / activeArea.size) - 0.5f) * 2;
mEditor->navigationPan(prevPointer, pointer);
}
break;
case ZOOM: mEditor->navigationZoom(1 + (events.getPointerDelta().y / activeArea.size.y)); break;
}
}
}
WorkspaceWidget::eventProcess(events);
}
void eventDraw(Canvas& canvas) override { canvas.rect(this->mArea, mBaseColor); }
void eventUpdateConfiguration(WidgetManager& wm) override {
wm.setActiveId("3DEditor");
mBaseColor = wm.getColor("Base", "Base");
}
public:
Editor* mEditor = nullptr;
// SplitView mSplitView;
ViewportWidget mViewport;
// ScrollableWindow mSettingsWidget;
// Controls
FloatingWidget mRenderMenu;
ButtonWidget mRenderPathTracer;
ButtonWidget mRenderRaster;
ButtonWidget mRenderDeNoise;
// Navigation
enum NavigationType { ORBIT, PAN, ZOOM } mNavigationType = ORBIT;
FloatingWidget mNavigationMenu;
ButtonWidget mNavigationPan;
ButtonWidget mNavigationOrbit;
ButtonWidget mNavigationZoom;
ButtonWidget mNavigationReset;
RGBA mBaseColor;
};
}

BIN
3DEditor/rsc/Font.ttf Normal file

Binary file not shown.

View file

@ -0,0 +1,20 @@
# Blender MTL File: 'scene.blend'
# Material Count: 2
newmtl Material
Ns 323.999994
Ka 1.000000 1.000000 1.000000
Kd 0.800000 0.800000 0.800000
Ks 0.500000 0.500000 0.500000
Ke 0.000000 0.000000 0.000000
Ni 1.450000
d 1.000000
illum 2
newmtl None
Ns 500
Ka 0.8 0.8 0.8
Kd 0.8 0.8 0.8
Ks 0.8 0.8 0.8
d 1
illum 2

View file

@ -0,0 +1,112 @@
# Blender v3.0.1 OBJ File: 'scene.blend'
# www.blender.org
mtllib meshes.mtl
o Cube
v -1.039076 1.039076 1.792917
v -1.039076 1.039076 -1.285234
v 1.039076 1.039076 1.792917
v 1.039076 1.039076 -1.285234
v -1.039076 -1.039076 1.792917
v -1.039076 -1.039076 -1.285234
v 1.039076 -1.039076 1.792917
v 1.039076 -1.039076 -1.285234
vt 0.625000 0.500000
vt 0.625000 0.750000
vt 0.875000 0.750000
vt 0.875000 0.500000
vt 0.375000 0.750000
vt 0.375000 1.000000
vt 0.625000 1.000000
vt 0.375000 0.000000
vt 0.375000 0.250000
vt 0.625000 0.250000
vt 0.625000 0.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.375000 0.500000
vn 0.0000 0.0000 -1.0000
vn -1.0000 0.0000 0.0000
vn 0.0000 1.0000 0.0000
vn 0.0000 0.0000 1.0000
vn 1.0000 0.0000 0.0000
usemtl Material
s off
f 1/1/1 3/2/1 7/3/1 5/4/1
f 4/5/2 8/6/2 7/7/2 3/2/2
f 8/8/3 6/9/3 5/10/3 7/11/3
f 6/12/4 8/13/4 4/5/4 2/14/4
f 6/9/5 2/14/5 1/1/5 5/10/5
o Cube.001
v 0.411013 -0.208216 -1.264212
v 0.411013 -0.208216 -0.612621
v -0.208216 -0.411013 -1.264212
v -0.208216 -0.411013 -0.612621
v 0.208216 0.411013 -1.264212
v 0.208216 0.411013 -0.612621
v -0.411013 0.208216 -1.264212
v -0.411013 0.208216 -0.612621
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
vn 0.3112 -0.9503 0.0000
vn -0.9503 -0.3112 0.0000
vn -0.3112 0.9503 0.0000
vn 0.9503 0.3112 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 0.0000 1.0000
usemtl None
s off
f 9/15/6 10/16/6 12/17/6 11/18/6
f 11/18/7 12/17/7 16/19/7 15/20/7
f 15/20/8 16/19/8 14/21/8 13/22/8
f 13/22/9 14/21/9 10/23/9 9/24/9
f 11/25/10 15/20/10 13/22/10 9/26/10
f 16/19/11 12/27/11 10/28/11 14/21/11
o Cube.002
v -0.351718 -0.467100 -0.602050
v -0.351718 -0.467100 0.049542
v -0.800825 0.004996 -0.602050
v -0.800825 0.004996 0.049542
v 0.120377 -0.017993 -0.602050
v 0.120377 -0.017993 0.049542
v -0.328730 0.454103 -0.602050
v -0.328730 0.454103 0.049542
vt 0.375000 0.000000
vt 0.625000 0.000000
vt 0.625000 0.250000
vt 0.375000 0.250000
vt 0.625000 0.500000
vt 0.375000 0.500000
vt 0.625000 0.750000
vt 0.375000 0.750000
vt 0.625000 1.000000
vt 0.375000 1.000000
vt 0.125000 0.500000
vt 0.125000 0.750000
vt 0.875000 0.500000
vt 0.875000 0.750000
vn -0.7245 -0.6892 0.0000
vn -0.6892 0.7245 0.0000
vn 0.7245 0.6892 0.0000
vn 0.6892 -0.7245 0.0000
vn 0.0000 0.0000 -1.0000
vn 0.0000 0.0000 1.0000
usemtl None
s off
f 17/29/12 18/30/12 20/31/12 19/32/12
f 19/32/13 20/31/13 24/33/13 23/34/13
f 23/34/14 24/33/14 22/35/14 21/36/14
f 21/36/15 22/35/15 18/37/15 17/38/15
f 19/39/16 23/34/16 21/36/16 17/40/16
f 24/33/17 20/41/17 18/42/17 22/35/17

View file

@ -0,0 +1,25 @@
Meshes = "meshes.obj"
Camera = {
pos = { 0.5, 4.5, 0.2 },
size_x = 600,
size_y = 800,
}
Lights = {
{
pos = { -0.5, 3.5, 1 },
intensity = 1
},
{
pos = { 0, 0, 1 },
intensity = 0.5
},
}
RenderSettings = {
depth = 1,
spray = 1,
multisampling = 1,
}

View file

@ -0,0 +1,7 @@
#version 330 core
out vec4 FragColor;
void main() {
FragColor = vec4(gl_FragCoord.z, gl_FragCoord.z, gl_FragCoord.z, 1.f);
}

View file

@ -0,0 +1,11 @@
#version 330 core
layout(location = 0) in vec3 Point;
uniform vec4 Origin;
uniform mat4 Basis;
uniform mat4 Camera;
void main() {
gl_Position = Camera * vec4(Point.xyz, 1.0);
}

13
3DScene/CMakeLists.txt Normal file
View file

@ -0,0 +1,13 @@
project(3DScene)
### ---------------------- Static Library --------------------- ###
file(GLOB SOURCES "./private/*.cpp")
file(GLOB HEADERS "./public/*.hpp")
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
target_include_directories(${PROJECT_NAME} PRIVATE ../Externals/)
target_link_libraries(${PROJECT_NAME} PUBLIC Math)
target_link_libraries(${PROJECT_NAME} PRIVATE Lua)

View file

@ -0,0 +1,220 @@
#include "Scene.hpp"
extern "C" {
#include "lauxlib.h"
#include "lualib.h"
}
#include <filesystem>
// Function to read a Lua table representing RenderSettings
int readRenderSettings(lua_State* L, tp::RenderSettings& settings) {
lua_getglobal(L, "RenderSettings");
if (!lua_istable(L, -1)) {
printf("RenderSettings is not a table.\n");
return 0; // Error
}
// Read depth field
lua_getfield(L, -1, "depth");
if (lua_isnumber(L, -1)) {
settings.depth = (int) lua_tonumber(L, -1);
} else {
printf("RenderSettings 'depth' field is missing or not a number.\n");
lua_pop(L, 1); // Pop the 'depth' field
return 0; // Error
}
lua_pop(L, 1); // Pop the 'depth' field
// Read spray field
lua_getfield(L, -1, "spray");
if (lua_isnumber(L, -1)) {
settings.spray = (int) lua_tonumber(L, -1);
} else {
printf("RenderSettings 'spray' field is missing or not a number.\n");
lua_pop(L, 1); // Pop the 'spray' field
return 0; // Error
}
lua_pop(L, 1); // Pop the 'spray' field
// Read depth field
lua_getfield(L, -1, "multisampling");
if (lua_isnumber(L, -1)) {
settings.multisampling = (int) lua_tonumber(L, -1);
} else {
printf("RenderSettings 'depth' field is missing or not a number.\n");
lua_pop(L, 1); // Pop the 'depth' field
return 0; // Error
}
lua_pop(L, 1); // Pop the 'depth' field
return 1; // Success
}
// Function to read a Lua table representing a light
int readLight(lua_State* L, tp::PointLight* light) {
lua_getfield(L, -1, "pos"); // Get the "pos" field from the light table
if (!lua_istable(L, -1)) {
printf("Light is missing the 'pos' table.\n");
return 0; // Error
}
for (int i = 0; i < 3; i++) {
lua_rawgeti(L, -1, i + 1); // Index is 1-based in Lua
if (!lua_isnumber(L, -1)) {
printf("Light 'pos' field is not a number at index %d.\n", i);
lua_pop(L, 2); // Pop both the number and the 'pos' table
return 0; // Error
}
light->pos[i] = lua_tonumber(L, -1);
lua_pop(L, 1); // Pop the number
}
lua_pop(L, 1); // Pop the 'pos' table
lua_getfield(L, -1, "intensity"); // Get the "intensity" field from the light table
if (!lua_isnumber(L, -1)) {
printf("Light is missing the 'intensity' field or it's not a number.\n");
lua_pop(L, 1); // Pop the 'intensity' field
return 0; // Error
}
light->intensity = lua_tonumber(L, -1);
lua_pop(L, 1); // Pop the 'intensity' field
return 1; // Success
}
bool tp::Scene::loadLuaFormat(const std::string& scenePath) {
lua_State* L = luaL_newstate();
luaL_openlibs(L);
namespace fs = std::filesystem;
fs::path fullPath(scenePath);
// Extract the filename
std::string fileName = fullPath.filename().string();
// Remove the filename from the path
fs::path directoryPath = fullPath.remove_filename();
if (luaL_dofile(L, scenePath.c_str()) != 0) {
lua_close(L);
printf("Cant open scene script.\n");
return false;
}
lua_getglobal(L, "Meshes");
if (lua_isstring(L, -1)) {
std::string meshesPath = lua_tostring(L, -1);
directoryPath /= meshesPath;
if (!loadOBJFormat(directoryPath.string())) {
printf("No 'meshes' loaded - check ur .obj path and validate content of .obj .\n");
return false;
}
} else {
printf("No 'meshes' path given.\n");
return false;
}
// --- camera
// Access Camera table
lua_getglobal(L, "Camera");
if (!lua_istable(L, -1)) {
printf("Camera is not a table.\n");
lua_close(L);
return false;
}
// Verify you are inside the "Camera" table
int cameraTableIndex = lua_gettop(L); // Get the index of the "Camera" table
// Access the "pos" field and validate it
lua_getfield(L, cameraTableIndex, "pos");
if (!lua_istable(L, -1) || lua_rawlen(L, -1) != 3) {
printf("Invalid 'pos' field in Camera table.\n");
lua_close(L);
return false;
}
// Read the values from the table
float pos[3];
for (int i = 0; i < 3; i++) {
lua_rawgeti(L, -1, i + 1);
if (lua_isnumber(L, -1)) {
pos[i] = lua_tonumber(L, -1);
} else {
printf("Invalid 'pos' field value at index %d.\n", i + 1);
lua_close(L);
return false;
}
lua_pop(L, 1);
}
// Access the "size_x" field and validate it
lua_getfield(L, cameraTableIndex, "size_x");
if (!lua_isnumber(L, -1)) {
printf("Invalid or missing 'size_x' field in Camera table.\n");
lua_close(L);
return false;
}
int size_x = lua_tointeger(L, -1);
lua_pop(L, 1); // Pop the 'size_x' value from the stack
// Access the "size_y" field and validate it
lua_getfield(L, cameraTableIndex, "size_y");
if (!lua_isnumber(L, -1)) {
printf("Invalid or missing 'size_y' field in Camera table.\n");
lua_close(L);
return false;
}
int size_y = lua_tointeger(L, -1);
mRenderSettings.size = { (tp::halnf) size_x, (tp::halnf) size_y };
mCamera.lookAtPoint({ 0, 0, 0 }, { pos[0], pos[1], pos[2] }, { 0, 0, 1 });
mCamera.setFOV(3.14 / 4);
mCamera.setFar(100);
mCamera.setRatio((tp::halnf) size_y / (tp::halnf) size_x);
// ---------- LIGHTS
{
lua_getglobal(L, "Lights");
if (!lua_istable(L, -1)) {
printf("Lights is not a table.\n");
lua_close(L);
return false; // Error
}
// Read and process each light in the "Lights" table
int numLights = lua_rawlen(L, -1); // Get the number of lights in the table
for (int i = 1; i <= numLights; i++) {
lua_rawgeti(L, -1, i); // Get the i-th element (light) from the table
if (lua_istable(L, -1)) {
tp::PointLight light;
if (!readLight(L, &light)) {
printf("Cant read lights data\n");
lua_close(L);
return false; // Error
}
mLights.append(light);
}
lua_pop(L, 1); // Pop the i-th light table
}
}
// ----------- settings --------------
if (!readRenderSettings(L, mRenderSettings)) {
printf("Cant Read Render Settings");
lua_close(L);
return false; // Error
}
lua_close(L);
return true;
}

View file

@ -0,0 +1,51 @@
#include "Scene.hpp"
extern "C" {
#include "lauxlib.h"
#include "lualib.h"
}
#include "obj/OBJ_Loader.h"
#include <filesystem>
bool tp::Scene::loadOBJFormat(const std::string& objetsPath) {
using namespace tp;
objl::Loader Loader;
if (!Loader.LoadFile(objetsPath)) {
std::cout << "Failed to Load File. May have failed to find it or it was not an .obj file.\n";
return false;
}
for (auto& curMesh : Loader.LoadedMeshes) {
mObjects.append(Object());
auto object = &mObjects.last();
for (auto& vertex : curMesh.Vertices) {
// printf("{ %f, %f, %f }, \n", vertex.Position.X, vertex.Position.Y, vertex.Position.Z);
object->mTopology.Points.append(Vec3F{ vertex.Position.X, vertex.Position.Y, vertex.Position.Z });
object->mTopology.Normals.append(Vec3F{ vertex.Normal.X, vertex.Normal.Y, vertex.Normal.Z });
}
for (int j = 0; j < curMesh.Indices.size(); j += 3) {
auto idx1 = (uhalni) curMesh.Indices[j];
auto idx2 = (uhalni) curMesh.Indices[j + 1];
auto idx3 = (uhalni) curMesh.Indices[j + 2];
// printf("{ %i, %i, %i },\n", idx1, idx2, idx3);
object->mTopology.Indexes.append(Vec3<uhalni>{ idx1, idx2, idx3 });
}
if (object->mTopology.Normals.size() != object->mTopology.Points.size()) {
printf("Logic error loading normals\n");
}
object->mCache.Source = &object->mTopology;
object->mCache.updateCache();
}
return mObjects.size();
}

View file

@ -0,0 +1,6 @@
#include "Scene.hpp"
bool tp::Scene::load(const std::string& scenePath) {
return loadLuaFormat(scenePath);
}

61
3DScene/public/Scene.hpp Normal file
View file

@ -0,0 +1,61 @@
#pragma once
#include "Topology.hpp"
#include "Buffer2D.hpp"
#include "Camera.hpp"
#include <string>
namespace tp {
struct RenderSettings {
uhalni depth = 2;
uhalni spray = 1;
ualni multisampling = 1;
Vec2<ualni> size;
};
class GPUBuffers {
public:
GPUBuffers() = default;
virtual ~GPUBuffers() = default;
virtual void drawCall() = 0;
};
class Object {
public:
Object() = default;
~Object() {
delete mGUPBuffers;
};
public:
Topology mTopology;
TopologyCache mCache;
GPUBuffers* mGUPBuffers = nullptr;
};
struct PointLight {
Vec3F pos;
halnf fallOut = 1.f;
halnf intensity = 1.f;
};
class Scene {
public:
Scene() = default;
bool load(const std::string& scenePath);
bool loadLuaFormat(const std::string& scenePath);
bool loadOBJFormat(const std::string& objectsPath);
public:
Buffer<Object> mObjects;
Buffer<PointLight> mLights;
Camera mCamera;
RenderSettings mRenderSettings;
};
}

View file

@ -1,42 +0,0 @@
# Profiling
## Memory Leaks
Example program with memory leaks:
```c++
#include "allocators.h"
void test_call22() { new int; }
void test_call21() { new float; }
void test_call11() {
test_call21();
test_call22();
}
int main(char argc, char* argv[]) {
tp::ModuleManifest* ModuleDependencies[] = { &tp::gModuleAllocators, NULL };
tp::ModuleManifest TestModule("Test", NULL, NULL, ModuleDependencies);
TestModule.initialize();
test_call11();
TestModule.deinitialize();
}
```
If memory leaks were detected it will be loged in the output console.
![image](https://user-images.githubusercontent.com/63184036/222794298-3f238de4-c0b8-41fa-b7ec-c0c675da8f05.png)
Also debug.memleaks binary will be generated in the working directory that can be viewved with MemLeaks Viewver.
![image](https://user-images.githubusercontent.com/63184036/222793169-a405effe-72be-42fc-b375-bb06dce0a735.png)
## Memory Usage Analisys
Currently outdated
## Benchmarks
Currently outdated

View file

@ -1,23 +0,0 @@
#include "Allocators.hpp"
#include <cstdlib>
static tp::ModuleManifest* sModuleDependencies[] = { &tp::gModuleBase, nullptr };
tp::ModuleManifest tp::gModuleAllocators = ModuleManifest("Allocators", nullptr, nullptr, sModuleDependencies);
void* operator new(size_t aSize) { return tp::HeapAllocGlobal::allocate(aSize); }
void* operator new[](size_t aSize) { return tp::HeapAllocGlobal::allocate(aSize); }
void operator delete(void* aPtr) noexcept { tp::HeapAllocGlobal::deallocate(aPtr); }
void operator delete[](void* aPtr) noexcept { tp::HeapAllocGlobal::deallocate(aPtr); }
void* operator new(size_t aSize, tp::HeapAlloc& aAlloc) { return aAlloc.allocate(aSize); }
void* operator new[](size_t aSize, tp::HeapAlloc& aAlloc) { return aAlloc.allocate(aSize); }
void operator delete(void* aPtr, tp::HeapAlloc& aAlloc) { aAlloc.deallocate(aPtr); }
void operator delete[](void* aPtr, tp::HeapAlloc& aAlloc) { aAlloc.deallocate(aPtr); }
void* operator new(size_t aSize, tp::HeapAllocGlobal& aAlloc) { return tp::HeapAllocGlobal::allocate(aSize); }
void* operator new[](size_t aSize, tp::HeapAllocGlobal& aAlloc) { return tp::HeapAllocGlobal::allocate(aSize); }
void operator delete(void* aPtr, tp::HeapAllocGlobal& aAlloc) { tp::HeapAllocGlobal::deallocate(aPtr); }
void operator delete[](void* aPtr, tp::HeapAllocGlobal& aAlloc) { tp::HeapAllocGlobal::deallocate(aPtr); }

View file

@ -1,70 +0,0 @@
#include "HeapAllocator.hpp"
#include "HeapAllocatorGlobal.hpp"
#include "PrivateConfig.hpp"
using namespace tp;
#if not defined(MEM_DEBUG)
// ----------------------- Release Implementation ---------------------------- //
void* HeapAlloc::allocate(ualni aBlockSize) { return malloc(aBlockSize); }
void HeapAlloc::deallocate(void* aPtr) { free(aPtr); }
HeapAlloc::~HeapAlloc() {}
#else
namespace tp {
struct MemHeadLocal {
MemHeadLocal* mPrev;
MemHeadLocal* mNext;
};
}
void* HeapAlloc::allocate(ualni aBlockSize) {
auto head = (MemHeadLocal*) HeapAllocGlobal::allocate(aBlockSize + sizeof(MemHeadLocal));
auto out = head + 1;
mNumAllocations++;
if (mEntry) {
DEBUG_ASSERT(!mEntry->mNext)
head->mNext = nullptr;
head->mPrev = mEntry;
mEntry->mNext = head;
} else {
head->mNext = nullptr;
head->mPrev = nullptr;
}
mEntry = head;
return out;
}
void HeapAlloc::deallocate(void* aPtr) {
auto head = ((MemHeadLocal*)(aPtr)) - 1;
mNumAllocations--;
DEBUG_ASSERT(!mEntry->mNext)
if (head->mNext) head->mNext->mPrev = head->mPrev;
if (head->mPrev) head->mPrev->mNext = head->mNext;
if (head == mEntry) {
mEntry = head->mPrev;
}
HeapAllocGlobal::deallocate(head);
}
HeapAlloc::~HeapAlloc() {
if (mNumAllocations) {
DEBUG_BREAK("Destruction of not freed Allocator")
#ifdef MEM_STACK_TRACE
// TODO : log leaks and free them up
#endif
}
}
#endif

View file

@ -1,150 +0,0 @@
#include "HeapAllocatorGlobal.hpp"
#include "PrivateConfig.hpp"
#include "Utils.hpp"
#include "Debugging.hpp"
#include <cstdlib>
using namespace tp;
#if not defined(MEM_DEBUG)
// ----------------------- Release Implementation ---------------------------- //
void* HeapAllocGlobal::allocate(ualni aBlockSize) { return malloc(aBlockSize); }
void HeapAllocGlobal::deallocate(void* aPtr) { free(aPtr); }
HeapAllocGlobal::~HeapAllocGlobal() = default;
#else
tp::MemHead* tp::HeapAllocGlobal::mEntry = nullptr;
tp::ualni tp::HeapAllocGlobal::mNumAllocations = 0;
// ----------------------- Debug Implementation ---------------------------- //
// |----------------|
// | MemHead |
// |----------------|
// | wrap top |
// |----------------| - Allocated Block Layout
// | data |
// |----------------|
// | wrap bottom |
// |----------------|
namespace tp {
struct MemHead {
MemHead* mPrev;
MemHead* mNext;
ualni mBlockSize;
#ifdef MEM_STACK_TRACE
const CallStackCapture::CallStack* mCallStack;
#endif
};
}
enum : ualni {
ALIGNED_SIZE = ENV_ALNI_SIZE_B,
WRAP_SIZE = MEM_WRAP_SIZE * ALIGNED_SIZE,
WRAP_VAL = MEM_WRAP_FILL_VAL,
HEAD_SIZE = sizeof(MemHead),
CLEAR_ALLOC_VAL = MEM_CLEAR_ON_ALLOC_VAL,
CLEAR_DEALLOC_VAL = MEM_CLEAR_ON_DEALLOC_VAL,
};
void* HeapAllocGlobal::allocate(ualni aBlockSize) {
static_assert(HEAD_SIZE % ALIGNED_SIZE == 0, "Heap Allocator Configuration Error");
if (aBlockSize % ALIGNED_SIZE) {
aBlockSize = (aBlockSize / ALIGNED_SIZE + 1) * ALIGNED_SIZE;
}
// 1) Allocate the block
auto head = (MemHead*)malloc(aBlockSize + WRAP_SIZE * 2 + HEAD_SIZE);
auto wrap_top = (int1*)(head + 1);
auto data = wrap_top + WRAP_SIZE;
auto wrap_bottom = data + aBlockSize;
if (!head) { return nullptr; }
head->mBlockSize = aBlockSize;
// 2) Link with existing blocks
mNumAllocations++;
if (mEntry) {
DEBUG_ASSERT(!mEntry->mNext)
head->mNext = nullptr;
head->mPrev = mEntry;
mEntry->mNext = head;
} else {
head->mNext = nullptr;
head->mPrev = nullptr;
}
mEntry = head;
// 3) Wrap fill
memSetVal(wrap_top, WRAP_SIZE, WRAP_VAL);
memSetVal(wrap_bottom, WRAP_SIZE, WRAP_VAL);
// 4) Trace the stack
#ifdef MEM_STACK_TRACE
head->mCallStack = gCSCapture->getSnapshot();
#endif
// 5) clear data
#ifdef MEM_CLEAR_ON_ALLOC
memSetVal(data, aBlockSize, CLEAR_ALLOC_VAL);
#endif
return data;
}
void HeapAllocGlobal::deallocate(void* aPtr) {
// 1) Restore the pointers
auto head = ((MemHead*)((int1*)aPtr - WRAP_SIZE)) - 1;
auto wrap_top = (int1*)(head + 1);
auto data = wrap_top + WRAP_SIZE;
auto wrap_bottom = data + head->mBlockSize;
// 2) Unlink with blocks
mNumAllocations--;
DEBUG_ASSERT(!mEntry->mNext)
if (head->mNext) head->mNext->mPrev = head->mPrev;
if (head->mPrev) head->mPrev->mNext = head->mNext;
if (head == mEntry) {
mEntry = head->mPrev;
}
// 3) Check the wrap
ASSERT(!memCompareVal(wrap_top, WRAP_SIZE, WRAP_VAL) && "Allocated Block Wrap Corrupted!")
ASSERT(!memCompareVal(wrap_bottom, WRAP_SIZE, WRAP_VAL) && "Allocated Block Wrap Corrupted!")
// 4) clear data
#ifdef MEM_CLEAR_ON_ALLOC
memSetVal(data, head->mBlockSize, CLEAR_DEALLOC_VAL);
#endif
// 5) free the block
free(head);
}
bool HeapAllocGlobal::checkLeaks() {
// 1) Check for not deallocated memory
if (mNumAllocations) {
#ifdef MEM_STACK_TRACE
gCSCapture->logLeaks();
#endif
DEBUG_BREAK("Destruction of not freed Allocator")
return true;
}
return false;
}
HeapAllocGlobal::~HeapAllocGlobal() = default;
#endif

View file

@ -1,29 +0,0 @@
#pragma once
#include "Module.hpp"
#include "HeapAllocatorGlobal.hpp"
#include "HeapAllocator.hpp"
#include "ChunkAllocator.hpp"
#include "PoolAllocator.hpp"
namespace tp {
extern ModuleManifest gModuleAllocators;
}
inline void* operator new(std::size_t aSize, void* aWhere) noexcept { return aWhere; }
void* operator new(std::size_t aSize);
void* operator new[](std::size_t aSize);
void operator delete(void* aPtr) noexcept;
void operator delete[](void* aPtr) noexcept;
void* operator new(std::size_t aSize, tp::HeapAlloc& aAlloc);
void* operator new[](std::size_t aSize, tp::HeapAlloc& aAlloc);
void operator delete(void* aPtr, tp::HeapAlloc& aAlloc);
void operator delete[](void* aPtr, tp::HeapAlloc& aAlloc);
void* operator new(std::size_t aSize, tp::HeapAllocGlobal& aAlloc);
void* operator new[](std::size_t aSize, tp::HeapAllocGlobal& aAlloc);
void operator delete(void* aPtr, tp::HeapAllocGlobal& aAlloc);
void operator delete[](void* aPtr, tp::HeapAllocGlobal& aAlloc);

View file

@ -1,135 +0,0 @@
#pragma once
/*
* Implementation uses embedded one-directional linked list to track free blocks.
* The embedded part ensures that there is no memory overhead on block specifically.
* Linked list is initialized iteratively on each allocation if it has not been already.
* Allocating:
* 1) updating list entry to stored in the entry itself next free pointer
* 2) returning entry before (1).
*
* Deallocating:
* 1) assigning list entry value to the deleted block
* 2) updating list entry to that block.
*/
#include "Environment.hpp"
#include "PrivateConfig.hpp"
namespace tp {
// Chunk Allocator
// Constant time allocations and de-allocations in any order.
// Memory blocks are fixed in size and number of blocks can not exceed given parameter.
template<typename tType, ualni tNumBlocks>
class ChunkAlloc {
enum : ualni {
ALIGNED_SIZE = ENV_ALNI_SIZE_B,
WRAP_SIZE_ALN = MEM_WRAP_SIZE / 2,
WRAP_SIZE = WRAP_SIZE_ALN * ALIGNED_SIZE,
WRAP_VAL = MEM_WRAP_FILL_VAL,
CLEAR_ALLOC_VAL = MEM_CLEAR_ON_ALLOC_VAL,
CLEAR_DEALLOC_VAL = MEM_CLEAR_ON_DEALLOC_VAL,
};
static constexpr ualni dataSize() {
auto BLOCK_SIZE_BYTES = sizeof(tType);
auto BLOCK_SIZE_ALIGNED = BLOCK_SIZE_BYTES / ALIGNED_SIZE;
return BLOCK_SIZE_ALIGNED;
}
static constexpr ualni blockSize() {
auto BLOCK_SIZE_BYTES = sizeof(tType);
auto BLOCK_SIZE = dataSize() + bool(BLOCK_SIZE_BYTES % ALIGNED_SIZE) + WRAP_SIZE_ALN * 2;
return BLOCK_SIZE;
}
private:
ualni* mNextBlock;
ualni mNumFreeBlocks;
ualni mNumInitBlocks;
ualni mBuff[tNumBlocks * blockSize() * ALIGNED_SIZE];
public:
ChunkAlloc() {
mNumFreeBlocks = tNumBlocks;
mNumInitBlocks = 0;
mNextBlock = mBuff;
}
~ChunkAlloc() = default; // TODO : check for leaks
public:
void* allocate(ualni) {
DEBUG_ASSERT(mNumFreeBlocks && "Out Of Memory")
// 1) PreInitialize blocks
if (mNumInitBlocks < tNumBlocks) {
mBuff[mNumInitBlocks * blockSize()] = (ualni) (mBuff + (mNumInitBlocks + 1) * blockSize());
mNumInitBlocks++;
}
// 2) Find free block and update next free block
auto data = mNextBlock;
mNextBlock = (ualni*)(*data);
mNumFreeBlocks--;
#ifdef MEM_DEBUG
// 3) Fill Wrap and offset data
auto wrap_top = data;
auto wrap_bottom = data + WRAP_SIZE_ALN + dataSize();
memSetVal(wrap_top, WRAP_SIZE, WRAP_VAL);
memSetVal(wrap_bottom, WRAP_SIZE, WRAP_VAL);
// 4) Clear data
#ifdef MEM_CLEAR_ON_ALLOC
memSetVal(data + WRAP_SIZE_ALN, dataSize() * ALIGNED_SIZE, CLEAR_ALLOC_VAL);
#endif
data += WRAP_SIZE_ALN;
#endif
return data;
}
void deallocate(void* aPtr) {
DEBUG_ASSERT(aPtr >= mBuff && aPtr < mBuff + tNumBlocks * blockSize())
auto block = (ualni*)aPtr;
#ifdef MEM_DEBUG
// 3) Check Wrap and offset data
auto wrap_bottom = block + dataSize();
auto wrap_top = block - WRAP_SIZE_ALN;
block = wrap_top;
// 3) Check the wrap
ASSERT(!memCompareVal(wrap_top, WRAP_SIZE, WRAP_VAL) && "Allocated Block Wrap Corrupted!")
ASSERT(!memCompareVal(wrap_bottom, WRAP_SIZE, WRAP_VAL) && "Allocated Block Wrap Corrupted!")
// 4) Clear data
#ifdef MEM_CLEAR_ON_ALLOC
memSetVal(block, blockSize() * ALIGNED_SIZE, CLEAR_DEALLOC_VAL);
#endif
#endif
(*block) = (ualni)mNextBlock;
mNextBlock = block;
mNumFreeBlocks++;
}
[[nodiscard]] bool checkWrap() const { return false; }
void checkValid() {}
public:
[[nodiscard]] bool isFull() const { return !mNumFreeBlocks; }
[[nodiscard]] bool isEmpty() const { return mNumFreeBlocks == tNumBlocks; }
[[nodiscard]] const ualni* getBuff() const { return mBuff; }
};
}

View file

@ -1,26 +0,0 @@
#pragma once
#include "Environment.hpp"
namespace tp {
class HeapAlloc {
#ifdef MEM_DEBUG
ualni mNumAllocations = 0;
struct MemHeadLocal* mEntry = nullptr;
#endif
public:
HeapAlloc() = default;
~HeapAlloc();
public:
void* allocate(ualni aBlockSize);
void deallocate(void* aPtr);
public:
[[nodiscard]] bool checkWrap() const { return false; }
void checkValid() {}
};
}

View file

@ -1,27 +0,0 @@
#pragma once
#include "Module.hpp"
namespace tp {
class HeapAllocGlobal {
#ifdef MEM_DEBUG
static ualni mNumAllocations;
static struct MemHead* mEntry;
#endif
public:
HeapAllocGlobal() = default;
~HeapAllocGlobal();
public:
static void* allocate(ualni aBlockSize);
static void deallocate(void* aPtr);
static bool checkLeaks();
public:
[[nodiscard]] bool checkWrap() const { return false; }
void checkValid() {}
};
}

View file

@ -1,162 +0,0 @@
#pragma once
/*
Implementation:
* Adding chunk pointer to each chunk to form one-directional list that keeps track of free chunk
* Storing ordered pointers to chunks in order to find desired chunk from delete pointer on de-allocation in log time
*
* Allocations:
* 1) allocate with chunk stored in list entry
* 2) ...
*
* De-allocations:
* 1) binary-search with delete pointer to find desired chunk
* 2) ...
*
*/
#include "ChunkAllocator.hpp"
namespace tp {
// Pool Allocator
// Overcomes chunk allocator fixed number of max allocations
template<typename tType, ualni tNumBlocks>
class PoolAlloc {
typedef ChunkAlloc<tType, tNumBlocks> Chunk;
struct Chunks {
void add(Chunk* aChunk){
if (!mBuff) {
mLen = 16;
mBuff = (Chunk**) HeapAllocGlobal::allocate(sizeof(Chunk*) * mLen);
mUsedLen = 1;
mBuff[0] = aChunk;
return;
}
// ensure order
auto smaller_address = findUtil(mBuff, mBuff + mUsedLen, aChunk);
for (auto iter = mBuff + mUsedLen; iter != smaller_address; iter--) {
*iter = *(iter - 1);
}
*(smaller_address) = aChunk;
mUsedLen++;
// check for buff overflow
if (mUsedLen == mLen) {
auto prevBuff = mBuff;
mBuff = (Chunk**) HeapAllocGlobal::allocate(sizeof(Chunk*) * mLen * 2);
memCopy(mBuff, prevBuff, sizeof(Chunk*) * mUsedLen);
mLen *= 2;
HeapAllocGlobal::deallocate(prevBuff);
}
}
void remove(Chunk** del_address){
if (mUsedLen == 1) {
mLen = 0;
mUsedLen = 0;
HeapAllocGlobal::deallocate(mBuff);
mBuff = nullptr;
return;
}
// ensure order
for (auto iter = del_address; iter != mBuff + mUsedLen - 1; iter++) {
*iter = *(iter + 1);
}
mUsedLen--;
// check for buff low usage
if ((halnf)mUsedLen / (halnf)mLen < 0.25f) {
auto prevBuff = mBuff;
mBuff = (Chunk**)HeapAllocGlobal::allocate(sizeof(Chunk*) * mLen / 2);
memCopy(mBuff, prevBuff, sizeof(Chunk*) * mUsedLen);
mLen /= 2;
HeapAllocGlobal::deallocate(prevBuff);
}
}
[[nodiscard]] Chunk** find(void* aPtr) {
return findUtil(mBuff, mBuff + mUsedLen, aPtr) - 1;
}
[[nodiscard]] Chunk* findNotFull() const {
for (ualni idx = 0; idx < mUsedLen; idx++) {
if (!mBuff[idx]->isFull()) {
return mBuff[idx];
}
}
return nullptr;
}
Chunk** mBuff = nullptr;
ualni mUsedLen = 0;
ualni mLen = 0;
private:
Chunk** findUtil(Chunk** aLeft, Chunk** aRight, void* aPtr) {
auto range = ualni(aRight - aLeft);
if (range == 1) {
return (aPtr < *aLeft) ? aLeft : aRight;
}
auto middle = aLeft + range / 2;
return (aPtr >= (*middle)) ? findUtil(middle, aRight, aPtr) : findUtil(aLeft, middle, aPtr);
}
};
private:
Chunks mChunks;
Chunk* mFreeChunk = nullptr;
public:
PoolAlloc() = default;
~PoolAlloc() = default;
public:
void* allocate(ualni) {
if (!mFreeChunk || mFreeChunk->isFull()) {
auto new_free_chunk = mChunks.findNotFull();
if (!new_free_chunk) {
new_free_chunk = new (HeapAllocGlobal::allocate(sizeof(Chunk))) Chunk();
DEBUG_ASSERT(new_free_chunk)
mChunks.add(new_free_chunk);
}
mFreeChunk = new_free_chunk;
}
return mFreeChunk->allocate(0);
}
void deallocate(void* aPtr) {
auto chunk = mChunks.find(aPtr);
(*chunk)->deallocate(aPtr);
if ((*chunk)->isEmpty()) {
if (mFreeChunk == *chunk) mFreeChunk = nullptr;
HeapAllocGlobal::deallocate(*chunk);
mChunks.remove(chunk);
}
}
public:
[[nodiscard]] bool checkWrap() const { return false; }
void checkValid() {
return;
for (auto i = 0; i < mChunks.mUsedLen; i++) {
for (auto j = 0; j < mChunks.mUsedLen; j++) {
if (i > j) {
ASSERT(mChunks.mBuff[i] > mChunks.mBuff[j])
} else if (i < j) {
ASSERT(mChunks.mBuff[i] < mChunks.mBuff[j])
}
}
}
}
};
}

View file

@ -1,10 +0,0 @@
#pragma once
#define MEM_WRAP_SIZE 8 // Wrapping Size in aligned units
#define MEM_WRAP_FILL_VAL 0xBB // Wrapping Fill Value
#define MEM_CLEAR_ON_ALLOC // Clear data on allocation
#define MEM_CLEAR_ON_DEALLOC // Clear data on free
#define MEM_CLEAR_ON_DEALLOC_VAL 0xAA // Clear data on free
#define MEM_CLEAR_ON_ALLOC_VAL 0xCC // Clear data on free
#define MEM_STACK_TRACE // Save stack on allocation call
#define MEM_STACK_TRACE_MAX_DEPTH 32 // Call stack max depth

View file

@ -1,20 +0,0 @@
#include "Allocators.hpp"
#include "Tests.hpp"
using namespace tp;
int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleAllocators, &tp::gModuleUtils, nullptr };
tp::ModuleManifest testModule("AllocatorsTest", nullptr, nullptr, deps);
if (!testModule.initialize()) {
return 1;
}
testAll();
testModule.deinitialize();
}

View file

@ -1,6 +0,0 @@
#pragma once
#include "Utils.hpp"
#include "Testing.hpp"
void testAll();

View file

@ -1,248 +0,0 @@
#include "Utils.hpp"
#include "Testing.hpp"
#include "HeapAllocatorGlobal.hpp"
#include "HeapAllocator.hpp"
#include "ChunkAllocator.hpp"
#include "PoolAllocator.hpp"
#include <cmath>
using namespace tp;
struct TestStruct {
alni val = 0;
TestStruct() : val(0) {}
explicit TestStruct(alni val) : val(val) {}
TestStruct(const TestStruct& in) : val(in.val) {}
~TestStruct() { val = -1; }
bool operator==(const TestStruct& in) const {
return in.val == val;
}
};
template <alni tSize, class tAllocator>
class TestBenches {
tAllocator mAlloc{};
TestStruct mData[tSize]{};
TestStruct* mLoaded[tSize]{};
bool mIsLoaded[tSize]{};
alni mLoadedNum = 0;
public:
TestBenches() {
for (alni i = 0; i < tSize; i++) {
mData[i].val = i;
mIsLoaded[i] = false;
mLoaded[i] = nullptr;
}
}
void runTests() {
try {
test1();
test2();
test3();
test4();
test5();
test6();
} catch (...) {
ASSERT(false)
}
}
private:
alni randomIdx(bool state, Range<alni> range = { 0, tSize }) {
RAND:
auto idx = alni(alnf(range.idxBegin()) + randomFloat() * alnf(range.idxDiff() + 1));
idx = clamp(idx, alni(0), tSize - 1);
if (state == mIsLoaded[idx]) goto RAND;
return idx;
}
void verifyIntegrity() {
mAlloc.checkValid();
ASSERT(!mAlloc.checkWrap())
for (alni i = 0; i < tSize; i++) {
if (mIsLoaded[i]) {
ASSERT(*mLoaded[i] == mData[i])
}
}
}
void loadItem(alni idx) {
if (mIsLoaded[idx]) return;
verifyIntegrity();
mLoaded[idx] = new (mAlloc.allocate(sizeof(TestStruct))) TestStruct(mData[idx]);
TEST(mLoaded[idx]);
mIsLoaded[idx] = true;
mLoadedNum++;
verifyIntegrity();
}
void unloadItem(alni idx) {
if (!mIsLoaded[idx]) return;
verifyIntegrity();
mLoaded[idx]->~TestStruct();
mAlloc.deallocate(mLoaded[idx]);
mIsLoaded[idx] = false;
mLoadedNum--;
verifyIntegrity();
}
void changeStates(Range<alni> rg, bool load, bool reversed = false, bool random = false) {
for (auto i : rg) {
alni idx = i;
if (random) {
idx = randomIdx(load, rg);
} else if (reversed) {
idx = rg.idxEnd() - i - 1;
}
(load) ? loadItem(idx) : unloadItem(idx);
}
}
// full down-up load then up-down unload
void test1() {
changeStates({ 0, tSize }, true);
changeStates({ 0, tSize }, false, true);
}
// full down-up load then down-up unload
void test2() {
changeStates({0, tSize}, true);
changeStates({0, tSize}, false);
}
// full random load then random unload
void test3() {
changeStates({0, tSize}, true, false, true);
changeStates({0, tSize}, false, false, true);
}
// combo tests 1-3
void test4() {
test1();
test1();
test2();
test2();
test3();
test3();
}
static alnf sineUpFunction(alnf aSize, alnf aX, bool aReverse) {
alnf end = 4 * 3.14159;
alnf a = (2 / 7.f) * aSize;
alnf b = end / aSize;
alni c = ((-1 * aReverse) + (1 * !aReverse));
alnf c1 = (aX - (end * aReverse)) / b;
alnf c2 = (a * sin(aX - (end * aReverse)));
alnf out = c1 + c2;
return (alnf) c * out;
}
// sin load & sin unload with ~1/2 drop factor
void test5() {
alnf end = 4 * 3.14159;
alnf step = end / 4.f;
for (char i = 0; i < 2; i++) {
for (alnf x = 0; x <= end; x += step) {
alni target_alloc_count = (alni) ceil(sineUpFunction(tSize, x, i));
target_alloc_count = clamp(target_alloc_count, alni(0), tSize);
while (mLoadedNum > target_alloc_count) {
unloadItem(randomIdx(0));
}
while (mLoadedNum < target_alloc_count) {
loadItem(randomIdx(1));
}
}
}
}
void checkWrap(ualni offset, bool after) {
offset = clamp(offset, (ualni) 1, (ualni) MEM_WRAP_SIZE);
TestStruct* ts = mLoaded[randomIdx(0)];
ualni shift = (sizeof(TestStruct) * after) + (offset - 1) * after - offset * (!after);
uint1* address = (((uint1*)ts) + shift);
uint1 val = *address;
*address = 5;
TEST(!mAlloc.checkWrap());
*address = val;
}
// mem guards test
void test6() {
changeStates({0, tSize}, 1);
#ifdef MEM_DEBUG
for (alni after = 0; after < 2; after++) {
for (alni offset = 1; offset <= MEM_WRAP_SIZE; offset++) {
checkWrap(offset, after);
}
}
#endif
changeStates({0, tSize}, 0);
}
};
const ualni size = 1000;
template<typename Alloc>
void testAlloc() {
try {
TestBenches<size, Alloc> heapTests{};
heapTests.runTests();
} catch (...) {
TEST(false);
}
}
TEST_DEF_STATIC(GlobalHeap) {
testAlloc<HeapAllocGlobal>();
}
TEST_DEF_STATIC(Heap) {
testAlloc<HeapAlloc>();
}
TEST_DEF_STATIC(Chunk) {
testAlloc<ChunkAlloc<TestStruct, size>>();
testAlloc<ChunkAlloc<TestStruct, size * 2>>();
}
TEST_DEF_STATIC(Pool) {
testAlloc<PoolAlloc<TestStruct, 1>>();
testAlloc<PoolAlloc<TestStruct, size / 100>>();
testAlloc<PoolAlloc<TestStruct, size>>();
}
TEST_DEF_STATIC(Simple) {
auto a = new TestStruct(-1);
delete a;
}
TEST_DEF(All) {
testSimple();
testGlobalHeap();
testHeap();
testChunk();
testPool();
// TEST(HeapAllocGlobal::checkLeaks());
// TEST(false);
}

View file

@ -1,17 +1,28 @@
cmake_minimum_required(VERSION 3.2)
set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_SOURCE_DIR}/install)
cmake_minimum_required(VERSION 3.5)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -gdwarf-4")
set(CMAKE_CXX_STANDARD 20)
enable_testing()
# set(CMAKE_INSTALL_PREFIX ${CMAKE_CURRENT_SOURCE_DIR}/./tmp/install)
# set(CMAKE_CXX_FLAGS "-fuse-ld=lld-15 ${CMAKE_CXX_FLAGS} -gdwarf-4 ")
project(Types)
project(ModulesRoot)
add_compile_definitions(MEM_DEBUG)
include(CMakeOptions.txt)
add_subdirectory(Modules)
add_subdirectory(Utils)
add_subdirectory(Containers)
add_subdirectory(Math)
add_subdirectory(Allocators)
# add_subdirectory(Language)
add_subdirectory(Externals)
add_subdirectory(Connection)
add_subdirectory(Graphics)
add_subdirectory(DataAnalysis)
add_subdirectory(Objects)
add_subdirectory(Widgets)
add_subdirectory(LibraryViewer)
add_subdirectory(RasterRender)
add_subdirectory(3DScene)
add_subdirectory(RayTracer)
add_subdirectory(Sketch3D)
add_subdirectory(3DEditor)

14
CMakeOptions.txt Normal file
View file

@ -0,0 +1,14 @@
option(MODULES_MEMORY_DEBUG "Debug memory" OFF)
option(MODULES_MEMORY_DEBUG_STACK_TRACE "Record stack info on memory debug" OFF)
set(WINDOWS_LIBRARIES "../../ModulesWindowsLibraries" CACHE STRING "Svn repository with windows libraries https://svn.riouxsvn.com/moduleswindowsl")
if (MODULES_MEMORY_DEBUG)
add_compile_definitions(MEM_DEBUG)
endif ()
if (MODULES_MEMORY_DEBUG_STACK_TRACE)
add_compile_definitions(MEM_STACK_TRACE)
endif ()
enable_testing()

15
CMakeSettings.json Normal file
View file

@ -0,0 +1,15 @@
{
"configurations": [
{
"name": "x64-Debug",
"generator": "Ninja",
"configurationType": "Debug",
"inheritEnvironments": [ "msvc_x64_x64" ],
"buildRoot": "${projectDir}\\out\\build\\${name}",
"installRoot": "${projectDir}\\out\\install\\${name}",
"cmakeCommandArgs": "",
"buildCommandArgs": "",
"ctestCommandArgs": ""
}
]
}

18
Connection/CMakeLists.txt Normal file
View file

@ -0,0 +1,18 @@
project(Connection)
set(BINDINGS_INCLUDE ./../Externals/asio/asio/include)
### ---------------------- Static Library --------------------- ###
file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp")
file(GLOB HEADERS "./public/*.hpp")
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
target_include_directories(${PROJECT_NAME} PRIVATE ${BINDINGS_INCLUDE})
target_link_libraries(${PROJECT_NAME} PUBLIC Modules)
### -------------------------- Tests -------------------------- ###
enable_testing()
file(GLOB TEST_SOURCES "./tests/*.cpp")
add_executable(Test${PROJECT_NAME} ${TEST_SOURCES})
target_link_libraries(Test${PROJECT_NAME} ${PROJECT_NAME} UnitTest++)
add_test(NAME Test${PROJECT_NAME} COMMAND Test${PROJECT_NAME})

View file

@ -0,0 +1,84 @@
#include "LocalConnection.hpp"
#include "bindings/Disk.hpp"
#include <cstdio>
using namespace tp;
bool LocalConnection::Location::exists() const {
// TODO : fixme
FILE* file = fopen(mLocation.c_str(), "r");
if (file) {
// File exists, close it and return 1
fclose(file);
return true;
}
return false;
}
bool LocalConnection::connect(const Location& location, const Type& connectionInfo) {
DEBUG_ASSERT(!mStatus.isOpened());
if (mStatus.isOpened()) return false;
auto handle = new LocalConnectionContext();
switch (connectionInfo.getType()) {
case Type::READ: handle->open(location.getLocation().c_str(), true); break;
case Type::WRITE: handle->open(location.getLocation().c_str(), false); break;
default: break;
};
if (!handle->isOpen()) {
mStatus.setStatus(Status::DENIED);
delete handle;
return false;
}
mStatus.setStatus(Status::OPENED);
mHandle = handle;
mConnectionType = connectionInfo;
return true;
}
bool LocalConnection::disconnect() {
DEBUG_ASSERT(mStatus.isOpened());
if (!mStatus.isOpened() || !mHandle) return false;
mHandle->close();
delete mHandle;
mStatus.setStatus(Status::CLOSED);
return true;
}
bool LocalConnection::setPointer(BytePointer pointer) {
DEBUG_ASSERT(mStatus.isOpened());
if (!mStatus.isOpened()) return false;
mPointer = pointer;
return true;
}
bool LocalConnection::readBytes(Byte* bytes, SizeBytes size) {
DEBUG_ASSERT(mStatus.isOpened() && mConnectionType.isRead());
if (!mStatus.isOpened() || !mConnectionType.isRead()) return false;
mHandle->seekp(mPointer);
mHandle->read(bytes, size);
mPointer += size;
return true;
}
bool LocalConnection::writeBytes(const Byte* bytes, SizeBytes size) {
DEBUG_ASSERT(mStatus.isOpened() && mConnectionType.isWrite());
if (!mStatus.isOpened() || !mConnectionType.isWrite()) return false;
mHandle->seekp(mPointer);
mHandle->write(bytes, size);
mPointer += size;
return true;
}
LocalConnection::SizeBytes LocalConnection::size() {
DEBUG_ASSERT(mStatus.isOpened());
if (!mStatus.isOpened() || !mHandle) return 0;
return mHandle->size();
}

View file

@ -0,0 +1,2 @@
#include "RemoteConnection.hpp"

View file

@ -0,0 +1,53 @@
#include "Disk.hpp"
#include <fstream>
using namespace tp;
ualni tp::LocalConnectionContext::size() {
auto strm = (std::fstream*) stream;
ualni out = 0;
strm->seekg(0, std::ios::beg);
out = strm->tellg();
strm->seekg(0, std::ios::end);
out = (ualni) strm->tellg() - out;
return out;
}
LocalConnectionContext::LocalConnectionContext() { stream = new std::fstream(); }
LocalConnectionContext::~LocalConnectionContext() {
auto strm = (std::fstream*) stream;
delete strm;
}
bool LocalConnectionContext::isOpen() {
auto strm = (std::fstream*) stream;
return strm->is_open();
}
void LocalConnectionContext::close() {
auto strm = (std::fstream*) stream;
strm->close();
}
void LocalConnectionContext::seekp(ualni in) {
auto strm = (std::fstream*) stream;
strm->seekp(in);
}
void LocalConnectionContext::read(int1* in, ualni size) {
auto strm = (std::fstream*) stream;
strm->read(in, size);
}
void LocalConnectionContext::write(const int1* in, ualni size) {
auto strm = (std::fstream*) stream;
strm->write(in, size);
}
void LocalConnectionContext::open(const char* path, bool read) {
auto strm = (std::fstream*) stream;
if (read) strm->open(path, std::ios::in | std::ios::binary | std::ios::app);
else strm->open(path, std::ios::out | std::ios::binary | std::ios::trunc);
}

View file

@ -0,0 +1,18 @@
#include "Common.hpp"
namespace tp {
class LocalConnectionContext {
void* stream;
public:
LocalConnectionContext();
~LocalConnectionContext();
void open(const char*, bool);
bool isOpen();
void close();
void seekp(ualni);
void read(int1*, ualni);
void write(const int1*, ualni);
ualni size();
};
}

View file

@ -0,0 +1,116 @@
#include "Network.hpp"
#include "asio.hpp"
#include <iostream>
using namespace tp;
class tp::ServerContext {
friend class Server;
asio::io_context context;
asio::ip::tcp::acceptor socket;
typedef asio::ip::tcp::socket Socket;
ServerContext() :
socket(context) {}
~ServerContext() {
context.stop();
socket.close();
}
};
class tp::ClientContext {
friend Client;
asio::io_context context;
asio::ip::tcp::socket socket;
public:
ClientContext() :
socket(context) {}
~ClientContext() {
context.stop();
socket.close();
}
};
// --------------------------------------------------------------------------------------- //
Server::Server() { mContext = new ServerContext(); }
Server::~Server() { delete mContext; }
void Server::start(ualni port) {
mContext->socket.open(asio::ip::tcp::v4());
mContext->socket.bind(asio::ip::tcp::endpoint(asio::ip::tcp::v4(), port));
mContext->socket.listen();
std::cout << "Server listening on port " << port << std::endl;
}
Server::Socket Server::accept() {
auto clientSocket = new asio::ip::tcp::socket(mContext->context);
mContext->socket.accept(*clientSocket);
std::cout << "New client accepted " << std::endl;
return clientSocket;
}
bool Server::read(Socket client, int1* message, halni messageSize) {
try {
std::size_t bytesRead = asio::read(*(ServerContext::Socket*) client, asio::buffer(message, messageSize));
return bytesRead == messageSize;
} catch (const std::exception& e) {
std::cerr << "Error during read: " << e.what() << "\n";
return false;
}
}
bool Server::write(Socket client, const int1* message, halni messageSize) {
try {
std::size_t bytesWritten = asio::write(*(ServerContext::Socket*) client, asio::buffer(message, messageSize));
return bytesWritten == messageSize;
} catch (const std::exception& e) {
std::cerr << "Error during write: " << e.what() << "\n";
return false;
}
}
// --------------------------------------------------------------------------------------- //
Client::Client() { mContext = new ClientContext(); }
Client::~Client() { delete mContext; }
bool Client::connect(const char* IP, ualni PORT) {
try {
asio::ip::tcp::endpoint endpoint(asio::ip::address::from_string(IP), PORT);
mContext->socket.connect(endpoint);
return true;
} catch (const std::exception& e) {
std::cerr << "Error during read: " << e.what() << "\n";
return false;
}
}
bool Client::read(int1* buff, halni size) {
try {
std::size_t bytesRead = asio::read(mContext->socket, asio::buffer(buff, size));
return bytesRead == size;
} catch (const std::exception& e) {
std::cerr << "Error during read: " << e.what() << "\n";
return false;
}
}
bool Client::write(const int1* message, halni messageSize) {
try {
std::size_t bytesWritten = asio::write(mContext->socket, asio::buffer(message, messageSize));
return bytesWritten == messageSize;
} catch (const std::exception& e) {
std::cerr << "Error during write: " << e.what() << "\n";
return false;
}
}

View file

@ -0,0 +1,66 @@
#pragma once
#include "Module.hpp"
#include <string>
namespace tp {
class Connection {
public:
typedef ualni SizeBytes;
typedef ualni BytePointer;
typedef int1 Byte;
class Status {
public:
enum State {
NONE,
OPENED,
CLOSED,
DENIED,
INVALID,
};
private:
State mStatus = NONE;
public:
Status() = default;
[[nodiscard]] State getStatus() const { return mStatus; }
void setStatus(State status) { mStatus = status; }
[[nodiscard]] bool isOpened() const { return mStatus == OPENED; }
};
class Type {
public:
enum State {
WRITE,
READ,
READ_WRITE,
NONE,
};
private:
State mHandleType = NONE;
public:
Type() = default;
explicit Type(bool read) :
mHandleType((State) read) {}
explicit Type(State handleType) :
mHandleType(handleType) {}
[[nodiscard]] State getType() const { return mHandleType; }
[[nodiscard]] bool isRead() const { return mHandleType == READ; }
[[nodiscard]] bool isWrite() const { return mHandleType == WRITE; }
};
protected:
Status mStatus;
Type mConnectionType;
public:
Connection() = default;
virtual const Status& getConnectionStatus() { return mStatus; }
virtual const Type& getConnectionType() { return mConnectionType; }
};
}

View file

@ -0,0 +1,66 @@
#pragma once
#include "Archiver.hpp"
#include "ConnectionCommon.hpp"
namespace tp {
class LocalConnectionContext;
class LocalConnection : public Connection {
public:
class Location {
std::string mLocation;
public:
Location() :
mLocation("tmp"){};
explicit Location(const std::string& location) :
mLocation(location) {}
void setLocation(const std::string& location) { mLocation = location; }
[[nodiscard]] const std::string& getLocation() const { return mLocation; }
[[nodiscard]] bool exists() const;
};
public:
LocalConnection() = default;
virtual ~LocalConnection() {
if (mStatus.isOpened()) LocalConnection::disconnect();
}
public:
virtual bool connect(const Location& location, const Type& connectionInfo);
virtual bool disconnect();
public:
virtual const Status& getConnectionStatus() { return mStatus; }
virtual const Type& getConnectionType() { return mConnectionType; }
virtual const Location& getLocation() { return mLocation; }
public:
virtual bool setPointer(BytePointer pointer);
virtual bool readBytes(Byte* bytes, SizeBytes size);
virtual bool writeBytes(const Byte* bytes, SizeBytes size);
public:
virtual SizeBytes size();
private:
LocalConnectionContext* mHandle = nullptr;
Location mLocation;
BytePointer mPointer = 0;
};
template <bool tRead>
class ArchiverLocalConnection : public ArchiverTemplate<tRead> {
public:
ArchiverLocalConnection() = default;
protected:
void writeBytes(const int1* val, ualni size) override { connection.writeBytes(val, size); }
void readBytes(int1* val, ualni size) override { connection.readBytes(val, size); }
public:
LocalConnection connection;
};
}

View file

@ -0,0 +1,36 @@
#pragma once
#include "Module.hpp"
namespace tp {
class ServerContext;
class ClientContext;
class Server {
ServerContext* mContext;
public:
typedef void* Socket;
public:
Server();
~Server();
void start(ualni port);
Socket accept();
bool read(Socket client, int1* message, halni size);
bool write(Socket client, const int1* message, halni size);
};
class Client {
ClientContext* mContext;
public:
Client();
~Client();
bool connect(const int1* IP, ualni PORT);
bool read(int1* buff, halni size);
bool write(const int1* message, halni size);
};
}

View file

@ -0,0 +1,40 @@
#pragma once
#include "ConnectionCommon.hpp"
namespace tp {
class RemoteConnectionContext;
class RemoteConnection : public Connection {
public:
class Location {
ualni mId = 0;
public:
Location() = default;
};
public:
RemoteConnection() = default;
virtual ~RemoteConnection() {
if (mStatus.isOpened()) RemoteConnection::disconnect();
}
public:
virtual bool connect(const Location& location, const Type& connectionInfo);
virtual bool disconnect();
public:
virtual const Location& getLocation() { return mLocation; }
public:
virtual bool readBytes(Byte* bytes, SizeBytes size);
virtual bool writeBytes(const Byte* bytes, SizeBytes size);
private:
RemoteConnectionContext* mHandle = nullptr;
Location mLocation;
};
}

37
Connection/tests/Test.cpp Normal file
View file

@ -0,0 +1,37 @@
#include "ConnectionCommon.hpp"
#include "LocalConnection.hpp"
#include "UnitTest++/UnitTest++.h"
using namespace tp;
SUITE(Connection) {
TEST(LocalConnection) {
const int1* data = "abcde\0";
int1 dataRead[6]{};
{
LocalConnection file;
file.connect(LocalConnection::Location(std::string("tmp2.txt")), LocalConnection::Type(false));
file.writeBytes(data, 6);
file.disconnect();
}
{
LocalConnection file;
file.connect(LocalConnection::Location(std::string("tmp2.txt")), LocalConnection::Type(true));
file.readBytes(dataRead, 6);
file.disconnect();
}
for (auto i = 0; i < 5; i++) {
CHECK(data[i] == dataRead[i]);
}
}
}
int main() {
return UnitTest::RunAllTests();
}

View file

@ -1,8 +1,3 @@
cmake_minimum_required(VERSION 3.2)
set(CMAKE_CXX_STANDARD 23)
project(Containers)
### ---------------------- Static Library --------------------- ###
@ -10,13 +5,24 @@ file(GLOB SOURCES "./private/*.cpp")
file(GLOB HEADERS "./public/*.hpp")
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
target_include_directories(${PROJECT_NAME} PUBLIC ./private/)
target_link_libraries(${PROJECT_NAME} PUBLIC Modules)
### -------------------------- Tests -------------------------- ###
enable_testing()
file(GLOB TEST_SOURCES "./tests/*.cpp")
add_executable(${PROJECT_NAME}Tests ${TEST_SOURCES})
target_link_libraries(${PROJECT_NAME}Tests ${PROJECT_NAME} Utils)
add_test(NAME ${PROJECT_NAME}Tests COMMAND ${PROJECT_NAME}Tests)
file(GLOB TEST_SOURCES
./tests/Buffer2DTest.cpp
./tests/BufferTest.cpp
./tests/IntervalTreeTests.cpp
./tests/ListTest.cpp
./tests/MapTest.cpp
./tests/TreeTest.cpp
./tests/Tests.cpp
)
install(TARGETS ${PROJECT_NAME} LIBRARY DESTINATION ${CMAKE_INSTALL_PREFIX}/${PROJECT_NAME}/lib)
add_executable(Tests${PROJECT_NAME} ${TEST_SOURCES})
target_link_libraries(Tests${PROJECT_NAME} ${PROJECT_NAME} UnitTest++)
add_test(NAME Tests${PROJECT_NAME} COMMAND Tests${PROJECT_NAME})
add_executable(AVLTreeSpeedTest ./tests/AVLTreeProfiling.cpp)
target_link_libraries(AVLTreeSpeedTest ${PROJECT_NAME})

View file

@ -0,0 +1,407 @@
// #pragma once
// #include "Tree.hpp"
template <typename Key, typename Data, class Allocator>
tp::AvlTree<Key, Data, Allocator>::~AvlTree() {
removeAll();
}
template <typename Key, typename Data, class Allocator>
void tp::AvlTree<Key, Data, Allocator>::deleteNode(Node* node) {
node->~Node();
mAlloc.deallocate(node);
mSize--;
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::newNode(KeyArg key, DataArg data) -> Node* {
mSize++;
auto node = new (mAlloc.allocate(sizeof(Node))) Node(key, data);
node->mLeft = &gNullNode;
node->mRight = &gNullNode;
return node;
}
template <typename Key, typename Data, class Allocator>
[[nodiscard]] tp::ualni tp::AvlTree<Key, Data, Allocator>::size() const {
return mSize;
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::head() const -> Node* {
return this->mRoot;
}
template <typename Key, typename Data, class Allocator>
void tp::AvlTree<Key, Data, Allocator>::insert(KeyArg key, DataArg data) {
if (!mRoot) {
mRoot = newNode(key, data);
return;
}
if (auto parent = findInsertParent(mRoot, key)) {
restoreInvariants(insertNode(parent, key, data));
}
}
template <typename Key, typename Data, class Allocator>
void tp::AvlTree<Key, Data, Allocator>::remove(KeyArg key) {
auto node = findSubTree(mRoot, key);
if (!node) return;
if (node->mRight != &gNullNode && node->mLeft != &gNullNode) {
Node* min = minNode(node->mRight);
injectNodeInstead(node, min);
std::swap(node, min);
// auto const& newKey = min->key.getFindKey(head->mRight);
node = findSubTree(node->mRight, key);
DEBUG_ASSERT(node);
}
if (node->mRight != &gNullNode) {
if (node->mParent) {
if (node->mParent->mLeft == node) node->mParent->mLeft = node->mRight;
else node->mParent->mRight = node->mRight;
}
node->mRight->mParent = node->mParent;
auto delNode = node;
node = node->mRight;
deleteNode(delNode);
} else if (node->mLeft != &gNullNode) {
if (node->mParent) {
if (node->mParent->mLeft == node) node->mParent->mLeft = node->mLeft;
else node->mParent->mRight = node->mLeft;
}
node->mLeft->mParent = node->mParent;
auto delNode = node;
node = node->mLeft;
deleteNode(delNode);
} else {
if (node->mParent) {
if (node->mParent->mLeft == node) node->mParent->mLeft = &gNullNode;
else node->mParent->mRight = &gNullNode;
}
auto delNode = node;
node = node->mParent;
deleteNode(delNode);
}
restoreInvariants(node);
if (mRoot) mRoot->mParent = nullptr;
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::maxNode(Node* head) const -> Node* {
if (!head) return nullptr;
while (head->mRight != &gNullNode) {
head = head->mRight;
}
return head;
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::minNode(Node* head) const -> Node* {
if (!head) return nullptr;
while (head->mLeft != &gNullNode) {
head = head->mLeft;
}
return head;
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::find(KeyArg key) const -> Node* {
return findSubTree(mRoot, key);
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::findSubTree(Node* iter, KeyArg key) const -> Node* {
while (true) {
if (iter == &gNullNode) return nullptr;
if (iter->key.exactNode(key)) return iter;
if (iter->key.descentRight(key)) {
// key = iter->key.keyInRightSubtree(key);
iter = iter->mRight;
} else {
// key = iter->key.keyInLeftSubtree(key);
iter = iter->mLeft;
}
}
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::findLessOrEq(KeyArg key) const -> Node* {
Node* iter = mRoot;
while (true) {
if (iter == &gNullNode) return nullptr;
if (iter->key.exactNode(key)) return iter;
if (iter->key.descentRight(key)) {
if (iter->mRight) {
// key = iter->key.keyInRightSubtree(key);
iter = iter->mRight;
} else {
return iter;
}
} else {
if (iter->mLeft) {
// key = iter->key.keyInLeftSubtree(key);
iter = iter->mLeft;
} else {
return iter;
}
}
}
}
template <typename Key, typename Data, class Allocator>
bool tp::AvlTree<Key, Data, Allocator>::isValid() {
return findInvalidNode(head()) == nullptr;
}
template <typename Key, typename Data, class Allocator>
void tp::AvlTree<Key, Data, Allocator>::removeAll() {
if (!mRoot) return;
removeAllUtil(mRoot);
mRoot = nullptr;
mSize = 0;
}
template <typename Key, typename Data, class Allocator>
void tp::AvlTree<Key, Data, Allocator>::removeAllUtil(Node* node) {
if (node->mLeft != &gNullNode) removeAllUtil(node->mLeft);
if (node->mRight != &gNullNode) removeAllUtil(node->mRight);
deleteNode(node);
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::findInvalidNode(const Node* head) const -> const Node* {
// checks invariants of AVL tree
// returns first invalid node
if (!head || head == &gNullNode) return nullptr;
if (head->mLeft != &gNullNode) {
// TODO: incomplete test
if (head->key.descentRight(head->mLeft->key.getFindKey(head))) {
return head;
}
if (head->mLeft->mParent != head) {
return head;
}
if (!head->mRight && head->mLeft->mHeight != head->mHeight - 1) {
return head;
}
}
if (head->mRight != &gNullNode) {
if (!head->key.descentRight(head->mRight->key.getFindKey(head))) {
return head;
}
if (head->mRight->mParent != head) {
return head;
}
if (!head->mLeft && head->mRight->mHeight != head->mHeight - 1) {
return head;
}
}
if (head->mLeft != &gNullNode && head->mRight != &gNullNode) {
if (max(head->mLeft->mHeight, head->mRight->mHeight) != head->mHeight - 1) {
return head;
}
}
int balance = head->mRight->mHeight - head->mLeft->mHeight;
if (balance > 1 || balance < -1) {
return head;
}
const Node* ret = findInvalidNode(head->mRight);
if (ret) {
return ret;
}
return findInvalidNode(head->mLeft);
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::rotateLeft(Node* pivot) -> Node* {
// returns new head
DEBUG_ASSERT(pivot);
Node* const head = pivot;
Node* const right = pivot->mRight;
Node* const right_left = right->mLeft;
Node* const parent = pivot->mParent;
// parents
if (right_left != &gNullNode) right_left->mParent = head;
head->mParent = right;
right->mParent = parent;
// children
head->mRight = right_left;
right->mLeft = head;
// heights
head->mHeight = 1 + max(head->mLeft->mHeight, head->mRight->mHeight);
right->mHeight = 1 + max(right->mLeft->mHeight, right->mRight->mHeight);
// cache
head->key.updateNodeCache(head);
right->key.updateNodeCache(right);
return right;
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::rotateRight(Node* pivot) -> Node* {
// returns new head
DEBUG_ASSERT(pivot);
Node* const head = pivot;
Node* const left = pivot->mLeft;
Node* const left_right = left->mRight;
Node* const parent = pivot->mParent;
// parents
if (left_right != &gNullNode) left_right->mParent = head;
head->mParent = left;
left->mParent = parent;
// children
head->mLeft = left_right;
left->mRight = head;
// heights
head->mHeight = 1 + max(head->mLeft->mHeight, head->mRight->mHeight);
left->mHeight = 1 + max(left->mLeft->mHeight, left->mRight->mHeight);
// cache
head->key.updateNodeCache(head);
left->key.updateNodeCache(left);
return left;
}
template <typename Key, typename Data, class Allocator>
void tp::AvlTree<Key, Data, Allocator>::restoreInvariants(Node* head) {
if (!head) mRoot = nullptr;
while (head) {
Node* headParent = head->mParent;
Node** parentHeadLink = nullptr;
if (headParent) parentHeadLink = headParent->mLeft == head ? &headParent->mLeft : &headParent->mRight;
head->mHeight = 1 + max(head->mRight->mHeight, head->mLeft->mHeight);
const alni balance = head->mRight->mHeight - head->mLeft->mHeight;
if (balance < -1) {
if (head->mLeft->mLeft->mHeight >= head->mLeft->mRight->mHeight) {
head = rotateRight(head);
} else {
head->mLeft = rotateLeft(head->mLeft);
head = rotateRight(head);
}
} else if (balance > 1) {
if (head->mRight->mRight->mHeight >= head->mRight->mLeft->mHeight) {
head = rotateLeft(head);
} else {
head->mRight = rotateRight(head->mRight);
head = rotateLeft(head);
}
}
head->key.updateNodeCache(head);
if (headParent) *parentHeadLink = head;
mRoot = head;
head = headParent;
}
if (mRoot) mRoot->mParent = nullptr;
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::insertNode(Node* head, KeyArg key, DataArg data) -> Node* {
Node* insertedNode = newNode(key, data);
if (head->key.descentRight(key)) {
head->mRight = insertedNode;
} else {
head->mLeft = insertedNode;
}
insertedNode->mParent = head;
return insertedNode;
}
template <typename Key, typename Data, class Allocator>
auto tp::AvlTree<Key, Data, Allocator>::findInsertParent(Node* head, KeyArg key) -> Node* {
while (true) {
if (head->key.exactNode(key)) {
return nullptr;
}
if (head->key.descentRight(key)) {
if (head->mRight == &gNullNode) {
return head;
}
head = head->mRight;
} else {
if (head->mLeft == &gNullNode) {
return head;
}
head = head->mLeft;
}
}
}
template <typename Key, typename Data, class Allocator>
void tp::AvlTree<Key, Data, Allocator>::injectNodeInstead(Node* target, Node* from) {
// swaps pointers of two nodes to preserve data location in the memory instead of swapping data directly
// 'target' always has two nodes
// 'from' has only one child on the right on no child at all
// 'from' can be right child of the 'target'
// 'target' can or can not have parent
// 'target' can be left or right child of parent
// from is not a child of target
Node* targetParent = target->mParent;
Node* targetLeft = target->mLeft;
Node* targetRight = target->mRight;
bool special = target->mRight == from;
// update parent
if (targetParent) {
if (targetParent->mRight == target) targetParent->mRight = from;
else targetParent->mLeft = from;
}
// clone 'from' to 'target'
target->mParent = special ? from : from->mParent;
target->mLeft = &gNullNode;
target->mRight = from->mRight;
if (!special) target->mParent->mLeft = target;
// if (target->mLeft) target->mLeft->mParent = target;
if (target->mRight) target->mRight->mParent = target;
// clone 'target' to 'from'
from->mParent = targetParent;
from->mLeft = targetLeft;
from->mRight = special ? target : targetRight;
from->mLeft->mParent = from;
from->mRight->mParent = from;
std::swap(from->mHeight, target->mHeight);
}

View file

@ -4,15 +4,6 @@
#include <cstdlib>
namespace tp {
static ModuleManifest* sModuleDependencies[] = { &gModuleBase,nullptr };
ModuleManifest gModuleContainers = ModuleManifest("Containers", nullptr, nullptr, sModuleDependencies);
void* DefaultAllocator::allocate(ualni size) {
return malloc(size);
}
void DefaultAllocator::deallocate(void* p) {
free(p);
}
void* DefaultAllocator::allocate(ualni size) { return malloc(size); }
void DefaultAllocator::deallocate(void* p) { free(p); }
}

View file

@ -5,68 +5,174 @@
namespace tp {
template<ualni tScale = 2>
inline ualni BufferResizeScaling(ualni const size) { return size * tScale; }
template <ualni tScale = 2>
inline ualni BufferResizeScaling(const ualni size) {
return size * tScale;
}
template<ualni tScale = 2>
inline ualni BufferResizeScalingDown(ualni const size) { return size / tScale; }
template <ualni tScale = 2>
inline ualni BufferResizeScalingDown(const ualni size) {
return size / tScale;
}
template<ualni tAddition = 1>
inline ualni BufferResizeAddition(ualni const size) { return size + tAddition; }
template <ualni tAddition = 1>
inline ualni BufferResizeAddition(const ualni size) {
return size + tAddition;
}
template<ualni tAddition = 1>
inline ualni BufferResizeAdditionDown(ualni const size) { return size - tAddition; }
template <ualni tAddition = 1>
inline ualni BufferResizeAdditionDown(const ualni size) {
return size - tAddition;
}
template<typename tType, ualni tSize>
template <typename tType, ualni tSize>
class ConstSizeBuffer {
SelCopyArg<tType> Arg;
typedef SelectValueOrReference<tType> Arg;
private:
tType mBuff[tSize];
ualni mLoad = 0;
public:
ConstSizeBuffer() = default;
~ConstSizeBuffer() {
for (auto i = 0; i < mLoad; i++) {
mBuff[i].~tType();
}
}
public:
[[nodiscard]] ualni size() const { return tSize; }
[[nodiscard]] ualni size() const { return mLoad; }
[[nodiscard]] ualni getBuffSize() const { return tSize; }
tType& first() {
DEBUG_ASSERT(mLoad)
return *mBuff;
}
const tType& first() const {
DEBUG_ASSERT(mLoad)
return *mBuff;
}
tType& last() {
return mBuff[tSize - 1];
DEBUG_ASSERT(mLoad)
return mBuff[mLoad - 1];
}
const tType& last() const {
return mBuff[tSize - 1];
DEBUG_ASSERT(mLoad)
return mBuff[mLoad - 1];
}
tType& operator[](ualni aIdx) {
DEBUG_ASSERT(aIdx >= 0 && aIdx < tSize)
DEBUG_ASSERT(aIdx >= 0 && aIdx < mLoad)
return mBuff[aIdx];
}
const tType& operator[](ualni aIdx) const {
DEBUG_ASSERT(aIdx >= 0 && aIdx < tSize)
DEBUG_ASSERT(aIdx >= 0 && aIdx < mLoad)
return mBuff[aIdx];
}
void append(Arg data) {
ASSERT(mLoad != tSize)
new (&mBuff[mLoad]) tType(data);
mLoad++;
}
void pop() {
DEBUG_ASSERT(mLoad)
mBuff[mLoad].~tType();
mLoad--;
}
ConstSizeBuffer& operator=(const tp::InitialierList<tType>& init) {
for (auto arg : init) {
append(arg);
}
return *this;
}
void clear() {
this->~ConstSizeBuffer();
new (this) ConstSizeBuffer();
}
public:
class IteratorPointer {
protected:
tType* mIter;
public:
IteratorPointer() = default;
tType& operator->() { return *mIter; }
const tType& operator->() const { return *mIter; }
};
class IteratorReference {
protected:
tType* mIter;
public:
IteratorReference() = default;
tType* operator->() { return mIter; }
const tType* operator->() const { return mIter; }
};
class Iterator : public TypeSelect<TypeTraits<tType>::isPointer, IteratorPointer, IteratorReference>::Result {
public:
explicit Iterator(tType* iter) { this->mIter = iter; }
const Iterator& operator*() const { return *this; }
Iterator& operator++() {
this->mIter++;
return *this;
}
bool operator==(const Iterator& left) const { return left.mIter == this->mIter; }
bool operator!=(const Iterator& left) const { return left.mIter != this->mIter; }
};
[[nodiscard]] Iterator begin() const { return Iterator(mBuff); }
[[nodiscard]] Iterator end() const { return Iterator(mBuff + mLoad); }
public:
template <class tArchiver>
void archiveWrite(tArchiver& ar) const {
ar << mLoad;
for (auto item : *this) {
ar << item.data();
}
}
template <class tArchiver>
void archiveRead(tArchiver& ar) {
clear();
ar >> mLoad;
for (auto i = 0; i < mLoad; i++) {
ar >> mBuff[i];
}
}
};
template<
template <
typename tType,
class tAllocator = DefaultAllocator,
ualni (tResizePolicy)(ualni) = BufferResizeScaling<2>,
ualni (tResizePolicyDown)(ualni) = BufferResizeScalingDown<2>,
ualni tMinSize = 4
>
ualni(tResizePolicy)(ualni) = BufferResizeScaling<2>,
ualni(tResizePolicyDown)(ualni) = BufferResizeScalingDown<2>,
ualni tMinSize = 4>
class Buffer {
typedef SelCopyArg<tType> Arg;
typedef SelectValueOrReference<tType> Arg;
private:
tType* mBuff;
@ -75,39 +181,72 @@ namespace tp {
ualni mLoad;
public:
Buffer() : mSize(tMinSize), mLoad(0) {
Buffer() :
mSize(tMinSize),
mLoad(0) {
mBuff = (tType*) mAllocator.allocate(sizeof(tType) * tMinSize);
}
explicit Buffer(ualni size) : mSize(size), mLoad(0) {
mBuff = (tType*) mAllocator.allocate(sizeof(tType) * tMinSize);
Buffer(const InitialierList<tType>& input) {
mSize = 0;
for (const auto& val : input) {
mSize++;
}
Buffer(const Buffer& in) : mSize(in.mSize), mLoad(in.mLoad) {
mBuff = (tType*) mAllocator.allocate(sizeof(tType) * mSize);
for (ualni i = 0; i < mLoad; i++) new (&mBuff[i]) tType(in.mBuff[i]);
mLoad = 0;
for (const auto& val : input) {
mBuff[mLoad] = val;
mLoad++;
}
}
explicit Buffer(ualni size) {
mBuff = (tType*) mAllocator.allocate(sizeof(tType) * size);
mSize = size;
mLoad = size;
for (ualni i = 0; i < mLoad; i++) {
new (mBuff + i) tType();
}
}
Buffer(const Buffer& in) :
mSize(in.mSize),
mLoad(in.mLoad) {
mBuff = (tType*) mAllocator.allocate(sizeof(tType) * mSize);
for (ualni i = 0; i < mLoad; i++) {
new (&mBuff[i]) tType(in.mBuff[i]);
}
}
void clear() {
this->~Buffer();
new (this) Buffer();
}
Buffer& operator=(const Buffer& in) {
if (this == &in) return *this;
if (this == &in) {
return *this;
}
this->~Buffer();
new (this) Buffer(in);
return *this;
}
~Buffer() {
for (ualni i = 0; i < mLoad; i++) mBuff[i].~tType();
for (ualni i = 0; i < mLoad; i++) {
mBuff[i].~tType();
}
mAllocator.deallocate(mBuff);
}
public:
[[nodiscard]] ualni size() const {
return mLoad;
}
[[nodiscard]] ualni size() const { return mLoad; }
[[nodiscard]] ualni getBuffSize() const {
return mSize;
}
[[nodiscard]] ualni getBuffSize() const { return mSize; }
[[nodiscard]] const tType* getBuff() const { return mBuff; }
[[nodiscard]] tType* getBuff() { return mBuff; }
tType& first() {
DEBUG_ASSERT(mLoad)
@ -141,28 +280,67 @@ namespace tp {
public:
bool operator==(const Buffer& in) const {
if (this == &in) return true;
if (mLoad != in.mLoad) return false;
if (this == &in) {
return true;
}
if (mLoad != in.mLoad) {
return false;
}
for (ualni i = 0; i < mLoad; i++) {
if (mBuff[i] != in.mBuff[i]) return false;
if (mBuff[i] != in.mBuff[i]) {
return false;
}
}
return true;
}
public:
void append(Arg data) {
if (mLoad == mSize) resizeBuffer(tResizePolicy(mSize));
new (&mBuff[mLoad]) tType(data);
Buffer& operator=(const tp::InitialierList<tType>& input) {
// TODO : optimize
for (ualni i = 0; i < mLoad; i++) {
mBuff[i].~tType();
}
mAllocator.deallocate(mBuff);
mSize = 0;
for (const auto& val : input) {
mSize++;
}
mBuff = (tType*) mAllocator.allocate(sizeof(tType) * mSize);
mLoad = 0;
for (const auto& val : input) {
new (&mBuff[mLoad]) tType(val);
mLoad++;
}
return *this;
}
tType& append(Arg data) {
if (mLoad == mSize) {
resizeBuffer(tResizePolicy(mSize));
}
new (&mBuff[mLoad]) tType(data);
mLoad++;
return mBuff[mLoad - 1];
}
void append(const Buffer& in) {
if (!in.mLoad) return;
if (!in.mLoad) {
return;
}
auto newLoad = mLoad + in.mLoad;
auto newSize = mSize;
while (newLoad >= newSize) newSize = tResizePolicy(newSize);
if (newSize != mSize) resizeBuffer(newSize);
for (auto i = mLoad; i < newLoad; i++) new (&mBuff[i]) tType(in.mBuff[i - mLoad]);
while (newLoad >= newSize) {
newSize = tResizePolicy(newSize);
}
if (newSize != mSize) {
resizeBuffer(newSize);
}
for (auto i = mLoad; i < newLoad; i++) {
new (&mBuff[i]) tType(in.mBuff[i - mLoad]);
}
mLoad = newLoad;
}
@ -172,19 +350,146 @@ namespace tp {
mLoad--;
ualni prevSize = tResizePolicyDown(mSize);
DEBUG_ASSERT(prevSize < mSize)
if (prevSize > mLoad) resizeBuffer(prevSize);
if (prevSize > mLoad) {
resizeBuffer(prevSize);
}
}
void reserve(ualni aSize) {
for (ualni i = 0; i < mLoad; i++) {
mBuff[i].~tType();
}
mAllocator.deallocate(mBuff);
mBuff = (tType*) mAllocator.allocate(sizeof(tType) * aSize);
mSize = aSize;
mLoad = aSize;
for (ualni i = 0; i < mLoad; i++) {
new (mBuff + i) tType();
}
}
public:
class IteratorPointer {
protected:
tType* mIter;
public:
IteratorPointer() = default;
tType& operator->() { return *mIter; }
const tType& operator->() const { return *mIter; }
};
class IteratorReference {
protected:
tType* mIter;
public:
IteratorReference() = default;
tType* operator->() { return mIter; }
const tType* operator->() const { return mIter; }
};
class Iterator : public TypeSelect<TypeTraits<tType>::isPointer, IteratorPointer, IteratorReference>::Result {
public:
explicit Iterator(tType* iter) { this->mIter = iter; }
const Iterator& operator*() const { return *this; }
tType& data() { return *this->mIter; }
Iterator& operator++() {
this->mIter++;
return *this;
}
bool operator==(const Iterator& left) const { return left.mIter == this->mIter; }
bool operator!=(const Iterator& left) const { return left.mIter != this->mIter; }
};
[[nodiscard]] Iterator begin() const { return Iterator(mBuff); }
[[nodiscard]] Iterator end() const { return Iterator(mBuff + mLoad); }
public:
template <class tArchiver>
void archiveWrite(tArchiver& ar) const {
ar << mLoad;
for (auto item : *this) {
ar % item.data();
}
}
template <class tArchiver>
void archiveRead(tArchiver& ar) {
clear();
decltype(mLoad) len;
ar >> len;
for (auto i = len; i; i--) {
// TODO : optimize
if (mLoad == mSize) {
resizeBuffer(tResizePolicy(mSize));
}
new (mBuff + mLoad) tType();
ar % mBuff[mLoad];
mLoad++;
}
}
private:
void resizeBuffer(ualni newSize) {
DEBUG_ASSERT(newSize >= mLoad)
auto const oldBuff = mBuff;
const auto oldBuff = mBuff;
mBuff = (tType*) mAllocator.allocate(sizeof(tType) * newSize);
for (ualni i = 0; i < mLoad; i++) new (&mBuff[i]) tType(oldBuff[i]);
for (ualni i = 0; i < mLoad; i++) oldBuff[i].~tType();
for (ualni i = 0; i < mLoad; i++) {
new (&mBuff[i]) tType(oldBuff[i]);
}
for (ualni i = 0; i < mLoad; i++) {
oldBuff[i].~tType();
}
mAllocator.deallocate(oldBuff);
mSize = newSize;
}
};
template <typename tType>
void generatePermutations(const Buffer<Buffer<tType>>& in, Buffer<Buffer<tType>>& out) {
typedef long long Idx;
// sanity check
for (const auto& vec : in) {
if (!vec.size()) {
return;
}
}
out.resize(in.size());
auto len = Idx(1);
for (const auto& vec : in) {
len *= (Idx) vec.size();
}
for (auto i = 0; i < in.size(); i++) {
out[i].resize(len);
}
auto dub = Idx(1);
for (auto power = (Idx) in.size() - 1; power >= 0; power--) {
auto& vec = in[power];
long long i = 0;
while (i < len) {
for (auto val : vec) {
for (auto j = 0; j < dub; j++) {
out[power][i] = val;
i++;
}
}
}
dub *= (Idx) vec.size();
}
}
}

View file

@ -0,0 +1,149 @@
#pragma once
#include "Buffer.hpp"
#include "Utils.hpp"
namespace tp {
template <typename tType, ualni tSizeX, ualni tSizeY>
using ConstSizeBuffer2D = ConstSizeBuffer<ConstSizeBuffer<tType, tSizeX>, tSizeY>;
typedef ualni Index;
struct Index2D {
Index x = 0;
Index y = 0;
};
template <typename tType, class tAllocator = DefaultAllocator>
class Buffer2D {
public:
typedef SelectValueOrReference<tType> tTypeArg;
private:
tAllocator mAlloc;
tType* mBuff = nullptr;
Index2D mSize = { 0, 0 };
void deleteBuffer() {
if (!mBuff) {
return;
}
for (ualni i = 0; i < mSize.x * mSize.y; i++) {
mBuff[i].~tType();
}
mAlloc.deallocate(mBuff);
}
void allocateBuffer(Index2D size) {
deleteBuffer();
mBuff = (tType*) mAlloc.allocate(sizeof(tType) * size.x * size.y);
for (ualni i = 0; i < size.x * size.y; i++) {
new (mBuff + i) tType();
}
}
public:
Buffer2D() = default;
~Buffer2D() {
deleteBuffer();
mSize = { 0, 0 };
}
explicit Buffer2D(Index2D aSize) { reserve(aSize); }
[[nodiscard]] Index2D size() const { return { mSize.x, mSize.y }; }
tType* getBuff() const { return mBuff; }
void flipY() {
for (Index i = 0; i < mSize.x; i++) {
const auto lenIdx = mSize.y - 1;
for (Index j = 0; j < mSize.y / 2; j++) {
swap(get({i, j}), get({i, lenIdx - j}));
}
}
}
void flipX() {
for (Index i = 0; i < mSize.y; i++) {
const auto lenIdx = mSize.x - 1;
for (Index j = 0; j < mSize.x / 2; j++) {
swap(get({i, j}), get({i, lenIdx - j}));
}
}
}
inline tType& get(const Index2D& at) {
DEBUG_ASSERT(mBuff && at.x < mSize.x && at.y < mSize.y && at.x >= 0 && at.y >= 0)
return *(mBuff + mSize.x * at.y + at.x);
}
inline const tType& get(const Index2D& at) const {
DEBUG_ASSERT(mBuff && at.x < mSize.x && at.y < mSize.y && at.x >= 0 && at.y >= 0)
return *(mBuff + mSize.x * at.y + at.x);
}
inline void set(const Index2D& at, tTypeArg value) {
DEBUG_ASSERT(mBuff && at.x < mSize.x && at.y < mSize.y && at.x >= 0 && at.y >= 0)
*(mBuff + mSize.x * at.y + at.x) = value;
}
void reserve(const Index2D& newSize) {
if (mSize.x != newSize.x || mSize.y != newSize.y) {
allocateBuffer(newSize);
mSize = newSize;
}
}
void assign(tType value) {
DEBUG_ASSERT(mBuff);
Index len = mSize.x * mSize.y;
for (Index i = 0; i < len; i++) {
mBuff[i] = value;
}
}
bool operator==(const Buffer2D& in) const {
if (&in == this) {
return true;
}
if (in.size() != size()) {
return false;
}
for (auto i = 0; i < mSize.x * mSize.y; i++) {
if (mBuff[i] != in.mBuff[i]) {
return false;
}
}
return true;
}
public:
template <class tArchiver>
void archiveWrite(tArchiver& ar) const {
ar << mSize;
for (auto i = 0; i < mSize.x; i++) {
for (auto j = 0; j < mSize.y; j++) {
ar << get(i, j);
}
}
}
template <class tArchiver>
void archiveRead(tArchiver& ar) {
decltype(mSize) size;
deleteBuffer();
ar >> size;
reserve(size);
for (auto i = 0; i < mSize.x; i++) {
for (auto j = 0; j < mSize.y; j++) {
ar >> get(i, j);
}
}
}
};
}

View file

@ -4,23 +4,22 @@
#include "Module.hpp"
namespace tp {
extern ModuleManifest gModuleContainers;
class DefaultAllocator {
public:
DefaultAllocator() = default;
static void *allocate(ualni);
static void deallocate(void *);
static void* allocate(ualni);
static void deallocate(void*);
};
class DefaultSaverLoader {
public:
DefaultSaverLoader() = default;
template<typename Type>
template <typename Type>
static void write(const Type&) {}
template<typename Type>
template <typename Type>
static void read(Type&) {}
};
}

View file

@ -0,0 +1,87 @@
#pragma once
#include "Tree.hpp"
namespace tp {
template <typename tType>
class IntervalKey {
public:
IntervalKey() = default;
IntervalKey(tType start, tType end) {
mStart = start;
mEnd = end;
}
inline bool descentRight(const IntervalKey& in) const {
if (in.mStart != mStart) return in.mStart > mStart;
return in.mEnd > mEnd;
}
inline bool exactNode(const IntervalKey& in) const { return in.mStart == mStart && in.mEnd == mEnd; }
template <typename tTreeNodeType>
inline const IntervalKey& getFindKey(const tTreeNodeType* node) const {
return *this;
}
inline const IntervalKey& keyInRightSubtree(const IntervalKey& in) const { return in; }
inline const IntervalKey& keyInLeftSubtree(const IntervalKey& in) const { return in; }
template <typename tTreeNodeType>
inline void updateNodeCache(const tTreeNodeType* node) {
mMax = 0;
if (node->mRight && node->mRight->key.mMax > mMax) mMax = node->mRight->key.mMax;
if (node->mLeft && node->mLeft->key.mMax > mMax) mMax = node->mLeft->key.mMax;
if (mMax < mEnd) mMax = mEnd;
}
public:
tType mStart = tType();
tType mEnd = tType();
tType mMax = tType();
};
template <typename tType, typename tData>
class IntervalTree : public AvlTree<IntervalKey<tType>, tData> {
typedef typename AvlTree<IntervalKey<tType>, tData>::Node Node;
public:
IntervalTree() = default;
template <typename tFunctor>
ualni forEachIntersection(tType start, tType end, tFunctor functor) const {
ualni debug = 0;
forEachIntersectionUtil(this->head(), start, end, functor, debug);
return debug;
}
private:
template <typename tFunctor>
void forEachIntersectionUtil(const Node* node, tType start, tType end, tFunctor functor, ualni& debug) const {
if (node->mHeight == -1) return; // sentinel node (null node)
debug++;
// If 'start' is to the right of the rightmost point of any interval
// in this node and all children, there won't be any matches.
if (start > node->key.mMax) return;
// Search left children
forEachIntersectionUtil(node->mLeft, start, end, functor, debug);
// Check this node
if (start <= node->key.mEnd && end >= node->key.mStart) {
functor(node->key.mStart, node->key.mEnd, node->data);
}
// If end is to the left of the start of this interval,
// then it can't be in any child to the right.
if (end < node->key.mStart) return;
// Otherwise, search right children
forEachIntersectionUtil(node->mRight, start, end, functor, debug);
}
};
}

View file

@ -10,23 +10,24 @@ namespace tp {
template <typename Type, class Allocator = DefaultAllocator>
class List {
typedef SelCopyArg<Type> TypeArg;
typedef SelectValueOrReference<Type> TypeArg;
typedef ualni Index;
public:
struct Node {
Type data;
Node* next = nullptr;
Node* prev = nullptr;
Node() = default;
explicit Node(TypeArg p_data) : data(p_data) {}
Node() { data = Type(); }
explicit Node(TypeArg p_data) :
data(p_data) {}
Type& operator->() { return data; }
};
class IteratorPointer {
protected:
Node* mIter;
public:
IteratorPointer() = default;
Type& operator->() { return (mIter->data); }
@ -36,6 +37,7 @@ namespace tp {
class IteratorReference {
protected:
Node* mIter;
public:
IteratorReference() = default;
Type* operator->() { return &(mIter->data); }
@ -44,7 +46,6 @@ namespace tp {
class Iterator : public TypeSelect<TypeTraits<Type>::isPointer, IteratorPointer, IteratorReference>::Result {
public:
explicit Iterator(Node* iter) { this->mIter = iter; }
Node* node() { return this->mIter; }
@ -70,14 +71,16 @@ namespace tp {
Allocator mAlloc;
public:
List() = default;
List(const List& in) { this->operator=(in); }
List(const InitialierList<Type>& list) { operator=(list); }
List(const init_list<Type>& list) { operator=(list); }
[[nodiscard]] inline Node* first() const { return mFirst; }
[[nodiscard]] inline Node* last() const { return mLast; }
[[nodiscard]] inline Type& first() const { return mFirst->data; }
[[nodiscard]] inline Type& last() const { return mLast->data; }
[[nodiscard]] inline Node* firstNode() const { return mFirst; }
[[nodiscard]] inline Node* lastNode() const { return mLast; }
[[nodiscard]] inline Index length() const { return mLength; }
[[nodiscard]] inline Index size() const { return length(); }
[[nodiscard]] Node* newNode() { return new (mAlloc.allocate(sizeof(Node))) Node(); }
[[nodiscard]] Node* newNode(TypeArg arg) { return new (mAlloc.allocate(sizeof(Node))) Node(arg); }
@ -107,6 +110,7 @@ namespace tp {
}
void attach(Node* node, Node* node_to) {
node->next = node->prev = nullptr;
if (node_to) {
if (node_to->next) {
node->next = node_to->next;
@ -146,7 +150,7 @@ namespace tp {
}
[[nodiscard]] Node* findIdx(Index idx) const {
DEBUG_ASSERT(!mFirst || idx > mLength - 1)
DEBUG_ASSERT(mFirst && idx < mLength && idx >= 0)
Node* found = mFirst;
for (int i = 0; i != idx; i++) {
found = found->next;
@ -157,6 +161,7 @@ namespace tp {
[[nodiscard]] Node* find(const TypeArg data) const {
Node* found = mFirst;
for (alni i = 0; data != found->data; i++) {
if (i == length()) return nullptr;
if (!found->next) {
return nullptr;
}
@ -177,8 +182,9 @@ namespace tp {
void popBack() {
DEBUG_ASSERT(mLast)
auto const tmp = mLast;
detach(mLast);
deleteNode(mLast);
deleteNode(tmp);
}
void popFront() {
@ -198,11 +204,10 @@ namespace tp {
}
}
void insert(TypeArg data, Index idx) {
insert(newNode(data), idx);
}
void insert(TypeArg data, Index idx) { insert(newNode(data), idx); }
void removeNode(Node* node) {
if (!node) return;
detach(node);
deleteNode(node);
}
@ -221,7 +226,7 @@ namespace tp {
return *this;
}
List& operator+=(const init_list<Type>& list) {
List& operator+=(const InitialierList<Type>& list) {
for (auto item : list) {
pushBack(item);
}
@ -229,29 +234,35 @@ namespace tp {
}
List& operator=(const List& in) {
if (this == &in) { return *this; }
if (this == &in) {
return *this;
}
removeAll();
(*this) += in;
return *this;
}
List& operator=(const init_list<Type>& list) {
List& operator=(const InitialierList<Type>& list) {
removeAll();
*this += list;
return *this;
}
[[nodiscard]] bool operator==(const List& in) const {
if (in == *this) { return true; }
if (&in == this) {
return true;
}
if (in.length() != length()) {
return false;
}
Node* left = in.first();
Node* right = first();
Node* left = in.firstNode();
Node* right = firstNode();
while (left && right) {
if (left->data != right->data) {
return false;
}
left = left->next;
right = right->next;
}
if (left != right) {
return false;
@ -274,9 +285,7 @@ namespace tp {
return out;
}
[[nodiscard]] Iterator end() const {
return Iterator(nullptr);
}
[[nodiscard]] Iterator end() const { return Iterator(nullptr); }
void invert() {
Node* iter = mFirst;
@ -295,28 +304,35 @@ namespace tp {
}
}
template<class Saver>
void write(Saver& file) const {
file.write(mLength);
void transferNodes(List in) {
removeAll();
for (auto node : in) {
attach(node);
}
in.detachAll();
}
public:
template <class tArchiver>
void archiveWrite(tArchiver& ar) const {
ar << mLength;
for (auto item : *this) {
file.write(item.data());
ar << item.data();
}
}
template<class Loader>
void read(Loader& file) {
template <class tArchiver>
void archiveRead(tArchiver& ar) {
removeAll();
ualni len;
file.read(len);
decltype(mLength) len;
ar >> len;
for (auto i = len; i; i--) {
auto node = newNodeNotConstructed();
file.read(node->data);
ar >> node->data;
pushBack(node);
}
}
~List() {
removeAll();
}
~List() { removeAll(); }
};
}

View file

@ -1,17 +1,22 @@
#pragma once
#include "ContainersCommon.hpp"
#include "Common.hpp"
#include "ContainersCommon.hpp"
namespace tp {
template<typename Key>
ualni DefaultHashFunc(SelCopyArg<Key> key) {
template <typename Key>
ualni DefaultHashFunc(SelectValueOrReference<Key> key) {
return hash(key);
}
template<typename tKey, typename tVal, class tAllocator = DefaultAllocator, ualni(*tHashFunc)(SelCopyArg<tKey>) = DefaultHashFunc<tKey>, int tTableInitialSize = 4>
template <
typename tKey,
typename tVal,
class tAllocator = DefaultAllocator,
ualni (*tHashFunc)(SelectValueOrReference<tKey>) = DefaultHashFunc<tKey>,
int tTableInitialSize = 4>
class Map {
enum {
@ -20,14 +25,16 @@ namespace tp {
MAP_MAX_LOAD_PERCENTAGE = 66,
};
typedef SelCopyArg<tKey> KeyArg;
typedef SelCopyArg<tVal> ValArg;
typedef SelectValueOrReference<tKey> KeyArg;
typedef SelectValueOrReference<tVal> ValArg;
public:
class Node {
friend Map;
Node(KeyArg aKey, ValArg aVal) : key(aKey), val(aVal) {}
Node(KeyArg aKey, ValArg aVal) :
key(aKey),
val(aVal) {}
public:
tKey key;
tVal val;
@ -35,53 +42,41 @@ namespace tp {
struct Idx {
alni idx = -1;
operator bool() { return idx != -1; }
[[nodiscard]] bool isValid() const { return bool(*this); }
explicit operator bool() const { return idx != -1; }
};
private:
tAllocator mAlloc;
Node** mTable;
Node** mTable = nullptr;
ualni mNSlots = 0;
ualni mNEntries = 0;
private:
constexpr halnf maxLoadFactor() { return halnf(MAP_MAX_LOAD_PERCENTAGE) / 100.f; }
inline Node** newTable(const ualni len) {
return new(mAlloc.allocate(sizeof(Node*) * len)) Node*[len]();
}
inline Node** newTable(const ualni len) { return new (mAlloc.allocate(sizeof(Node*) * len)) Node*[len](); }
inline Node* newNode(KeyArg key, ValArg val) {
return new(mAlloc.allocate(sizeof(Node))) Node(key, val);
}
inline Node* newNode(KeyArg key, ValArg val) { return new (mAlloc.allocate(sizeof(Node))) Node(key, val); }
inline Node* newNodeNotConstructed() {
return (Node*) mAlloc.allocate(sizeof(Node));
}
inline Node* newNodeNotConstructed() { return (Node*) mAlloc.allocate(sizeof(Node)); }
inline void deleteTable(Node** table) {
mAlloc.deallocate(table);
}
inline void deleteTable(Node** table) { mAlloc.deallocate(table); }
inline void deleteNode(Node* p) {
p->~Node();
mAlloc.deallocate(p);
}
void markDeletedSlot(ualni idx) const {
mTable[idx] = (Node*)-1;
}
void markDeletedSlot(ualni idx) const { mTable[idx] = (Node*) -1; }
static bool isDeletedNode(Node* node) {
return node == (Node*)-1;
}
static bool isDeletedNode(Node* node) { return node == (Node*) -1; }
void rehash() {
alni nSlotsOld = mNSlots;
Node** tableOld = mTable;
mNSlots = next2pow((uhalni)((1.f / (maxLoadFactor())) * mNEntries + 1));
mNSlots = next2pow((uhalni) ((1.f / (maxLoadFactor())) * mNEntries + 1));
mTable = newTable(mNSlots);
mNEntries = 0;
@ -167,42 +162,35 @@ namespace tp {
mTable[idx] = node;
if ((halnf)mNEntries / mNSlots > maxLoadFactor()) {
if ((halnf) mNEntries / mNSlots > maxLoadFactor()) {
rehash();
}
}
public:
Map() {
MODULE_SANITY_CHECK(gModuleContainers)
mNSlots = next2pow(uhalni(tTableInitialSize - 1));
mTable = newTable(mNSlots);
}
Node** buff() const {
return mTable;
}
Map(const Map& in) { this->operator=(in); }
[[nodiscard]] ualni size() const {
return mNEntries;
}
Node** buff() const { return mTable; }
[[nodiscard]] ualni slotsSize() const {
return mNEntries;
}
[[nodiscard]] ualni size() const { return mNEntries; }
[[nodiscard]] const tAllocator& getAllocator() const {
return mAlloc;
}
[[nodiscard]] ualni slotsSize() const { return mNEntries; }
[[nodiscard]] const tAllocator& getAllocator() const { return mAlloc; }
void put(KeyArg key, ValArg val) {
const ualni idx = findSlotWrite(key);
if (!mTable[idx] || isDeletedNode(mTable[idx])) {
mTable[idx] = newNode(key, val);
mNEntries++;
}
} else {
mTable[idx]->val = val;
}
if ((halnf) mNEntries / mNSlots > maxLoadFactor()) {
rehash();
}
@ -240,6 +228,13 @@ namespace tp {
return mTable[slot]->val;
}
tVal& operator[](KeyArg key) {
auto idx = presents(key);
if (idx.isValid()) return getSlotVal(idx);
put(key, {});
return get(key);
}
tVal& getSlotVal(ualni slot) {
DEBUG_ASSERT(slot < mNSlots && (mTable[slot] && !isDeletedNode(mTable[slot])) && "Key Error")
return mTable[slot]->val;
@ -247,7 +242,7 @@ namespace tp {
const tVal& getSlotVal(Idx slot) const {
DEBUG_ASSERT(slot.idx < mNSlots && (mTable[slot.idx] && !isDeletedNode(mTable[slot.idx])) && "Key Error")
return mTable[slot]->val;
return mTable[slot.idx]->val;
}
tVal& getSlotVal(Idx slot) {
@ -259,8 +254,15 @@ namespace tp {
if (this == &in) {
return *this;
}
removeAll();
for (ualni i = 0; i < mNSlots; i++) {
if (mTable[i] && !isDeletedNode(mTable[i])) {
deleteNode(mTable[i]);
}
}
mNEntries = 0;
mNSlots = in.mNSlots;
deleteTable(mTable);
mTable = newTable(mNSlots);
for (alni i = 0; i < mNSlots; i++) {
if (in.mTable[i] && !isDeletedNode(in.mTable[i])) {
@ -323,7 +325,6 @@ namespace tp {
}
public:
class Iterator {
const Map* map;
Node* mIter;
@ -347,7 +348,7 @@ namespace tp {
void operator++() {
mSlot++;
while ((map->isDeletedNode(map->mTable[mSlot]) || !map->mTable[mSlot]) && (mSlot != map->mNSlots)) {
while ((map->isDeletedNode(map->mTable[mSlot]) || !map->mTable[mSlot]) && (mSlot != (map->mNSlots - 1))) {
mSlot++;
}
if (mSlot != map->mNSlots) {
@ -357,36 +358,39 @@ namespace tp {
}
};
[[nodiscard]] Iterator begin() const {
return Iterator(this);
}
[[nodiscard]] Iterator begin() const { return Iterator(this); }
[[nodiscard]] ualni end() const {
return mNSlots;
}
[[nodiscard]] ualni end() const { return mNSlots - 1; }
template<class Saver>
void write(Saver& file) {
file.write(mNEntries);
template <class Archiver>
void archiveWrite(Archiver& ar) const {
ar << mNEntries;
for (auto item : *this) {
file.write(item->val);
file.write(item->key);
ar << item->val;
ar << item->key;
}
}
template<class Loader>
void read(Loader& file) {
template <class Archiver>
void archiveRead(Archiver& ar) {
removeAll();
ualni len;
file.read(len);
decltype(mNSlots) len;
ar >> len;
for (auto i = len; i; i--) {
auto node = newNodeNotConstructed();
file.read(node->val);
file.read(node->key);
ar >> node->val;
ar >> node->key;
put(node);
}
}
~Map() { removeAll(); }
~Map() {
for (ualni i = 0; i < mNSlots; i++) {
if (mTable[i] && !isDeletedNode(mTable[i])) {
deleteNode(mTable[i]);
}
}
deleteTable(mTable);
}
};
}

View file

@ -6,368 +6,112 @@ namespace tp {
template <typename NumericType>
struct AvlNumericKey {
NumericType val;
public:
AvlNumericKey() = default;
AvlNumericKey(NumericType val) : val(val) {}
AvlNumericKey(NumericType val) :
val(val) {}
inline bool descentRight(AvlNumericKey in) const { return in.val > val; }
inline bool descentLeft(AvlNumericKey in) const { return in.val < val; }
inline bool exactNode(AvlNumericKey in) const { return in.val == val; }
inline bool descentRight(const AvlNumericKey& in) const { return in.val > val; }
inline bool exactNode(const AvlNumericKey& in) const { return in.val == val; }
inline AvlNumericKey getFindKey(/**/) const { return *this; }
inline AvlNumericKey keyInRightSubtree(AvlNumericKey in) const { return in; }
inline AvlNumericKey keyInLeftSubtree(AvlNumericKey in) const { return in; }
inline const AvlNumericKey& keyInRightSubtree(const AvlNumericKey& in) const { return in; }
inline const AvlNumericKey& keyInLeftSubtree(const AvlNumericKey& in) const { return in; }
inline void updateTreeCacheCallBack() {}
template <typename NodeType>
inline void updateNodeCache(const NodeType*) {}
template <typename NodeType>
inline const AvlNumericKey& getFindKey(const NodeType*) const {
return *this;
}
public:
NumericType val;
};
template <typename Key, typename Data, class Allocator = DefaultAllocator>
class AvlTree {
typedef SelCopyArg<Key> KeyArg;
typedef SelCopyArg<Data> DataArg;
typedef SelectValueOrReference<Key> KeyArg;
typedef SelectValueOrReference<Data> DataArg;
public:
class Node {
friend AvlTree;
public:
Node() = default;
private:
Node(KeyArg aKey, DataArg aData) : key(aKey), data(aData) {}
Node(KeyArg aKey, DataArg aData) :
key(aKey),
data(aData) {}
public:
Data data;
Key key;
alni mHeight = -1;
private:
Node* mLeft = nullptr;
Node* mRight = nullptr;
Node* mParent = nullptr;
ualni mHeight = 0;
Data data;
Key key;
};
public:
AvlTree() = default;
~AvlTree();
ualni size() const;
Node* head() const;
void insert(KeyArg key, DataArg data);
void remove(KeyArg key);
void removeAll();
Node* maxNode(Node* head) const;
Node* minNode(Node* head) const;
Node* find(KeyArg key) const;
Node* findSubTree(Node* iter, KeyArg key) const;
Node* findLessOrEq(KeyArg key) const;
template <typename tFunctor>
void traverse(Node* node, bool after, tFunctor functor) {
if (!after) functor(node);
if (node->mLeft) traverse(node->mLeft, after, functor);
if (node->mRight) traverse(node->mRight, after, functor);
if (after) functor(node);
}
auto findInvalidNode(const Node* head) const -> const Node*;
bool isValid();
private:
inline bool descentRight(KeyArg aKey) const { return key.descentRight(aKey); }
inline bool descentLeft(KeyArg aKey) const { return key.descentLeft(aKey); }
inline bool exactNode(KeyArg aKey) const { return key.exactNode(aKey); }
inline void deleteNode(Node* node);
inline auto newNode(KeyArg key, DataArg data) -> Node*;
inline KeyArg getFindKey(const Node* node = nullptr) const { return key.getFindKey(/*node*/); }
inline KeyArg keyInRightSubtree(KeyArg aKey) const { return key.keyInRightSubtree(aKey); }
inline KeyArg keyInLeftSubtree(KeyArg aKey) const { return key.keyInLeftSubtree(aKey); }
inline auto rotateLeft(Node* pivot) -> Node*;
inline auto rotateRight(Node* pivot) -> Node*;
inline void updateTreeCacheCallBack() { key.updateTreeCacheCallBack(); }
};
inline void restoreInvariants(Node* head);
inline auto insertNode(Node* head, KeyArg key, DataArg data) -> Node*;
inline auto findInsertParent(Node* head, KeyArg key) -> Node*;
inline void injectNodeInstead(Node* target, Node* from);
void removeAllUtil(Node* node);
private:
Node* mRoot = nullptr;
ualni mSize = 0;
Allocator mAlloc;
private:
inline void deleteNode(Node* node) {
node->~Node();
mAlloc.deallocate(node);
}
inline Node* newNode(KeyArg key, DataArg data) {
return new (mAlloc.allocate(sizeof(Node))) Node(key, data);
}
inline void injectNodeInstead(Node* place, Node* inject) {
// TODO : swap instead of copy
place->data = inject->data;
place->key = inject->key;
}
inline alni getNodeHeight(const Node* node) const {
return node ? node->mHeight : -1;
}
// returns new head
Node* rotateLeft(Node* pivot) {
DEBUG_ASSERT(pivot);
Node* const head = pivot;
Node* const right = pivot->mRight;
Node* const right_left = right->mLeft;
Node* const parent = pivot->mParent;
// parents
if (right_left) right_left->mParent = head;
head->mParent = right;
right->mParent = parent;
// children
head->mRight = right_left;
right->mLeft = head;
// heights
head->mHeight = 1 + max(getNodeHeight(head->mLeft), getNodeHeight(head->mRight));
right->mHeight = 1 + max(getNodeHeight(right->mLeft), getNodeHeight(right->mRight));
// cache
head->updateTreeCacheCallBack();
right->updateTreeCacheCallBack();
return right;
}
Node* rotateRight(Node* pivot) {
DEBUG_ASSERT(pivot);
Node* const head = pivot;
Node* const left = pivot->mLeft;
Node* const left_right = left->mRight;
Node* const parent = pivot->mParent;
// parents
if (left_right) left_right->mParent = head;
head->mParent = left;
left->mParent = parent;
// children
head->mLeft = left_right;
left->mRight = head;
// heights
head->mHeight = 1 + max(getNodeHeight(head->mLeft), getNodeHeight(head->mRight));
left->mHeight = 1 + max(getNodeHeight(left->mLeft), getNodeHeight(left->mRight));
// cache
head->updateTreeCacheCallBack();
left->updateTreeCacheCallBack();
return left;
}
// recursively returns valid isLeft or isRight child or root
Node* insertUtil(Node* head, KeyArg key, DataArg data) {
Node* insertedNode;
if (head == nullptr) {
mSize++;
Node* out = newNode(key, data);
out->updateTreeCacheCallBack();
return out;
}
else if (head->exactNode(key)) {
return head;
}
else if (head->descentRight(key)) {
insertedNode = insertUtil(head->mRight, head->keyInRightSubtree(key), data);
head->mRight = insertedNode;
insertedNode->mParent = head;
}
else {
insertedNode = insertUtil(head->mLeft, head->keyInLeftSubtree(key), data);
head->mLeft = insertedNode;
insertedNode->mParent = head;
}
// update height
head->mHeight = 1 + max(getNodeHeight(head->mRight), getNodeHeight(head->mLeft));
alni balance = alni(getNodeHeight(head->mRight) - getNodeHeight(head->mLeft));
if (balance > 1) {
if (head->mRight->descentRight(head->keyInRightSubtree(key))) {
return rotateLeft(head);
}
else {
head->mRight = rotateRight(head->mRight);
return rotateLeft(head);
}
}
else if (balance < -1) {
if (head->mLeft->descentLeft(head->keyInLeftSubtree(key))) {
return rotateRight(head);
}
else {
head->mLeft = rotateLeft(head->mLeft);
return rotateRight(head);
}
}
head->updateTreeCacheCallBack();
return head;
}
Node* removeUtil(Node* head, KeyArg key) {
if (head == nullptr) return head;
if (head->exactNode(key)) {
if (head->mRight && head->mLeft) {
Node* min = minNode(head->mRight);
auto const& newKey = min->getFindKey(head->mRight);
injectNodeInstead(head, min);
head->mRight = removeUtil(head->mRight, newKey);
}
else if (head->mRight) {
injectNodeInstead(head, head->mRight);
deleteNode(head->mRight);
head->mRight = nullptr;
mSize--;
}
else if (head->mLeft) {
injectNodeInstead(head, head->mLeft);
deleteNode(head->mLeft);
head->mLeft = nullptr;
mSize--;
}
else {
deleteNode(head);
mSize--;
head = nullptr;
}
}
else if (head->descentRight(key)) {
head->mRight = removeUtil(head->mRight, head->keyInRightSubtree(key));
}
else if (head->descentLeft(key)) {
head->mLeft = removeUtil(head->mLeft, head->keyInLeftSubtree(key));
}
if (head == nullptr) return head;
head->mHeight = 1 + max(getNodeHeight(head->mRight), getNodeHeight(head->mLeft));
alni balance = getNodeHeight(head->mRight) - getNodeHeight(head->mLeft);
if (balance < -1) {
if (getNodeHeight(head->mLeft->mLeft) >= getNodeHeight(head->mLeft->mRight)) {
return rotateRight(head);
}
else {
head->mLeft = rotateLeft(head->mLeft);
return rotateRight(head);
}
}
else if (balance > 1) {
if (getNodeHeight(head->mRight->mRight) >= getNodeHeight(head->mRight->mLeft)) {
return rotateLeft(head);
}
else {
head->mRight = rotateRight(head->mRight);
return rotateLeft(head);
}
}
head->updateTreeCacheCallBack();
return head;
}
public:
AvlTree() {
MODULE_SANITY_CHECK(gModuleContainers)
}
[[nodiscard]] ualni size() const {
return mSize;
}
Node* head() const {
return this->mRoot;
}
void insert(KeyArg key, DataArg data) {
mRoot = insertUtil(mRoot, key, data);
mRoot->mParent = nullptr;
}
void remove(KeyArg key) {
mRoot = removeUtil(mRoot, key);
if (mRoot) mRoot->mParent = nullptr;
}
Node* maxNode(Node* head) const {
if (!head) return nullptr;
while (head->mRight != nullptr) {
head = head->mRight;
}
return head;
}
Node* minNode(Node* head) const {
if (!head) return nullptr;
while (head->mLeft != nullptr) {
head = head->mLeft;
}
return head;
}
Node* find(KeyArg key) const {
Node* iter = mRoot;
while (true) {
if (!iter) return nullptr;
if (iter->exactNode(key)) return iter;
if (iter->descentLeft(key)) {
key = iter->keyInLeftSubtree(key);
iter = iter->mLeft;
} else {
key = iter->keyInRightSubtree(key);
iter = iter->mRight;
}
}
}
Node* findLessOrEq(KeyArg key) const {
Node* iter = mRoot;
while (true) {
if (!iter) return nullptr;
if (iter->exactNode(key)) return iter;
if (iter->descentLeft(key)) {
if (iter->mLeft) {
key = iter->keyInLeftSubtree(key);
iter = iter->mLeft;
} else {
return iter;
}
} else {
if (iter->mRight) {
key = iter->keyInRightSubtree(key);
iter = iter->mRight;
} else {
return iter;
}
}
}
}
// returns first invalid node
const Node* findInvalidNode(const Node* head) const {
if (head == nullptr) return nullptr;
if (head->mLeft) {
// TODO: incomplete test
if (!head->descentLeft(head->mLeft->getFindKey(head))) return head;
if (head->mLeft->mParent != head) return head;
if (!head->mRight && head->mLeft->mHeight != head->mHeight - 1) return head;
}
if (head->mRight) {
if (!head->descentRight(head->mRight->getFindKey(head))) return head;
if (head->mRight->mParent != head) return head;
if (!head->mLeft && head->mRight->mHeight != head->mHeight - 1) return head;
}
if (head->mLeft && head->mRight) {
if (max(head->mLeft->mHeight, head->mRight->mHeight) != head->mHeight - 1) return head;
}
int balance = getNodeHeight(head->mRight) - getNodeHeight(head->mLeft);
if (balance > 1 || balance < -1) return head;
const Node* ret = findInvalidNode(head->mRight);
if (ret) return ret;
return findInvalidNode(head->mLeft);
}
bool isValid() { return findInvalidNode(head()) == nullptr; }
static Node gNullNode;
};
template <typename Key, typename Data, class Allocator>
AvlTree<Key, Data, Allocator>::Node AvlTree<Key, Data, Allocator>::gNullNode;
}
#include "AVLTree.ipp"

View file

@ -0,0 +1,59 @@
#include <iostream>
#include "Tree.hpp"
#include "Timing.hpp"
using namespace tp;
struct Item {
Item() :
data(0) {}
bool presents = false;
alni data;
};
const auto size = 1000000;
Item buff[size];
int main() {
AvlTree<AvlNumericKey<alni>, alni> tree;
for (auto i : Range(size)) {
buff[i].data = i;
}
Timer insertTime;
ualni loadSize = 0;
while (loadSize < size / 2) {
auto idx = ualni(randomFloat() * (size - 1));
if (!buff[idx].presents) {
tree.insert((alni) buff[idx].data, buff[idx].data);
loadSize++;
buff[idx].presents = true;
}
}
std::cout << "AVL Tree Insert Speed " << (double) loadSize / (double) insertTime.timePassed() << "\n";
Timer removeTime;
ualni unloadSize = 0;
while (unloadSize < size / 2) {
auto idx = ualni(randomFloat() * (size - 1));
if (buff[idx].presents) {
tree.remove((alni) buff[idx].data);
unloadSize++;
buff[idx].presents = false;
}
}
for (auto& item : buff) {
if (item.presents) {
tree.remove((alni) item.data);
unloadSize++;
item.presents = false;
}
}
std::cout << "AVL Tree Remove Speed " << (double) unloadSize / (double) removeTime.timePassed() << "\n";
}

View file

@ -0,0 +1,15 @@
#include "Buffer2D.hpp"
#include "Tests.hpp"
using namespace tp;
const ualni size = 1000;
SUITE(Buffer2D) {
TEST(Simple) {
Buffer2D<int, TestAllocator> buff;
buff.reserve({ 4, 4 });
buff.set({ 2, 2 }, 5);
CHECK(buff.get({ 2, 2 }) == 5);
}
}

View file

@ -1,37 +1,31 @@
#include "Tests.hpp"
#include "Buffer.hpp"
#include "Testing.hpp"
#include <iostream>
#include "Tests.hpp"
using namespace tp;
const ualni size = 1000;
TEST_DEF_STATIC(Simple1) {
Buffer<TestClass> buff;
TEST(buff.size() == 0);
SUITE(Buffer) {
TEST(Simple1) {
Buffer<TestClass, TestAllocator> buff;
CHECK(buff.size() == 0);
for (auto i : Range(size * 10)) {
buff.append(TestClass(i));
}
TEST(buff.size() == size * 10);
while (buff.size()) buff.pop();
TEST(buff.size() == 0);
}
CHECK(buff.size() == size * 10);
while (buff.size())
buff.pop();
CHECK(buff.size() == 0);
}
TEST_DEF_STATIC(Simple2) {
Buffer<TestClass> buff(size);
TEST(buff.size() == 0);
for (auto i : Range(size * 10)) buff.append(TestClass(i));
TEST(buff.size() == size * 10);
while (buff.size()) buff.pop();
TEST(buff.size() == 0);
}
TEST_DEF(Buffer) {
testSimple1();
testSimple2();
TEST(Simple2) {
Buffer<TestClass, TestAllocator> buff(size);
CHECK(buff.size() == size);
for (auto i : Range(size * 10))
buff.append(TestClass(i));
CHECK(buff.size() == size + size * 10);
while (buff.size())
buff.pop();
CHECK(buff.size() == 0);
}
}

View file

@ -0,0 +1,273 @@
#include "IntervalTree.hpp"
#include "Tests.hpp"
#include "Buffer.hpp"
#include <cstdio>
using namespace tp;
struct Interval {
[[nodiscard]] bool overlaps(const Interval& in) const { return in.start <= end && in.end >= start; }
halnf start{};
halnf end{};
bool ignore = false;
void random(halnf span, halnf scale = 1.f) {
start = ((halnf) randomFloat()) * (span);
end = ((halnf) randomFloat()) * (span);
if (start > end) swap(start, end);
auto len = (end - start) * scale * 0.5f;
auto mid = (start + end) / 2.f;
start = mid - len;
end = mid + len;
}
void randomSized(halnf span, halnf size, halnf wobble) {
start = ((halnf) randomFloat()) * (span);
end = start + size + (halnf) (randomFloat() * wobble);
}
};
SUITE(IntervalTree) {
TEST(FunctionalitySimple) {
IntervalTree<ualni, ualni> intervalTree;
intervalTree.insert({ 0, 10 }, 1);
intervalTree.insert({ 3, 6 }, 2);
intervalTree.insert({ 8, 12 }, 3);
intervalTree.forEachIntersection(4, 5, [](alni start, ualni end, ualni data) {
printf("%i", int(data));
printf("\n");
});
}
TEST(FunctionalityScale) {
const int NUM_TEST_INTERVALS = 1000;
const halnf SPAN = 1000;
Buffer<Interval> pool;
IntervalTree<halnf, ualni> intervalTree;
Buffer<Interval> testIntervals;
auto test = [&]() {
for (auto testInterval : testIntervals) {
Buffer<ualni> correct;
Buffer<ualni> result;
ualni idx = 0;
for (auto interval : pool) {
if (!interval->ignore && interval->overlaps(testInterval.data())) {
correct.append(idx);
}
idx++;
}
intervalTree.forEachIntersection(
testInterval->start, testInterval->end, [&](alni start, ualni end, ualni data) { result.append(data); }
);
CHECK(correct.size() == result.size());
if (!(correct.size() == result.size())) {
printf("intersections - \n");
for (auto i : correct) {
printf(" %i", (int) i.data());
}
printf("\n");
for (auto i : result) {
printf(" %i", (int) i.data());
}
printf("\n\n");
}
// todo compare containers
}
};
// initialize
for (auto i : Range<ualni>(NUM_TEST_INTERVALS)) {
auto interval = Interval();
interval.random(SPAN);
pool.append(interval);
intervalTree.insert({ interval.start, interval.end }, i);
interval.random(SPAN * 2.f, (halnf) randomFloat());
testIntervals.append(interval);
}
test();
// remove some
for (auto i : Range<ualni>(NUM_TEST_INTERVALS / 2)) {
auto idx = ualni(randomFloat() * (alnf) pool.size());
pool[idx].ignore = true;
intervalTree.remove({ pool[idx].start, pool[idx].end });
}
test();
}
TEST(Efficency) {
struct Stat {
halnf numItems = 0;
halnf avgFound = 0;
halnf avgChecks = 0;
};
auto test = [&](ualni NUM_TEST_INTERVALS, ualni NUM_CHECKS) {
const auto SPAN = (halnf) (halnf(NUM_TEST_INTERVALS));
const auto SCALE = (halnf) (2.f);
IntervalTree<halnf, ualni> intervalTree;
Buffer<Interval> testIntervals;
auto WOBBLE = SPAN * 0;
for (auto i : Range<ualni>(NUM_TEST_INTERVALS)) {
auto interval = Interval();
interval.randomSized(SPAN, SCALE, WOBBLE);
intervalTree.insert({ interval.start, interval.end }, i);
// WOBBLE -= 1.f;
}
for (auto i : Range(0))
intervalTree.insert({ (halnf) i * 0.01f, SPAN }, 0);
WOBBLE = 0;
for (auto i : Range<ualni>(NUM_CHECKS)) {
auto interval = Interval();
interval.randomSized(SPAN, SCALE, WOBBLE);
testIntervals.append(interval);
}
ualni debugMaxChecks = 0;
ualni debugMaxFound = 0;
halnf debugAvgChecks = 0;
halnf debugAvgFound = 0;
for (auto testInterval : testIntervals) {
ualni debugFound = 0;
ualni debug = intervalTree.forEachIntersection(
testInterval->start,
testInterval->end,
[&](ualni start, ualni end, ualni data) {
debugFound++;
//
}
);
if (debug > debugMaxChecks) {
debugMaxChecks = debug;
debugMaxFound = debugFound;
}
debugMaxChecks = max(debug, debugMaxChecks);
debugAvgChecks += (halnf) debug;
debugAvgFound += (halnf) debugFound;
}
debugAvgChecks /= (halnf) testIntervals.size();
debugAvgFound /= (halnf) testIntervals.size();
printf("\nItems : %llu\n", NUM_TEST_INTERVALS);
printf("Avg(checks) : %f\n", debugAvgChecks);
printf("Avg(found) : %f\n", debugAvgFound);
printf("Max checks : %llu\n", debugMaxChecks);
printf("Max checks found : %llu\n", debugMaxFound);
printf("N(Avg(checks) / Avg(N(items)) : %f\n", debugAvgChecks / (halnf) intervalTree.size());
printf("N(Avg(found)) / Avg(N(items)) : %f\n", debugAvgFound / (halnf) intervalTree.size());
printf("Avg(found) / Avg(checks) : %f\n", debugAvgFound / debugAvgChecks);
return Stat{ (halnf) NUM_TEST_INTERVALS,
debugAvgFound / (halnf) intervalTree.size(),
debugAvgChecks / (halnf) intervalTree.size() };
};
Buffer<Stat> stats;
for (auto i : Range(2, 5)) {
Stat stat = test(pow(10, i), 100);
stats.append(stat);
}
printf("\nChecks: ");
for (auto stat : stats)
printf("%e ", stat->avgChecks);
printf("\nHits: ");
for (auto stat : stats)
printf("%e ", stat->avgFound);
printf("\nItems: ");
for (auto stat : stats)
printf("%e ", stat->numItems);
printf("\n\n");
}
TEST(FunctionalityComplex) {
IntervalTree<ualni, ualni> intervals;
struct QueryResult {
ualni numFound = 0;
ualni lastDataFound = 0;
[[nodiscard]] bool isSingleData(ualni aData) const { return numFound == 1 && lastDataFound == aData; }
[[nodiscard]] bool notFound() const { return numFound == 0; }
[[nodiscard]] bool found(ualni num) const { return numFound == num; }
};
auto makeQuery = [&](ualni aStart, ualni aEnd) {
QueryResult out;
intervals.forEachIntersection(aStart, aEnd, [&](alni start, ualni end, ualni data) {
out.numFound++;
out.lastDataFound = data;
});
return out;
};
intervals.insert({ 2, 5 }, 1);
intervals.insert({ 12, 15 }, 2);
intervals.insert({ 22, 25 }, 3);
CHECK(makeQuery(1, 6).isSingleData(1));
CHECK(makeQuery(1, 3).isSingleData(1));
CHECK(makeQuery(3, 6).isSingleData(1));
CHECK(makeQuery(0, 1).notFound());
CHECK(makeQuery(7, 8).notFound());
CHECK(makeQuery(3, 4).isSingleData(1));
CHECK(makeQuery(13, 14).isSingleData(2));
CHECK(makeQuery(1, 35).found(3));
CHECK(makeQuery(11, 35).found(2));
// check opened
CHECK(makeQuery(5, 12).found(2));
CHECK(makeQuery(15, 22).found(2));
CHECK(makeQuery(1, 2).isSingleData(1));
CHECK(makeQuery(25, 35).isSingleData(3));
intervals.removeAll();
intervals.insert({ 0, 3 }, 1);
intervals.insert({ 0, 13 }, 2);
CHECK(makeQuery(0, 1).found(2));
}
}

View file

@ -1,12 +1,12 @@
#include "Archiver.hpp"
#include "Tests.hpp"
#include "Testing.hpp"
#include <iostream>
#include "List.hpp"
using namespace tp;
TEST_DEF_STATIC(SimpleReference) {
SUITE(DoubleLinkedList) {
TEST(SimpleReference) {
tp::List<TestClass, TestAllocator> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
list.pushBack(TestClass(5));
@ -15,17 +15,18 @@ TEST_DEF_STATIC(SimpleReference) {
ualni i = -1;
for (auto iter : list) {
i++;
TEST_EQUAL(iter->getVal(), i);
CHECK_EQUAL(iter->getVal(), i);
}
TEST(i == 5);
CHECK(i == 5);
list.removeAll();
TEST(list.getAllocator().getAllocationsCount() == 0);
}
}
TEST_DEF_STATIC(SimplePointer) {
tp::List<TestClass*, TestAllocator> list = { new TestClass(1), new TestClass(2), new TestClass(3), new TestClass(4) };
TEST(SimplePointer) {
tp::List<TestClass*, TestAllocator> list = {
new TestClass(1), new TestClass(2), new TestClass(3), new TestClass(4)
};
list.pushBack(new TestClass(5));
list.pushFront(new TestClass(0));
@ -33,56 +34,49 @@ TEST_DEF_STATIC(SimplePointer) {
ualni i = -1;
for (auto iter : list) {
i++;
TEST_EQUAL(iter->getVal(), i);
CHECK_EQUAL(iter->getVal(), i);
}
TEST(i == 5);
CHECK(i == 5);
for (auto iter : list) {
delete iter.data();
}
list.removeAll();
}
TEST(list.getAllocator().getAllocationsCount() == 0);
}
TEST_DEF_STATIC(Copy) {
TEST(Copy) {
tp::List<TestClass, TestAllocator> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
tp::List<TestClass, TestAllocator> list2 = list;
TEST_EQUAL(list, list2);
CHECK(list == list2);
list.removeAll();
list2.removeAll();
}
TEST(list.getAllocator().getAllocationsCount() == 0);
TEST(list2.getAllocator().getAllocationsCount() == 0);
}
TEST_DEF_STATIC(SaveLoad) {
TEST(Serialization) {
tp::List<TestClass, TestAllocator> list = { TestClass(1), TestClass(2), TestClass(3), TestClass(4) };
TestFile file;
ArchiverExample<1024, false> write;
ArchiverExample<1024, true> read;
list.write(file);
write % list;
list.removeAll();
file.setAddress(0);
memCopy(read.mBuff, write.mBuff, sizeof(write.mBuff));
list.read(file);
read % list;
ualni i = 0;
for (auto iter : list) {
i++;
TEST_EQUAL(iter->getVal(), i);
CHECK(iter->getVal() == i);
}
TEST(i == 4);
CHECK(i == 4);
list.removeAll();
TEST(list.getAllocator().getAllocationsCount() == 0);
}
TEST_DEF(List) {
testSimplePointer();
testSimpleReference();
testSaveLoad();
}
}

View file

@ -1,14 +1,11 @@
#include "Tests.hpp"
#include "Testing.hpp"
#include "Archiver.hpp"
#include "Map.hpp"
#include <iostream>
#include "Tests.hpp"
using namespace tp;
TEST_DEF_STATIC(SimpleReference) {
SUITE(HashTable) {
TEST(SimpleReference) {
tp::Map<tp::ualni, TestClass, TestAllocator> map;
for (auto i : Range(1000, 100000)) {
@ -16,8 +13,8 @@ TEST_DEF_STATIC(SimpleReference) {
}
for (auto i : Range(1000, 100000)) {
TEST(map.presents(i));
TEST_EQUAL(map.get(i).getVal(), i);
CHECK(map.presents(i));
CHECK_EQUAL((tp::ualni) map.get(i).getVal(), (tp::ualni) i);
}
for (auto i : Range(1000, 100000)) {
@ -25,14 +22,14 @@ TEST_DEF_STATIC(SimpleReference) {
}
for (auto i : Range(1000, 2000)) {
TEST(map.presents(i));
CHECK(map.presents(i));
map.remove(i);
TEST(!map.presents(i));
CHECK(!map.presents(i));
}
for (auto i : Range(2000, 100000)) {
TEST(map.presents(i));
TEST_EQUAL(map.get(i).getVal(), i);
CHECK(map.presents(i));
CHECK_EQUAL((tp::ualni) map.get(i).getVal(), (tp::ualni) i);
}
for (auto i : map) {
@ -40,11 +37,9 @@ TEST_DEF_STATIC(SimpleReference) {
}
map.removeAll();
}
TEST(map.getAllocator().getAllocationsCount() == 1);
}
TEST_DEF_STATIC(SimplePointer) {
TEST(SimplePointer) {
tp::Map<tp::ualni, TestClass*, TestAllocator> map;
for (auto i : Range(1000)) {
@ -52,23 +47,26 @@ TEST_DEF_STATIC(SimplePointer) {
}
for (auto i : Range(1000)) {
TEST(map.presents(i));
TEST_EQUAL(map.get(i)->getVal(), i);
CHECK(map.presents(i));
CHECK_EQUAL((tp::ualni) map.get(i)->getVal(), (tp::ualni) i);
}
for (auto i : Range(1000)) {
auto del = map.get(i);
map.put(i, new TestClass(i));
delete del;
}
for (auto i : Range(900, 1000)) {
TEST(map.presents(i));
CHECK(map.presents(i));
delete map.get(i);
map.remove(i);
TEST(!map.presents(i));
CHECK(!map.presents(i));
}
for (auto i : Range(900)) {
TEST(map.presents(i));
TEST_EQUAL(map.get(i)->getVal(), i);
CHECK(map.presents(i));
CHECK_EQUAL((tp::ualni) map.get(i)->getVal(), (tp::ualni) i);
}
for (auto i : map) {
@ -77,11 +75,9 @@ TEST_DEF_STATIC(SimplePointer) {
}
map.removeAll();
}
TEST(map.getAllocator().getAllocationsCount() == 1);
}
TEST_DEF_STATIC(Copy) {
TEST(Copy) {
tp::Map<tp::ualni, TestClass, TestAllocator> map;
for (auto i : Range(10)) {
@ -90,48 +86,39 @@ TEST_DEF_STATIC(Copy) {
tp::Map<tp::ualni, TestClass, TestAllocator> map2 = map;
TEST_EQUAL(map, map2);
CHECK(map == map2);
map.removeAll();
map2.removeAll();
}
TEST(map.getAllocator().getAllocationsCount() == 1);
TEST(map2.getAllocator().getAllocationsCount() == 1);
}
TEST_DEF_STATIC(SaveLoad) {
TEST(SaveLoad) {
tp::Map<tp::ualni, TestClass, TestAllocator> map;
for (auto i : Range(10)) {
map.put(i, TestClass(i));
}
TestFile file;
ArchiverExample<1024, false> write;
ArchiverExample<1024, true> read;
map.write(file);
write % map;
map.removeAll();
TEST(map.getAllocator().getAllocationsCount() == 1);
CHECK(map.size() == 0);
file.setAddress(0);
memCopy(read.mBuff, write.mBuff, sizeof(write.mBuff));
map.read(file);
read % map;
TEST(map.getAllocator().getAllocationsCount() == 11);
CHECK(map.size() == 10);
for (auto i : Range(10)) {
TEST(map.presents(i));
TEST_EQUAL(map.get(i).getVal(), i);
CHECK(map.presents(i));
CHECK_EQUAL(map.get(i).getVal(), i);
}
map.removeAll();
TEST(map.getAllocator().getAllocationsCount() == 1);
}
TEST_DEF(Map) {
testSimplePointer();
testSimpleReference();
testSaveLoad();
}
}

View file

@ -1,42 +1,24 @@
#include "Tests.hpp"
#include "Testing.hpp"
#include <cstdlib>
static bool init(const tp::ModuleManifest* self) {
tp::gTesting.setRootName(self->getName());
return true;
}
#include "UnitTest++/UnitTest++.h"
void* TestAllocator::allocate(tp::ualni size) {
nAllocations++;
count++;
return malloc(size);
}
void TestAllocator::deallocate(void* p) {
nAllocations--;
if (p) {
free(p);
count--;
}
}
tp::ualni TestAllocator::getAllocationsCount() const {
return nAllocations;
TestAllocator::~TestAllocator() {
ASSERT(!count);
}
int main() {
tp::ModuleManifest* deps[] = { &tp::gModuleContainers, &tp::gModuleUtils, nullptr };
tp::ModuleManifest testModule("ContainersTest", init, nullptr, deps);
if (!testModule.initialize()) {
return 1;
}
testList();
testMap();
testAvl();
testBuffer();
testModule.deinitialize();
return UnitTest::RunAllTests();
}

View file

@ -1,74 +1,43 @@
#pragma once
#include "UnitTest++/UnitTest++.h"
#include "Utils.hpp"
// counting number of allocations and deallocations
struct TestAllocator {
TestAllocator() { count = 0; };
tp::ualni count = 0;
void* allocate(tp::ualni size);
void deallocate(void*);
~TestAllocator();
};
class TestClass {
tp::ualni val2 = 0;
tp::ualni val1;
public:
TestClass() { val1 = 0; }
explicit TestClass(tp::ualni val) : val1(val) {}
explicit TestClass(tp::ualni val) :
val1(val) {}
template<class Saver>
template <class Saver>
void write(Saver& file) const {
file.write(val1);
}
template<class Loader>
template <class Loader>
void read(Loader& file) {
file.read(val1);
}
[[nodiscard]] bool operator==(const TestClass& in) const {
return in.val1 == val1;
}
[[nodiscard]] bool operator==(const TestClass& in) const { return in.val1 == val1; }
[[nodiscard]] tp::ualni getVal() const { return val1; }
void setVal(tp::ualni val) { val1 = val; }
};
class TestAllocator {
tp::ualni nAllocations = 0;
public:
TestAllocator() = default;
void* allocate(tp::ualni size);
void deallocate(void* p);
[[nodiscard]] tp::ualni getAllocationsCount() const;
};
class TestFile {
tp::ualni mem[1024] = { 0 };
tp::ualni address = 0;
public:
TestFile() = default;
template<typename Type>
void write(const Type& val) {
val.write(*this);
}
template<>
void write<tp::ualni>(const tp::ualni& val) {
mem[address] = val;
address++;
}
void setAddress(tp::ualni addr) { address = addr; }
template<typename Type>
void read(Type& val) {
val.read(*this);
}
template<>
void read<tp::ualni>(tp::ualni& val) {
val = mem[address];
address++;
}
};
void testList();
void testMap();
void testAvl();
void testBuffer();

View file

@ -1,38 +1,36 @@
#include "Tests.hpp"
#include "Tree.hpp"
#include "Testing.hpp"
#include <iostream>
#include "Tests.hpp"
#include "Tree.hpp"
#include "Timing.hpp"
using namespace tp;
TEST_DEF_STATIC(Simple) {
SUITE(AvlTree) {
TEST(Simple) {
AvlTree<AvlNumericKey<alni>, TestClass, TestAllocator> tree;
TEST(tree.size() == 0);
TEST(tree.head() == nullptr);
CHECK(tree.size() == 0);
CHECK(tree.head() == nullptr);
tree.insert(6, TestClass(6));
TEST(tree.isValid());
TEST(tree.size() == 1);
TEST(tree.head()->data == TestClass(6));
CHECK(tree.isValid());
CHECK(tree.size() == 1);
CHECK(tree.head()->data == TestClass(6));
tree.remove(6);
TEST(tree.isValid());
TEST(tree.size() == 0);
TEST(tree.head() == nullptr);
}
CHECK(tree.isValid());
CHECK(tree.size() == 0);
CHECK(tree.head() == nullptr);
}
TEST_DEF_STATIC(Persistance) {
TEST(Persistance) {
AvlTree<AvlNumericKey<alni>, TestClass, TestAllocator> tree;
const auto size = 1000;
struct Item {
Item() : data(0) {}
Item() :
data(0) {}
bool presents = false;
TestClass data;
};
@ -46,15 +44,15 @@ TEST_DEF_STATIC(Persistance) {
// random load
ualni loadSize = 0;
while (loadSize < size / 2) {
ualni idx = rand() % (size - 1);
auto idx = ualni(randomFloat() * (size - 1));
DEBUG_ASSERT(idx < size)
if (!buff[idx].presents) {
tree.insert((alni) buff[idx].data.getVal(), buff[idx].data);
loadSize++;
buff[idx].presents = true;
TEST(tree.isValid());
TEST(tree.size() == loadSize);
CHECK(tree.isValid());
CHECK(tree.size() == loadSize);
}
}
@ -64,33 +62,35 @@ TEST_DEF_STATIC(Persistance) {
loadSize++;
item.presents = true;
TEST(tree.isValid());
TEST(tree.size() == loadSize);
CHECK(tree.isValid());
CHECK(tree.size() == loadSize);
}
TEST(tree.size() == size);
TEST(tree.maxNode(tree.head())->data.getVal() == size - 1);
TEST(tree.minNode(tree.head())->data.getVal() == 0);
CHECK(tree.size() == size);
CHECK(tree.maxNode(tree.head())->data.getVal() == size - 1);
CHECK(tree.minNode(tree.head())->data.getVal() == 0);
// find
for (auto item : buff) {
auto node = tree.find((alni) item.data.getVal());
TEST(node);
CHECK(node);
if (!node) continue;
TEST(node->data.getVal() == item.data.getVal());
CHECK(node->data.getVal() == item.data.getVal());
}
TEST(!tree.find(size + 1));
TEST(!tree.find(-1));
CHECK(!tree.find(size + 1));
CHECK(!tree.find(-1));
// random unload
ualni unloadSize = 0;
while (unloadSize < size / 2) {
ualni idx = rand() % (size - 1);
auto idx = ualni(randomFloat() * (size - 1));
if (buff[idx].presents) {
tree.remove((alni) buff[idx].data.getVal());
CHECK(tree.isValid());
unloadSize++;
buff[idx].presents = false;
@ -98,13 +98,13 @@ TEST_DEF_STATIC(Persistance) {
for (auto item : buff) {
if (!item.presents) continue;
auto node = tree.find((alni) item.data.getVal());
TEST(node);
CHECK(node);
if (!node) continue;
TEST(node->data.getVal() == item.data.getVal());
CHECK(node->data.getVal() == item.data.getVal());
}
TEST(tree.isValid());
TEST(tree.size() == size - unloadSize);
CHECK(tree.isValid());
CHECK(tree.size() == size - unloadSize);
}
}
@ -114,18 +114,14 @@ TEST_DEF_STATIC(Persistance) {
unloadSize++;
item.presents = false;
TEST(tree.isValid());
TEST(tree.size() == size - unloadSize);
CHECK(tree.isValid());
CHECK(tree.size() == size - unloadSize);
}
}
TEST(tree.size() == 0);
TEST(tree.head() == nullptr);
TEST(tree.maxNode(tree.head()) == nullptr);
TEST(tree.minNode(tree.head()) == nullptr);
}
TEST_DEF(Avl) {
testSimple();
testPersistance();
CHECK(tree.size() == 0);
CHECK(tree.head() == nullptr);
CHECK(tree.maxNode(tree.head()) == nullptr);
CHECK(tree.minNode(tree.head()) == nullptr);
}
}

View file

@ -0,0 +1,29 @@
project(DataAnalysis)
### ---------------------- Externals --------------------- ###
set(BINDINGS_INCLUDE ${EXTERNALS}/glfw/include ${EXTERNALS}/glew/include)
set(BINDINGS_LIBS glfw glew_s Imgui Nanovg)
### ---------------------- Static Library --------------------- ###
file(GLOB SOURCES "./private/*.cpp" "./private/*/*.cpp")
file(GLOB HEADERS "./public/*.hpp" "./public/*/*.hpp" "./applications/*.hpp")
add_library(${PROJECT_NAME} STATIC ${SOURCES} ${HEADERS})
target_include_directories(${PROJECT_NAME} PUBLIC ./public/)
target_link_libraries(${PROJECT_NAME} PUBLIC Math Containers)
### -------------------------- Applications -------------------------- ###
add_executable(NumRecTrain applications/NumRecTraining.cpp)
target_link_libraries(NumRecTrain ${PROJECT_NAME} Connection ImageIO)
file(COPY "applications/rsc" DESTINATION "${CMAKE_BINARY_DIR}/${PROJECT_NAME}/")
add_executable(NumRecApp applications/NumRecApp.cpp)
target_link_libraries(NumRecApp ${PROJECT_NAME} Connection ImageIO)
### -------------------------- Tests -------------------------- ###
file(GLOB TEST_SOURCES "./tests/*.cpp" "./tests/*/*.cpp")
add_executable(Test${PROJECT_NAME} ${TEST_SOURCES})
target_include_directories(Test${PROJECT_NAME} PUBLIC ./applications/)
target_link_libraries(Test${PROJECT_NAME} ${PROJECT_NAME} UnitTest++)
add_test(NAME Test${PROJECT_NAME} COMMAND Test${PROJECT_NAME})

View file

@ -0,0 +1,68 @@
#include "FCNN.hpp"
#include "LocalConnection.hpp"
// #include "NewPlacement.hpp"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#define STB_IMAGE_IMPLEMENTATION
#include "stb_image.h"
#include "stb_image_write.h"
using namespace tp;
void loadImage(Buffer<halnf>& output, const char* name) {
int x, y, channels_in_file;
unsigned char* loadedImage = stbi_load(name, &x, &y, &channels_in_file, 4);
if (!loadedImage) return;
output.reserve(x * y);
for (auto i : Range(output.size())) {
output[i] = loadedImage[i * 4] / 255.f;
}
stbi_image_free(loadedImage);
}
void loadNN(FCNN& nn) {
ArchiverLocalConnection<true> archiver;
archiver.connection.connect(LocalConnection::Location("NumRec.wb"), LocalConnection::Type(true));
if (archiver.connection.getConnectionStatus().isOpened()) {
archiver % nn;
} else {
Buffer<halni> layers = { 784, 10 };
nn.initializeRandom(layers);
}
}
void executeCmd(const char* imageName) {
FCNN nn;
Buffer<halnf> output(10);
Buffer<halnf> input;
loadNN(nn);
loadImage(input, imageName);
nn.evaluate(input, output);
printf("Output - ");
for (auto val : output) {
printf("%f ", val.data());
}
printf("\n\n");
}
int main(int argc, char** argv) {
const char* imageName = "digit.png";
if (argc == 2) {
imageName = argv[1];
}
executeCmd(imageName);
return 0;
}

View file

@ -0,0 +1,244 @@
#include "FCNN.hpp"
#include "LocalConnection.hpp"
#define STB_IMAGE_WRITE_IMPLEMENTATION
#include "stb_image_write.h"
using namespace tp;
void writeImage(const Buffer<halnf>& image, const char* name) {
struct Tmp {
uint1 r, g, b, a;
};
Buffer<Tmp> converted;
converted.reserve(image.size());
for (auto i = 0; i < image.size(); i++) {
auto val = uint1(image[i] * 255);
converted[i] = { val, val, val, 255 };
}
stbi_write_png(name, 28, 28, 4, converted.getBuff(), 28 * 4);
}
struct Dataset {
ualni length = 0;
std::pair<ualni, ualni> imageSize = { 0, 0 };
Buffer<uint1> labels;
Buffer<Buffer<uint1>> images;
};
bool loadDataset(Dataset& out, const std::string& location) {
LocalConnection dataset;
dataset.connect(LocalConnection::Location(location), LocalConnection::Type(true));
if (!dataset.getConnectionStatus().isOpened()) {
return false;
}
LocalConnection::Byte length;
dataset.readBytes(&length, 1);
LocalConnection::Byte sizeX;
dataset.readBytes(&sizeX, 1);
LocalConnection::Byte sizeY;
dataset.readBytes(&sizeY, 1);
out.length = ((ualni) length) * 1000;
out.imageSize = { sizeX, sizeY };
out.labels.reserve(out.length);
out.images.reserve(out.length);
for (auto i : Range(out.length)) {
auto& image = out.images[i];
image.reserve(sizeX * sizeY);
dataset.readBytes((LocalConnection::Byte*) image.getBuff(), sizeX * sizeY);
}
LocalConnection::Byte label;
dataset.readBytes((LocalConnection::Byte*) out.labels.getBuff(), out.length);
return true;
}
struct NumberRec {
NumberRec() {
// try to load wb file
{
ArchiverLocalConnection<true> archiver;
archiver.connection.connect(LocalConnection::Location("NumRec.wb"), LocalConnection::Type(true));
if (archiver.connection.getConnectionStatus().isOpened()) {
archiver % nn;
} else {
Buffer<halni> layers = { 784, 10 };
nn.initializeRandom(layers);
}
}
Dataset dataset;
if (!loadDataset(dataset, "rsc/mnist")) {
printf("Cant Load Mnist Dataset\n");
return;
}
mTestcases.reserve(dataset.images.size());
for (auto i : Range(dataset.images.size())) {
auto& image = dataset.images[i];
auto label = dataset.labels[i];
auto& testcase = mTestcases[i];
testcase.output.reserve(10);
for (auto dig : Range(10)) {
testcase.output[dig] = label == dig ? 1 : 0;
}
testcase.input.reserve(image.size());
for (auto pxl : Range(image.size())) {
testcase.input[pxl] = (halnf) image[pxl] / 255.f;
}
}
output.reserve(10);
writeImage(mTestcases.first().input, "tmp1.png");
writeImage(mTestcases.last().input, "tmp2.png");
}
~NumberRec() {
// save aas wb file
{
ArchiverLocalConnection<false> archiver;
archiver.connection.connect(LocalConnection::Location("NumRec.wb"), LocalConnection::Type(false));
if (archiver.connection.getConnectionStatus().isOpened()) {
archiver % nn;
}
}
}
halnf eval(ualni idx) {
nn.evaluate(mTestcases[idx].input, output);
return nn.calcCost(mTestcases[idx].output);
}
void applyGrad(ualni idx) {
nn.calcGrad(mTestcases[idx].output);
nn.applyGrad(step);
}
static halni getMaxIdx(const Buffer<halnf>& in) {
halni out = 0;
for (auto i : Range(in.size())) {
if (in[i] > in[out]) {
out = i;
}
}
return out;
}
bool testIncorrect(ualni idx) {
nn.evaluate(mTestcases[idx].input, output);
return getMaxIdx(mTestcases[idx].output) != getMaxIdx(output);
}
void debLog(halni idx) {
printf("\n Got %i - ", getMaxIdx(output));
for (auto val : output) {
printf("%f ", val.data());
}
printf("\n Expected %i - ", getMaxIdx(mTestcases[idx].output));
for (auto val : mTestcases[idx].output) {
printf("%f ", val.data());
}
printf("\n\n");
}
void displayImage(ualni idx) {
auto& testcase = mTestcases[idx];
printf("Image : %i\n", int(getMaxIdx(testcase.output)));
for (auto i : Range(28)) {
for (auto j : Range(28)) {
printf("%c", char(testcase.input[j * 28 + i] * 255));
}
printf("\n");
}
}
halnf test(const Range<halni>& range) {
halnf avgCost = 0;
for (auto i : range) {
avgCost += eval(i);
}
avgCost /= (halnf) range.idxDiff();
return avgCost;
}
void trainStep(const Range<halni>& range) {
nn.clearGrad();
for (auto i : range) {
nn.evaluate(mTestcases[i].input, output);
nn.calcGrad(mTestcases[i].output);
}
nn.applyGrad(step);
}
public:
struct Image {
Buffer<halnf> input;
Buffer<halnf> output;
};
public:
Buffer<Image> mTestcases;
FCNN nn;
Buffer<halnf> output;
halnf step = 1.f;
};
int main() {
NumberRec app;
auto numBatches = 10;
auto trainRange = Range(0, 50000);
auto testRange = Range(50000, 70000);
auto batchSize = trainRange.idxDiff() / numBatches;
for (auto epoch : Range(1)) {
printf("Epoch %i\n", epoch.index());
for (auto batchIdx : Range(trainRange.idxDiff() / batchSize)) {
printf(" - Batch :%i \n", batchIdx.index());
auto batchRange = Range(trainRange.idxBegin() + batchSize * batchIdx, trainRange.idxBegin() + batchSize * (batchIdx + 1));
app.trainStep(batchRange);
printf("Cost on batch data : %f\n", app.test(batchRange));
}
printf("Cost on test data : %f\n\n", app.test(testRange));
}
auto errors = 0;
for (auto i : testRange) {
if (app.testIncorrect(i)) {
errors++;
}
// app.debLog(i);
// app.displayImage(i);
}
printf("\n\nIncorrect - %i out of %i (%f)\n\n", errors, testRange.idxDiff(), (halnf) errors / (halnf) testRange.idxDiff());
}

Binary file not shown.

View file

@ -0,0 +1,157 @@
// #include "NewPlacement.hpp"
#include "FCNN.hpp"
#include <cmath>
using namespace tp;
static halnf linearFun(halnf val) { return val; }
static halnf linearFunDerivative(halnf val) { return 1; }
static halnf sigmoid(double val) { return 1.0f / (1.0f + (halnf) exp(-val)); }
static halnf sigmoidDerivative(double val) {
halnf sigmoid_val = sigmoid(val);
return sigmoid_val * (1.0f - sigmoid_val);
}
static halnf relu(halnf val) { return val < 0 ? 0 : val; }
static halnf reluDerivative(halnf val) { return val < 0 ? 0 : 1; }
static halnf activationFunction(halnf val) { return sigmoid(val); }
static halnf activationFunctionDerivative(halnf val) { return sigmoidDerivative(val); }
FCNN::FCNN(const Buffer<halni>& description) { initializeRandom(description); }
void FCNN::initializeRandom(const Buffer<halni>& description) {
ASSERT(description.size() > 1);
mLayers.reserve(description.size());
for (auto i : Range<halni>(0, (halni) description.size())) {
mLayers[i].neurons.reserve(description[i]);
if (i == 0) {
continue;
}
for (auto neuron : mLayers[i].neurons) {
neuron->weights.reserve(description[i - 1]);
for (auto weight : neuron->weights) {
weight->val = (halnf) (randomFloat() - 0.5) * 2;
}
neuron->bias.val = (halnf) (randomFloat() - 0.5) * 2;
}
}
}
void FCNN::evaluate(const Buffer<halnf>& input, Buffer<halnf>& output) {
ASSERT(output.size() == mLayers.last().neurons.size() && input.size() == mLayers.first().neurons.size())
for (auto idx : Range(input.size())) {
mLayers.first().neurons[idx].activationValue = input[idx];
}
for (auto layerIdx : Range<halni>(1, (halni) mLayers.size())) {
auto& layer = mLayers[layerIdx];
auto& layerPrev = mLayers[layerIdx - 1];
for (auto neuron : layer.neurons) {
neuron->activationValue = 0;
for (auto connectionIdx : Range(neuron->weights.size())) {
neuron->activationValue += neuron->weights[connectionIdx].val * layerPrev.neurons[connectionIdx].activationValue;
}
neuron->activationValue += neuron->bias.val;
neuron->activationValueLinear = neuron->activationValue;
neuron->activationValue = activationFunction(neuron->activationValue);
}
}
for (auto idx : Range(output.size())) {
output[idx] = mLayers.last().neurons[idx].activationValue;
}
}
halnf FCNN::calcCost(const Buffer<halnf>& output) {
halnf out = 0;
for (auto neuronIdx : Range(mLayers.last().neurons.size())) {
out += pow(output[neuronIdx] - mLayers.last().neurons[neuronIdx].activationValue, 2);
}
return out;
}
void FCNN::clearGrad() {
for (auto layIdx : Range<halni>(1, (halni) mLayers.size())) {
auto& layer = mLayers[layIdx];
for (auto neuron : layer.neurons) {
neuron->bias.grad = 0;
for (auto weightIdx : Range(neuron->weights.size())) {
neuron->weights[weightIdx].grad = 0;
}
}
}
mAvgCount = 0;
}
void FCNN::calcGrad(const Buffer<halnf>& output) {
ASSERT(mLayers.last().neurons.size() == output.size())
auto& lastLayer = mLayers.last();
// calculate chaining cache value for each neuron in last layer
for (auto neuronIdx : Range(lastLayer.neurons.size())) {
auto& neuron = lastLayer.neurons[neuronIdx];
neuron.cache = 2 * (neuron.activationValue - output[neuronIdx]);
}
// calculate rest of the layers
for (auto layerIdx = mLayers.size() - 1; layerIdx > 0; layerIdx--) {
auto& currentLayer = mLayers[layerIdx];
auto& inputLayer = mLayers[layerIdx - 1];
for (auto currentNeuronIdx : Range(currentLayer.neurons.size())) {
auto& currentNeuron = currentLayer.neurons[currentNeuronIdx];
// calculate cache value (chaining)
if (layerIdx != mLayers.size() - 1) {
auto& userLayer = mLayers[layerIdx + 1];
currentNeuron.cache = 0;
for (auto userNeuron : userLayer.neurons) {
currentNeuron.cache += userNeuron->weights[currentNeuronIdx].val * userNeuron->cache;
}
currentNeuron.cache *= activationFunctionDerivative(currentNeuron.activationValueLinear);
}
// gradient for current neuron bias
currentNeuron.bias.grad += currentNeuron.cache;
// calculate gradient for weights of current neuron
for (auto weightIdx : Range(currentNeuron.weights.size())) {
currentNeuron.weights[weightIdx].grad += inputLayer.neurons[weightIdx].activationValue * currentNeuron.cache;
}
}
}
mAvgCount++;
}
void FCNN::applyGrad(halnf step) {
for (auto layIdx : Range<halni>(1, (halni) mLayers.size())) {
auto& layer = mLayers[layIdx];
for (auto neuron : layer.neurons) {
neuron->bias.val -= neuron->bias.grad / (halnf) mAvgCount * step;
for (auto weightIdx : Range(neuron->weights.size())) {
neuron->weights[weightIdx].val -= (neuron->weights[weightIdx].grad / (halnf) mAvgCount) * step;
}
}
}
mAvgCount = 0;
}

View file

@ -0,0 +1,76 @@
#pragma once
#include "Buffer.hpp"
namespace tp {
// Fully connected neural network
class FCNN {
struct Layer {
struct Neuron {
struct Parameter {
Parameter() = default;
Parameter(halnf in) :
val(in) {}
halnf val = 0;
halnf grad = 0;
public:
template <class tArchiver>
void archive(tArchiver& ar) {
ar % val;
}
};
Parameter bias;
Buffer<Parameter> weights;
halnf activationValue = 0;
halnf activationValueLinear = 0;
halnf cache;
public:
template <class tArchiver>
void archive(tArchiver& ar) {
ar % bias;
ar % weights;
}
};
Buffer<Neuron> neurons;
public:
template <class tArchiver>
void archive(tArchiver& ar) {
ar % neurons;
}
};
public:
FCNN() = default;
explicit FCNN(const Buffer<halni>& description);
void initializeRandom(const Buffer<halni>& description);
void evaluate(const Buffer<halnf>& input, Buffer<halnf>& output);
halnf calcCost(const Buffer<halnf>& output);
void clearGrad();
void calcGrad(const Buffer<halnf>& output);
void applyGrad(halnf step);
public:
template <class tArchiver>
void archive(tArchiver& ar) {
ar % mLayers;
}
public:
Buffer<Layer> mLayers;
halni mAvgCount = 0;
};
};

View file

@ -0,0 +1,64 @@
#include "UnitTest++/UnitTest++.h"
#include "FCNN.hpp"
#include "Utils.hpp"
#include <cstdio>
using namespace tp;
halnf inputLayer[100] = {
6.50073, 2.41955, 3.57390, 2.54054, 4.01545, 1.27555, 8.93310, 5.98754, 0.83661, 2.30855, 7.70906, 6.53513, 5.92166,
9.96563, 1.24706, 3.17029, 8.52388, 8.75402, 8.73118, 0.56217, 1.02163, 7.27230, 5.51980, 2.10261, 9.94351, 1.89839,
4.23003, 3.80691, 9.43242, 2.74919, 0.30270, 9.76303, 5.72574, 7.80288, 8.62568, 6.25799, 0.03797, 2.56737, 5.57602,
9.85272, 8.81618, 6.40643, 6.51678, 6.28869, 5.20166, 2.39731, 2.18484, 0.61359, 6.27063, 1.89839, 1.38699, 2.49058,
7.03768, 9.24257, 7.14492, 9.79083, 7.09768, 6.10761, 2.06128, 5.79821, 9.65542, 6.98304, 3.00416, 9.48536, 2.21974,
4.31504, 0.70457, 4.78254, 1.76592, 6.04608, 2.58798, 4.91384, 8.95884, 8.09472, 7.13455, 9.15459, 1.94269, 5.99912,
6.79787, 1.03997, 5.23773, 9.31124, 9.44900, 8.06692, 4.86936, 7.97706, 7.48052, 4.77991, 9.32074, 2.11929, 8.23583,
2.80812, 1.94275, 0.42090, 6.15178, 2.26695, 4.12673, 5.84851, 0.22800, 3.11190
};
halnf outputLayer[20] = {
1.000000, 0.283636, 0.725544, 1.000000, 0.921875, 0.131610, 0.276638, 0.894206, 0.379333, 0.601731,
0.074395, 0.598880, 0.454188, 0.424037, 0.961471, 0.930909, 0.681503, 0.734448, 0.123868, 1.000000
};
SUITE(FCNN) {
TEST(Basic) {
Buffer<halni> layers = { 100, 70, 50, 30, 20 };
Buffer<halnf> input(layers.first());
Buffer<halnf> outputExpected(layers.last());
Buffer<halnf> output(layers.last());
for (auto inputVal : Range(layers.first())) {
input[inputVal] = inputLayer[inputVal];
}
for (auto outIdx : Range(layers.last())) {
outputExpected[outIdx] = outputLayer[outIdx];
}
FCNN nn(layers);
halnf steppingValue = 0.1;
halnf cost = 0;
for (auto i : Range(150)) {
nn.evaluate(input, output);
nn.calcGrad(outputExpected);
nn.applyGrad(steppingValue);
cost = nn.calcCost(outputExpected);
// printf("Loss %f \n", nn.calcCost(outputExpected));
}
CHECK(cost < 0.15f);
}
}
int main() {
return UnitTest::RunAllTests();
}

94
Externals/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,94 @@
# find_package(ALSA REQUIRED)
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
message("Configuring for windows...")
message("Libraries path is - ${WINDOWS_LIBRARIES}")
set(CMAKE_PREFIX_PATH "${WINDOWS_LIBRARIES}/glew-2.1.0")
find_package(GLEW REQUIRED)
set(GLEW_LIB ${GLEW_STATIC_LIBRARY_RELEASE} opengl32.lib PARENT_SCOPE)
# Your relative paths
set(RELATIVE_INCLUDE_DIR "${WINDOWS_LIBRARIES}/portaudio/include")
set(RELATIVE_LIB "${WINDOWS_LIBRARIES}/portaudio_build/Debug/portaudio.lib")
# Convert to absolute paths
get_filename_component(ABSOLUTE_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/${RELATIVE_INCLUDE_DIR}" ABSOLUTE)
get_filename_component(ABSOLUTE_LIB "${CMAKE_CURRENT_SOURCE_DIR}/${RELATIVE_LIB}" ABSOLUTE)
# Set absolute paths with respect to the parent scope
set(PORTAUDIO_INCLUDE_DIR "${ABSOLUTE_INCLUDE_DIR}" PARENT_SCOPE)
set(PORTAUDIO_LIB "${ABSOLUTE_LIB}" PARENT_SCOPE)
else()
find_package(GLEW REQUIRED)
set(GLEW_LIB ${GLEW_LIBRARIES} GL PARENT_SCOPE)
set(PORTAUDIO_LIB portaudio PARENT_SCOPE)
endif()
#add_subdirectory(glew/build/cmake/)
#target_compile_definitions(glew_s PUBLIC GLEW_NO_GLU)
#add_subdirectory(unittest-cpp)
add_subdirectory(lalr)
if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
else()
target_compile_options(UnitTest++ PUBLIC -Wno-error)
endif()
add_subdirectory(glfw)
project(Imgui)
set(${PROJECT_NAME}_SOURCES
imgui/imgui.cpp
imgui/imgui_draw.cpp
imgui/imgui_tables.cpp
imgui/imgui_widgets.cpp
imgui/imgui_demo.cpp
imgui/backends/imgui_impl_glfw.cpp
imgui/backends/imgui_impl_opengl3.cpp
)
add_library(${PROJECT_NAME} STATIC ${${PROJECT_NAME}_SOURCES})
include_directories(${PROJECT_NAME} ./glfw/include)
target_include_directories(${PROJECT_NAME} PUBLIC ./imgui/ ./imgui/backends/)
project(Nanovg)
set(${PROJECT_NAME}_SOURCES
nanovg/src/nanovg.c
)
add_library(${PROJECT_NAME} STATIC ${${PROJECT_NAME}_SOURCES})
target_include_directories(${PROJECT_NAME} PUBLIC ./nanovg/src/ ./nanovg/obsolete/)
project(Lua)
# Add the Lua source files
#file(GLOB ${PROJECT_NAME}_SOURCES "./lua/luaone.c")
# list(FILTER ${PROJECT_NAME}_SOURCES EXCLUDE REGEX "./lua/lua.c$")
# Create the Lua library
add_library(${PROJECT_NAME} STATIC "lua/onelua.c")
target_compile_definitions(${PROJECT_NAME} PUBLIC MAKE_LIB)
# Include directories for Lua headers
target_include_directories(${PROJECT_NAME} PUBLIC "./lua")
# Set compilation options, e.g., for compilation with C99
set_target_properties(${PROJECT_NAME} PROPERTIES
C_STANDARD 99
C_STANDARD_REQUIRED ON
)
project(ImageIO)
add_library(${PROJECT_NAME} INTERFACE)
target_include_directories(${PROJECT_NAME} INTERFACE ./imageIO/)
#set(OIDN_DEVICE_CPU ON)
#set(OIDN_STATIC_LIB ON)
#add_subdirectory(oidn)
find_package(OpenImageDenoise REQUIRED)

1
Externals/asio vendored Submodule

@ -0,0 +1 @@
Subproject commit ed5db1b50136bace796062c1a6eab0df9a74f8fa

Some files were not shown because too many files have changed in this diff Show more