Compare commits

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

219 commits

Author SHA1 Message Date
IlyaShurupov
e2072d257f tmp 2024-05-03 15:09:26 +03:00
IlyaShurupov
86a41c1876 tmp 2024-04-29 12:37:39 +03:00
IlyaShurupov
8171ba03da tmp 2024-04-18 12:54:37 +03:00
IlyaShurupov
2160dfca34 tmp 2024-04-13 12:28:46 +03:00
IlyaShurupov
e161fffc0c tmp 2024-04-12 16:27:21 +03:00
IlyaShurupov
a9fbb909ac tmp 2024-04-12 15:27:40 +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
322 changed files with 278679 additions and 6647 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,49 @@
# 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: |
git submodule update --init --recursive
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
- 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}}
- 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; }

22
3DEditor/CMakeLists.txt Normal file
View file

@ -0,0 +1,22 @@
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 Graphics Connection Widgets Math RasterRender)
target_link_libraries(${PROJECT_NAME} PUBLIC ${BINDINGS_LIBS})
### -------------------------- Applications -------------------------- ###
add_executable(3DEditorApp ./applications/Entry.cpp ./applications/SceneLoad.cpp)
target_link_libraries(3DEditorApp ${PROJECT_NAME} Lua ImageIO)
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;
bool loadMeshes(tp::Scene& scene, const std::string& objetsPath);
class EditorGUI : public Application {
public:
EditorGUI() {
Vec2F renderResolution = { 1000, 1000 };
auto canvas = this->mGraphics->getCanvas();
// mGui = new EditorWidget<EventHandler, Canvas>(canvas, &geometry, renderResolution);
mGui = new ShortcutsTest<EventHandler, Canvas>();
loadMeshes(geometry, "rsc/scene.obj");
geometry.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->proc(*eventHandler, rec, rec);
}
void drawFrame(Canvas* canvas) override { mGui->draw(*canvas); }
private:
Scene geometry;
ShortcutsTest<EventHandler, Canvas>* mGui;
};
int main() {
EditorGUI gui;
gui.run();
}

View file

@ -0,0 +1,41 @@
#include "Scene.hpp"
#include "obj/OBJ_Loader.h"
#include <filesystem>
bool loadMeshes(tp::Scene& scene, const std::string& objetsPath) {
using namespace tp;
objl::Loader Loader;
if (!Loader.LoadFile(objetsPath.c_str())) {
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) {
scene.mObjects.append(Object());
auto object = &scene.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) {
uint idx1 = (int) curMesh.Indices[j];
uint idx2 = (int) curMesh.Indices[j + 1];
uint idx3 = (int) curMesh.Indices[j + 2];
// printf("{ %i, %i, %i },\n", idx1, idx2, idx3);
object->mTopology.Indexes.append({ idx1, idx2, idx3 });
}
if (object->mTopology.Normals.size() != object->mTopology.Points.size()) {
printf("Logic error loading normals\n");
}
}
return scene.mObjects.size();
}

110
3DEditor/private/Render.cpp Normal file
View file

@ -0,0 +1,110 @@
#include "Render.hpp"
#include "GraphicsApi.hpp"
using namespace tp;
class ObjectBuffers {
public:
ObjectBuffers(Object* object) {
mObject = (object);
auto& buff = mObject->mTopology.Points;
auto& indices = mObject->mTopology.Indexes;
glGenVertexArrays(1, &VAO);
glGenBuffers(1, &VBO);
glGenBuffers(1, &EBO);
glBindVertexArray(VAO);
glBindBuffer(GL_ARRAY_BUFFER, VBO);
glBufferData(GL_ARRAY_BUFFER, sizeof(Vec3F) * buff.size(), buff.getBuff(), GL_STATIC_DRAW);
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, sizeof(Vec3<uhalni>) * indices.size(), indices.getBuff(), GL_STATIC_DRAW);
glVertexAttribPointer(0, 3, GL_FLOAT, GL_FALSE, 3 * sizeof(float), nullptr);
glEnableVertexAttribArray(0);
// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, 0);
glBindBuffer(GL_ARRAY_BUFFER, 0);
glBindVertexArray(0);
}
Object* mObject = nullptr;
GLuint VAO = 0;
GLuint VBO = 0;
GLuint EBO = 0;
void drawCall() {
auto& indices = mObject->mTopology.Indexes;
glBindVertexArray(VAO);
// glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, EBO);
glDrawElements(GL_TRIANGLES, indices.size() * 3, GL_UNSIGNED_INT, nullptr);
// glDrawArrays(GL_TRIANGLES, 0, sizeof(buffer) / (2 * sizeof(float)));
// glBindVertexArray(0);
}
~ObjectBuffers() {
glDeleteBuffers(1, &VBO);
glDeleteVertexArrays(1, &VAO);
}
};
Render::Render(Vec2F renderResolution) :
mRenderBuffer(renderResolution) {
mDefaultShader.load("rsc/shaders/default.vert", nullptr, "rsc/shaders/default.frag", true);
}
Render::~Render() {}
uint4 Render::getRenderBuffer() { return mRenderBuffer.texId(); }
Vec2F Render::getBufferSize() { return mRenderBuffer.getSize(); }
void Render::render(const Scene& geometry, Vec2F size) {
for (auto object : geometry.mObjects) {
if (!object->mBuffers) {
object->mBuffers = std::make_shared<ObjectBuffers>(&object.data());
}
}
mRenderBuffer.mClearCol = { 0.0f, 0.0f, 0.0f, 0.f };
mRenderBuffer.beginDraw();
mRenderBuffer.clear();
mDefaultShader.bind();
Mat4F cameraMat = geometry.mCamera.calculateTransformationMatrix();
glEnable(GL_DEPTH_TEST);
for (auto object : geometry.mObjects) {
static auto origin = (GLint) mDefaultShader.getu("Origin");
static auto basis = (GLint) mDefaultShader.getu("Basis");
static auto camera = (GLint) mDefaultShader.getu("Camera");
Mat4F basisMat;
Vec4F originPoint;
glUniform4fv(origin, 1, &originPoint[0]);
glUniformMatrix4fv(basis, 1, false, &basisMat[0][0]);
glUniformMatrix4fv(camera, 1, true, &cameraMat[0][0]);
object->mBuffers->drawCall();
}
mDefaultShader.unbind();
mRenderBuffer.endDraw();
}

View file

@ -0,0 +1,104 @@
#include "Widgets.hpp"
#include "Render.hpp"
namespace tp {
template <typename Events, typename Canvas>
class ShortcutsTest : public Widget<Events, Canvas> {
public:
ShortcutsTest() { this->createConfig("ShortcutsTest"); }
void action(const Events&) {
//
}
void proc(const Events& events, const RectF& areaParent, const RectF& aArea) override {
this->mArea = aArea;
this->mVisible = areaParent.isOverlap(aArea);
if (!this->mVisible) return;
}
void draw(Canvas& canvas) override {
if (!this->mVisible) return;
canvas.rect(this->mArea, this->getColor("Base"));
}
void populateConfig() override {
this->addColor("Base", "Base");
this->addOperator("OperatorName", { this, [](void* self, const Events& events) {
((ShortcutsTest*) self)->action(events);
} });
this->getShortcuts("OperatorName").append({ { "Alt", "Hold" }, { "Mouse1", "Hold" } });
this->getShortcuts("OperatorName").append({ { "Alt", "Hold" }, { "Mouse1", "Hold" } });
}
};
template <typename Events, typename Canvas>
class ViewportWidget : public Widget<Events, Canvas> {
public:
explicit ViewportWidget(Canvas* canvas, Scene* geometry, Vec2F renderResolution) :
mRender(renderResolution) {
this->createConfig("ViewportWidget");
mImage = canvas->createImageFromTextId(mRender.getRenderBuffer(), mRender.getBufferSize());
mGeometry = geometry;
mCanvas = canvas;
}
~ViewportWidget() { mCanvas->deleteImageHandle(mImage); }
void proc(const Events& events, const RectF& areaParent, const RectF& aArea) override {
this->mArea = aArea;
this->mVisible = areaParent.isOverlap(aArea);
if (!this->mVisible) return;
mGeometry->mCamera.rotate(0.01f, 0.0);
}
void draw(Canvas& canvas) override {
if (!this->mVisible) return;
mRender.render(*mGeometry, this->mArea.size);
canvas.drawImage(this->mArea, &mImage, PI);
}
public:
Render mRender;
Scene* mGeometry = nullptr;
Canvas* mCanvas = nullptr;
Canvas::ImageHandle mImage;
};
template <typename Events, typename Canvas>
class EditorWidget : public Widget<Events, Canvas> {
public:
EditorWidget(Canvas* canvas, Scene* geometry, Vec2F renderResolution) :
mViewport(canvas, geometry, renderResolution) {
this->createConfig("EditorWidget");
this->addColor("Base", "Base");
}
void proc(const Events& events, const RectF& areaParent, const RectF& aArea) override {
this->mArea = aArea;
this->mVisible = areaParent.isOverlap(aArea);
if (!this->mVisible) return;
mSplitView.proc(events, aArea, aArea);
mViewport.proc(events, aArea, mSplitView.getFirst());
}
void draw(Canvas& canvas) override {
if (!this->mVisible) return;
canvas.rect(this->mArea, this->getColor("Base"));
mSplitView.draw(canvas);
mViewport.draw(canvas);
}
public:
ViewportWidget<Events, Canvas> mViewport;
SplitView<Events, Canvas> mSplitView;
};
}

View file

@ -0,0 +1,23 @@
#pragma once
#include "Scene.hpp"
#include "Rect.hpp"
#include "FrameBuffer.hpp"
#include "Shader.hpp"
namespace tp {
class Render {
public:
explicit Render(Vec2F renderResolution);
~Render();
void render(const Scene& geometry, Vec2F size);
uint4 getRenderBuffer();
Vec2F getBufferSize();
private:
RenderBuffer mRenderBuffer;
RenderShader mDefaultShader;
};
}

34
3DEditor/public/Scene.hpp Normal file
View file

@ -0,0 +1,34 @@
#pragma once
#include "Topology.hpp"
#include <memory>
class ObjectBuffers;
namespace tp {
class Object {
public:
Object() = default;
public:
Topology mTopology;
std::shared_ptr<ObjectBuffers> mBuffers;
};
struct PointLight {
Vec3F pos;
halnf fallOut = 1.f;
halnf intensity = 1.f;
};
class Scene {
public:
Scene() = default;
public:
Buffer<Object> mObjects;
Buffer<PointLight> mLights;
Camera mCamera;
};
}

BIN
3DEditor/rsc/Font.ttf Normal file

Binary file not shown.

112
3DEditor/rsc/scene.obj Normal file
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,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);
}

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,27 @@
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(RayTracer)
add_subdirectory(DataAnalysis)
add_subdirectory(Objects)
add_subdirectory(Widgets)
add_subdirectory(LibraryViewer)
add_subdirectory(RasterRender)
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,131 @@
#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 < mSize.x * mSize.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; }
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,10 +71,9 @@ namespace tp {
Allocator mAlloc;
public:
List() = default;
List(const init_list<Type>& list) { operator=(list); }
List(const List& in) { this->operator=(in); }
List(const InitialierList<Type>& list) { operator=(list); }
[[nodiscard]] inline Node* first() const { return mFirst; }
[[nodiscard]] inline Node* last() const { return mLast; }
@ -146,7 +146,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 +157,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 +178,9 @@ namespace tp {
void popBack() {
DEBUG_ASSERT(mLast)
auto const tmp = mLast;
detach(mLast);
deleteNode(mLast);
deleteNode(tmp);
}
void popFront() {
@ -198,9 +200,7 @@ 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) {
detach(node);
@ -221,7 +221,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,20 +229,24 @@ 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;
}
@ -252,6 +256,8 @@ namespace tp {
if (left->data != right->data) {
return false;
}
left = left->next;
right = right->next;
}
if (left != right) {
return false;
@ -274,9 +280,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 +299,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();
}

83
Externals/CMakeLists.txt vendored Normal file
View file

@ -0,0 +1,83 @@
# 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)
target_compile_options(UnitTest++ PUBLIC -Wno-error)
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/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/)

1
Externals/asio vendored Submodule

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

943
Externals/easytab/easytab.h vendored Normal file
View file

@ -0,0 +1,943 @@
/*
EasyTab.h - Single-header multi-platform tablet library
https://github.com/ApoorvaJ/EasyTab
----------------------------------------------------------------------------
USAGE
----------------------------------------------------------------------------
1) Add the following lines in exactly one of your cpp files to compile the
implementation.
#define EASYTAB_IMPLEMENTATION
#include "easytab.h"
2) Call EasyTab_Load() with correct parameters to initialize EasyTab. These
parameters vary per OS, so look at the function declarations or examples
below. Function returns EASYTAB_OK if initialization was successful.
3) Call EasyTab_HandleEvent() in your message-handling code. The function
returns EASYTAB_OK if the message was a tablet message, and
EASYTAB_EVENT_NOT_HANDLED otherwise.
4) Call EasyTab_Unload() in your shutdown code.
5) Once initialized, you can query tablet state using the EasyTab pointer.
e.g.:
EasyTab->PosX // X position of the pen
EasyTab->PosY // Y position of the pen
EasyTab->Pressure // Pressure of the pen ranging from 0.0f to 1.0f
For more info, have a look at the EasyTabInfo struct below.
* Add -lXi to compiler options to link XInput on Linux.
----------------------------------------------------------------------------
EXAMPLES
----------------------------------------------------------------------------
1) Windows:
int CALLBACK WinMain(...)
{
HWND Window;
...
if (EasyTab_Load(Window) != EASYTAB_OK) // Load
{
OutputDebugStringA("Tablet init failed\n");
}
...
// Once you've set up EasyTab loading, unloading and event handling,
// use the EasyTab variable at any point in your program to access
// the tablet state:
// EasyTab->PosX
// EasyTab->PosY
// EasyTab->Pressure
// For more tablet information, look at the EasyTabInfo struct.
...
EasyTab_Unload(); // Unload
}
LRESULT CALLBACK WindowProc(
HWND Window,
UINT Message,
WPARAM WParam,
LPARAM LParam)
{
if (EasyTab_HandleEvent(Window, Message, LParam, WParam) == EASYTAB_OK) // Event
{
return true; // Tablet event handled
}
switch (Message)
{
...
}
}
2) Linux:
int main(...)
{
Display* Disp;
Window Win;
...
if (EasyTab_Load(Disp, Win) != EASYTAB_OK) // Load
{
printf("Tablet init failed\n");
}
...
while (XPending(Disp)) // Event loop
{
XEvent Event;
XNextEvent(XlibDisplay, &Event);
if (EasyTab_HandleEvent(&Event) == EASYTAB_OK) // Event
{
continue; // Tablet event handled
}
switch (Event.type)
{
...
}
}
...
// Once you've set up EasyTab loading, unloading and event handling,
// use the EasyTab variable at any point in your program to access
// the tablet state:
// EasyTab->PosX
// EasyTab->PosY
// EasyTab->Pressure
// For more tablet information, look at the EasyTabInfo struct.
...
EasyTab_Unload(); // Unload
}
----------------------------------------------------------------------------
CREDITS
----------------------------------------------------------------------------
Apoorva Joshi apoorvaj.io
Sergio Gonzalez s3rg.io
This library is coded in the spirit of the stb libraries and follows the stb
guidelines.
*/
// TODO: Null checks and warnings for EasyTab
// TODO: Differentiate between stylus and eraser in the API
// TODO: Linux support for relative mode
// TODO: Documentation for relative mode
// =============================================================================
// EasyTab header section
// =============================================================================
#ifndef EASYTAB_H
#define EASYTAB_H
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
#ifdef __linux__
#include <X11/extensions/XInput.h>
#endif // __linux__
#ifdef _WIN32
#include <windows.h>
#endif // _WIN32
typedef enum
{
EASYTAB_OK = 0,
// Errors
EASYTAB_MEMORY_ERROR = -1,
EASYTAB_X11_ERROR = -2,
EASYTAB_DLL_LOAD_ERROR = -3,
EASYTAB_WACOM_WIN32_ERROR = -4,
EASYTAB_INVALID_FUNCTION_ERROR = -5,
EASYTAB_EVENT_NOT_HANDLED = -16,
} EasyTabResult;
typedef enum
{
EASYTAB_TRACKING_MODE_SYSTEM = 0,
EASYTAB_TRACKING_MODE_RELATIVE = 1,
} EasyTabTrackingMode;
#ifdef WIN32
// -----------------------------------------------------------------------------
// wintab.h
// -----------------------------------------------------------------------------
#if 1
DECLARE_HANDLE(HMGR);
DECLARE_HANDLE(HCTX);
typedef DWORD WTPKT;
typedef DWORD FIX32;
// Messages
#if 1
#define WT_DEFBASE 0x7FF0
#define WT_MAXOFFSET 0xF
#define _WT_PACKET(b) ((b)+0)
#define _WT_CTXOPEN(b) ((b)+1)
#define _WT_CTXCLOSE(b) ((b)+2)
#define _WT_CTXUPDATE(b) ((b)+3)
#define _WT_CTXOVERLAP(b) ((b)+4)
#define _WT_PROXIMITY(b) ((b)+5)
#define _WT_INFOCHANGE(b) ((b)+6)
#define _WT_CSRCHANGE(b) ((b)+7) /* 1.1 */
#define _WT_PACKETEXT(b) ((b)+8) /* 1.4 */
#define _WT_MAX(b) ((b)+WT_MAXOFFSET)
#define WT_PACKET _WT_PACKET(WT_DEFBASE)
#define WT_CTXOPEN _WT_CTXOPEN(WT_DEFBASE)
#define WT_CTXCLOSE _WT_CTXCLOSE(WT_DEFBASE)
#define WT_CTXUPDATE _WT_CTXUPDATE(WT_DEFBASE)
#define WT_CTXOVERLAP _WT_CTXOVERLAP(WT_DEFBASE)
#define WT_PROXIMITY _WT_PROXIMITY(WT_DEFBASE)
#define WT_INFOCHANGE _WT_INFOCHANGE(WT_DEFBASE)
#define WT_CSRCHANGE _WT_CSRCHANGE(WT_DEFBASE) /* 1.1 */
#define WT_PACKETEXT _WT_PACKETEXT(WT_DEFBASE) /* 1.4 */
#define WT_MAX _WT_MAX(WT_DEFBASE)
#endif // Messages
// Flags
#if 1
#define CTX_NAME 1
#define CTX_OPTIONS 2
#define CTX_STATUS 3
#define CTX_LOCKS 4
#define CTX_MSGBASE 5
#define CTX_DEVICE 6
#define CTX_PKTRATE 7
#define CTX_PKTDATA 8
#define CTX_PKTMODE 9
#define CTX_MOVEMASK 10
#define CTX_BTNDNMASK 11
#define CTX_BTNUPMASK 12
#define CTX_INORGX 13
#define CTX_INORGY 14
#define CTX_INORGZ 15
#define CTX_INEXTX 16
#define CTX_INEXTY 17
#define CTX_INEXTZ 18
#define CTX_OUTORGX 19
#define CTX_OUTORGY 20
#define CTX_OUTORGZ 21
#define CTX_OUTEXTX 22
#define CTX_OUTEXTY 23
#define CTX_OUTEXTZ 24
#define CTX_SENSX 25
#define CTX_SENSY 26
#define CTX_SENSZ 27
#define CTX_SYSMODE 28
#define CTX_SYSORGX 29
#define CTX_SYSORGY 30
#define CTX_SYSEXTX 31
#define CTX_SYSEXTY 32
#define CTX_SYSSENSX 33
#define CTX_SYSSENSY 34
#define CTX_MAX 34
// Context option values
#define CXO_SYSTEM 0x0001
#define CXO_PEN 0x0002
#define CXO_MESSAGES 0x0004
#define CXO_MARGIN 0x8000
#define CXO_MGNINSIDE 0x4000
#define CXO_CSRMESSAGES 0x0008 /* 1.1 */
#define DVC_NAME 1
#define DVC_HARDWARE 2
#define DVC_NCSRTYPES 3
#define DVC_FIRSTCSR 4
#define DVC_PKTRATE 5
#define DVC_PKTDATA 6
#define DVC_PKTMODE 7
#define DVC_CSRDATA 8
#define DVC_XMARGIN 9
#define DVC_YMARGIN 10
#define DVC_ZMARGIN 11
#define DVC_X 12
#define DVC_Y 13
#define DVC_Z 14
#define DVC_NPRESSURE 15
#define DVC_TPRESSURE 16
#define DVC_ORIENTATION 17
#define DVC_ROTATION 18 /* 1.1 */
#define DVC_PNPID 19 /* 1.1 */
#define DVC_MAX 19
#define PK_CONTEXT 0x0001 // reporting context
#define PK_STATUS 0x0002 // status bits
#define PK_TIME 0x0004 // time stamp
#define PK_CHANGED 0x0008 // change bit vector
#define PK_SERIAL_NUMBER 0x0010 // packet serial number
#define PK_CURSOR 0x0020 // reporting cursor
#define PK_BUTTONS 0x0040 // button information
#define PK_X 0x0080 // x axis
#define PK_Y 0x0100 // y axis
#define PK_Z 0x0200 // z axis
#define PK_NORMAL_PRESSURE 0x0400 // normal or tip pressure
#define PK_TANGENT_PRESSURE 0x0800 // tangential or barrel pressure
#define PK_ORIENTATION 0x1000 // orientation info: tilts
#define PK_ROTATION 0x2000 // rotation info; 1.1
// constants for use with pktdef.h
#define PKEXT_ABSOLUTE 1
#define PKEXT_RELATIVE 2
#define WTI_DEFCONTEXT 3
#define WTI_DEFSYSCTX 4
#define WTI_DEVICES 100
#define WTI_DDCTXS 400 /* 1.1 */
#define WTI_DSCTXS 500 /* 1.1 */
#endif // Flags
typedef struct tagAXIS {
LONG axMin;
LONG axMax;
UINT axUnits;
FIX32 axResolution;
} AXIS, *PAXIS, NEAR *NPAXIS, FAR *LPAXIS;
#define LCNAMELEN 40
typedef struct tagLOGCONTEXTA {
char lcName[LCNAMELEN];
UINT lcOptions;
UINT lcStatus;
UINT lcLocks;
UINT lcMsgBase;
UINT lcDevice;
UINT lcPktRate;
WTPKT lcPktData;
WTPKT lcPktMode;
WTPKT lcMoveMask;
DWORD lcBtnDnMask;
DWORD lcBtnUpMask;
LONG lcInOrgX;
LONG lcInOrgY;
LONG lcInOrgZ;
LONG lcInExtX;
LONG lcInExtY;
LONG lcInExtZ;
LONG lcOutOrgX;
LONG lcOutOrgY;
LONG lcOutOrgZ;
LONG lcOutExtX;
LONG lcOutExtY;
LONG lcOutExtZ;
FIX32 lcSensX;
FIX32 lcSensY;
FIX32 lcSensZ;
BOOL lcSysMode;
int lcSysOrgX;
int lcSysOrgY;
int lcSysExtX;
int lcSysExtY;
FIX32 lcSysSensX;
FIX32 lcSysSensY;
} LOGCONTEXTA, *PLOGCONTEXTA, NEAR *NPLOGCONTEXTA, FAR *LPLOGCONTEXTA;
typedef struct tagEXTENSIONBASE { /* 1.4 */
HCTX nContext;
UINT nStatus;
DWORD nTime;
UINT nSerialNumber;
} EXTENSIONBASE;
#endif // wintab.h
// -----------------------------------------------------------------------------
#define PACKETDATA PK_X | PK_Y | PK_BUTTONS | PK_NORMAL_PRESSURE
#define PACKETMODE 0
// -----------------------------------------------------------------------------
// pktdef.h
// -----------------------------------------------------------------------------
#if 1
// TODO: Simplify this file if we have a fixed packet format.
// The macros here are too ugly.
#ifndef PACKETNAME
/* if no packet name prefix */
#define __PFX(x) x
#define __IFX(x,y) x ## y
#else
/* add prefixes and infixes to packet format names */
#define __PFX(x) __PFX2(PACKETNAME,x)
#define __PFX2(p,x) __PFX3(p,x)
#define __PFX3(p,x) p ## x
#define __IFX(x,y) __IFX2(x,PACKETNAME,y)
#define __IFX2(x,i,y) __IFX3(x,i,y)
#define __IFX3(x,i,y) x ## i ## y
#endif
#define __SFX2(x,s) __SFX3(x,s)
#define __SFX3(x,s) x ## s
#define __TAG __IFX(tag,PACKET)
#define __TYPES __PFX(PACKET), * __IFX(P,PACKET), NEAR * __IFX(NP,PACKET), FAR * __IFX(LP,PACKET)
#define __TAGE __IFX(tag,PACKETEXT)
#define __TYPESE __PFX(PACKETEXT), * __IFX(P,PACKETEXT), NEAR * __IFX(NP,PACKETEXT), FAR * __IFX(LP,PACKETEXT)
#define __DATA (__PFX(PACKETDATA))
#define __MODE (__PFX(PACKETMODE))
#define __EXT(x) __SFX2(__PFX(PACKET),x)
typedef struct __TAG {
#if (__DATA & PK_CONTEXT)
HCTX pkContext;
#endif
#if (__DATA & PK_STATUS)
UINT pkStatus;
#endif
#if (__DATA & PK_TIME)
DWORD pkTime;
#endif
#if (__DATA & PK_CHANGED)
WTPKT pkChanged;
#endif
#if (__DATA & PK_SERIAL_NUMBER)
UINT pkSerialNumber;
#endif
#if (__DATA & PK_CURSOR)
UINT pkCursor;
#endif
#if (__DATA & PK_BUTTONS)
DWORD pkButtons;
#endif
#if (__DATA & PK_X)
LONG pkX;
#endif
#if (__DATA & PK_Y)
LONG pkY;
#endif
#if (__DATA & PK_Z)
LONG pkZ;
#endif
#if (__DATA & PK_NORMAL_PRESSURE)
#if (__MODE & PK_NORMAL_PRESSURE)
/* relative */
int pkNormalPressure;
#else
/* absolute */
UINT pkNormalPressure;
#endif
#endif
#if (__DATA & PK_TANGENT_PRESSURE)
#if (__MODE & PK_TANGENT_PRESSURE)
/* relative */
int pkTangentPressure;
#else
/* absolute */
UINT pkTangentPressure;
#endif
#endif
#if (__DATA & PK_ORIENTATION)
ORIENTATION pkOrientation;
#endif
#if (__DATA & PK_ROTATION)
ROTATION pkRotation; /* 1.1 */
#endif
#ifndef NOWTEXTENSIONS
/* extensions begin here. */
#if (__EXT(FKEYS) == PKEXT_RELATIVE) || (__EXT(FKEYS) == PKEXT_ABSOLUTE)
UINT pkFKeys;
#endif
#if (__EXT(TILT) == PKEXT_RELATIVE) || (__EXT(TILT) == PKEXT_ABSOLUTE)
TILT pkTilt;
#endif
#endif
} __TYPES;
#ifndef NOWTEXTENSIONS
typedef struct __TAGE {
EXTENSIONBASE pkBase;
#if (__EXT(EXPKEYS) == PKEXT_RELATIVE) || (__EXT(EXPKEYS) == PKEXT_ABSOLUTE)
EXPKEYSDATA pkExpKeys; /* 1.4 */
#endif
#if (__EXT(TOUCHSTRIP) == PKEXT_RELATIVE) || (__EXT(TOUCHSTRIP) == PKEXT_ABSOLUTE)
SLIDERDATA pkTouchStrip; /* 1.4 */
#endif
#if (__EXT(TOUCHRING) == PKEXT_RELATIVE) || (__EXT(TOUCHRING) == PKEXT_ABSOLUTE)
SLIDERDATA pkTouchRing; /* 1.4 */
#endif
} __TYPESE;
#endif
#undef PACKETNAME
#undef __TAG
#undef __TAGE
#undef __TAG2
#undef __TYPES
#undef __TYPESE
#undef __TYPES2
#undef __DATA
#undef __MODE
#undef __PFX
#undef __PFX2
#undef __PFX3
#undef __IFX
#undef __IFX2
#undef __IFX3
#undef __SFX2
#undef __SFX3
#endif // pktdef.h
// -----------------------------------------------------------------------------
typedef UINT (WINAPI * WTINFOA) (UINT, UINT, LPVOID);
typedef HCTX (WINAPI * WTOPENA) (HWND, LPLOGCONTEXTA, BOOL);
typedef BOOL (WINAPI * WTGETA) (HCTX, LPLOGCONTEXTA);
typedef BOOL (WINAPI * WTSETA) (HCTX, LPLOGCONTEXTA);
typedef BOOL (WINAPI * WTCLOSE) (HCTX);
typedef BOOL (WINAPI * WTENABLE) (HCTX, BOOL);
typedef BOOL (WINAPI * WTPACKET) (HCTX, UINT, LPVOID);
typedef BOOL (WINAPI * WTOVERLAP) (HCTX, BOOL);
typedef BOOL (WINAPI * WTSAVE) (HCTX, LPVOID);
typedef BOOL (WINAPI * WTCONFIG) (HCTX, HWND);
typedef HCTX (WINAPI * WTRESTORE) (HWND, LPVOID, BOOL);
typedef BOOL (WINAPI * WTEXTSET) (HCTX, UINT, LPVOID);
typedef BOOL (WINAPI * WTEXTGET) (HCTX, UINT, LPVOID);
typedef BOOL (WINAPI * WTQUEUESIZESET) (HCTX, int);
typedef int (WINAPI * WTDATAPEEK) (HCTX, UINT, UINT, int, LPVOID, LPINT);
typedef int (WINAPI * WTPACKETSGET) (HCTX, int, LPVOID);
typedef HMGR (WINAPI * WTMGROPEN) (HWND, UINT);
typedef BOOL (WINAPI * WTMGRCLOSE) (HMGR);
typedef HCTX (WINAPI * WTMGRDEFCONTEXT) (HMGR, BOOL);
typedef HCTX (WINAPI * WTMGRDEFCONTEXTEX) (HMGR, UINT, BOOL);
#endif // WIN32
// -----------------------------------------------------------------------------
// Enums
// -----------------------------------------------------------------------------
/*
Use this enum in conjunction with EasyTab->Buttons to check for tablet button
presses.
e.g. To check for lower pen button press, use:
if (EasyTab->Buttons & EasyTab_Buttons_Pen_Lower)
{
// Lower button is pressed
}
*/
enum EasyTab_Buttons_
{
EasyTab_Buttons_Pen_Touch = 1 << 0, // Pen is touching tablet
EasyTab_Buttons_Pen_Lower = 1 << 1, // Lower pen button is pressed
EasyTab_Buttons_Pen_Upper = 1 << 2, // Upper pen button is pressed
};
// -----------------------------------------------------------------------------
// Structs
// -----------------------------------------------------------------------------
typedef struct
{
int32_t PosX, PosY;
float Pressure; // Range: 0.0f to 1.0f
int32_t Buttons; // Bit field. Use with the EasyTab_Buttons_ enum.
int32_t RangeX, RangeY;
int32_t MaxPressure;
#ifdef __linux__
XDevice* Device;
uint32_t MotionType;
XEventClass EventClasses[1024];
uint32_t NumEventClasses;
#endif // __linux__
#ifdef WIN32
HINSTANCE Dll;
HCTX Context;
WTINFOA WTInfoA;
WTOPENA WTOpenA;
WTGETA WTGetA;
WTSETA WTSetA;
WTCLOSE WTClose;
WTPACKET WTPacket;
WTENABLE WTEnable;
WTOVERLAP WTOverlap;
WTSAVE WTSave;
WTCONFIG WTConfig;
WTRESTORE WTRestore;
WTEXTSET WTExtSet;
WTEXTGET WTExtGet;
WTQUEUESIZESET WTQueueSizeSet;
WTDATAPEEK WTDataPeek;
WTPACKETSGET WTPacketsGet;
WTMGROPEN WTMgrOpen;
WTMGRCLOSE WTMgrClose;
WTMGRDEFCONTEXT WTMgrDefContext;
WTMGRDEFCONTEXTEX WTMgrDefContextEx;
#endif // WIN32
} EasyTabInfo;
extern EasyTabInfo* EasyTab;
// -----------------------------------------------------------------------------
// Function declarations
// -----------------------------------------------------------------------------
#if defined(__linux__)
EasyTabResult EasyTab_Load(Display* Disp, Window Win);
EasyTabResult EasyTab_HandleEvent(XEvent* Event);
void EasyTab_Unload(Display* Disp);
#elif defined(_WIN32)
EasyTabResult EasyTab_Load(HWND Window);
EasyTabResult EasyTab_Load_Ex(HWND Window,
EasyTabTrackingMode Mode,
float RelativeModeSensitivity,
int32_t MoveCursor);
EasyTabResult EasyTab_HandleEvent(HWND Window,
UINT Message,
LPARAM LParam,
WPARAM WParam);
void EasyTab_Unload();
#else
// Save some trouble when porting.
#error "Unsupported platform."
#endif // __linux__ _WIN32
// -----------------------------------------------------------------------------
#endif // EASYTAB_H
// =============================================================================
// EasyTab implementation section
// =============================================================================
#ifdef EASYTAB_IMPLEMENTATION
EasyTabInfo* EasyTab;
// -----------------------------------------------------------------------------
// Linux implementation
// -----------------------------------------------------------------------------
#ifdef __linux__
EasyTabResult EasyTab_Load(Display* Disp, Window Win)
{
EasyTab = (EasyTabInfo*)calloc(1, sizeof(EasyTabInfo)); // We want init to zero, hence calloc.
if (!EasyTab) { return EASYTAB_MEMORY_ERROR; }
int32_t Count;
XDeviceInfoPtr Devices = (XDeviceInfoPtr)XListInputDevices(Disp, &Count);
if (!Devices) { return EASYTAB_X11_ERROR; }
for (int32_t i = 0; i < Count; i++)
{
if (!strstr(Devices[i].name, "stylus") &&
!strstr(Devices[i].name, "eraser")) { continue; }
EasyTab->Device = XOpenDevice(Disp, Devices[i].id);
XAnyClassPtr ClassPtr = Devices[i].inputclassinfo;
for (int32_t j = 0; j < Devices[i].num_classes; j++)
{
#if defined(__cplusplus)
switch (ClassPtr->c_class)
#else
switch (ClassPtr->class)
#endif
{
case ValuatorClass:
{
XValuatorInfo *Info = (XValuatorInfo *)ClassPtr;
// X
if (Info->num_axes > 0)
{
int32_t min = Info->axes[0].min_value;
EasyTab->RangeX = Info->axes[0].max_value;
//printf("Max/min x values: %d, %d\n", min, EasyTab->RangeX); // TODO: Platform-print macro
}
// Y
if (Info->num_axes > 1)
{
int32_t min = Info->axes[1].min_value;
EasyTab->RangeY = Info->axes[1].max_value;
//printf("Max/min y values: %d, %d\n", min, EasyTab->RangeY);
}
// Pressure
if (Info->num_axes > 2)
{
int32_t min = Info->axes[2].min_value;
EasyTab->MaxPressure = Info->axes[2].max_value;
//printf("Max/min pressure values: %d, %d\n", min, EasyTab->MaxPressure);
}
XEventClass EventClass;
DeviceMotionNotify(EasyTab->Device, EasyTab->MotionType, EventClass);
if (EventClass)
{
EasyTab->EventClasses[EasyTab->NumEventClasses] = EventClass;
EasyTab->NumEventClasses++;
}
} break;
}
ClassPtr = (XAnyClassPtr) ((uint8_t*)ClassPtr + ClassPtr->length); // TODO: Access this as an array to avoid pointer arithmetic?
}
XSelectExtensionEvent(Disp, Win, EasyTab->EventClasses, EasyTab->NumEventClasses);
}
XFreeDeviceList(Devices);
if (EasyTab->Device != 0) { return EASYTAB_OK; }
else { return EASYTAB_X11_ERROR; }
}
EasyTabResult EasyTab_HandleEvent(XEvent* Event)
{
if (Event->type != EasyTab->MotionType) { return EASYTAB_EVENT_NOT_HANDLED; }
XDeviceMotionEvent* MotionEvent = (XDeviceMotionEvent*)(Event);
EasyTab->PosX = MotionEvent->x;
EasyTab->PosY = MotionEvent->y;
EasyTab->Pressure = (float)MotionEvent->axis_data[2] / (float)EasyTab->MaxPressure;
return EASYTAB_OK;
}
void EasyTab_Unload(Display* Disp)
{
XCloseDevice(Disp, EasyTab->Device);
free(EasyTab);
EasyTab = NULL;
}
#endif // __linux__
// -----------------------------------------------------------------------------
// Windows implementation
// -----------------------------------------------------------------------------
#ifdef WIN32
#define GETPROCADDRESS(type, func) \
EasyTab->func = (type)GetProcAddress(EasyTab->Dll, #func); \
if (!EasyTab->func) \
{ \
OutputDebugStringA("Function " #func " not found in Wintab32.dll.\n"); \
return EASYTAB_INVALID_FUNCTION_ERROR; \
}
EasyTabResult EasyTab_Load(HWND Window)
{
return EasyTab_Load_Ex(Window, EASYTAB_TRACKING_MODE_SYSTEM, 0, 1);
}
EasyTabResult EasyTab_Load_Ex(HWND Window,
EasyTabTrackingMode TrackingMode,
float RelativeModeSensitivity,
int32_t MoveCursor)
{
EasyTab = (EasyTabInfo*)calloc(1, sizeof(EasyTabInfo)); // We want init to zero, hence calloc.
if (!EasyTab) { return EASYTAB_MEMORY_ERROR; }
// Load Wintab DLL and get function addresses
{
EasyTab->Dll = LoadLibraryA("Wintab32.dll");
if (!EasyTab->Dll)
{
OutputDebugStringA("Wintab32.dll not found.\n");
return EASYTAB_DLL_LOAD_ERROR;
}
GETPROCADDRESS(WTINFOA , WTInfoA);
GETPROCADDRESS(WTOPENA , WTOpenA);
GETPROCADDRESS(WTGETA , WTGetA);
GETPROCADDRESS(WTSETA , WTSetA);
GETPROCADDRESS(WTCLOSE , WTClose);
GETPROCADDRESS(WTPACKET , WTPacket);
GETPROCADDRESS(WTENABLE , WTEnable);
GETPROCADDRESS(WTOVERLAP , WTOverlap);
GETPROCADDRESS(WTSAVE , WTSave);
GETPROCADDRESS(WTCONFIG , WTConfig);
GETPROCADDRESS(WTRESTORE , WTRestore);
GETPROCADDRESS(WTEXTSET , WTExtSet);
GETPROCADDRESS(WTEXTGET , WTExtGet);
GETPROCADDRESS(WTQUEUESIZESET , WTQueueSizeSet);
GETPROCADDRESS(WTDATAPEEK , WTDataPeek);
GETPROCADDRESS(WTPACKETSGET , WTPacketsGet);
GETPROCADDRESS(WTMGROPEN , WTMgrOpen);
GETPROCADDRESS(WTMGRCLOSE , WTMgrClose);
GETPROCADDRESS(WTMGRDEFCONTEXT , WTMgrDefContext);
GETPROCADDRESS(WTMGRDEFCONTEXTEX , WTMgrDefContextEx);
}
if (!EasyTab->WTInfoA(0, 0, NULL))
{
OutputDebugStringA("Wintab services not available.\n");
return EASYTAB_WACOM_WIN32_ERROR;
}
// Open context
{
LOGCONTEXTA LogContext = {0};
AXIS RangeX = {0};
AXIS RangeY = {0};
AXIS Pressure = {0};
EasyTab->WTInfoA(WTI_DDCTXS, 0, &LogContext);
EasyTab->WTInfoA(WTI_DEVICES, DVC_X, &RangeX);
EasyTab->WTInfoA(WTI_DEVICES, DVC_Y, &RangeY);
EasyTab->WTInfoA(WTI_DEVICES, DVC_NPRESSURE, &Pressure);
LogContext.lcPktData = PACKETDATA; // ??
LogContext.lcOptions |= CXO_MESSAGES;
if (MoveCursor) { LogContext.lcOptions |= CXO_SYSTEM; }
LogContext.lcPktMode = PACKETMODE;
LogContext.lcMoveMask = PACKETDATA;
LogContext.lcBtnUpMask = LogContext.lcBtnDnMask;
LogContext.lcOutOrgX = 0;
LogContext.lcOutOrgY = 0;
LogContext.lcOutExtX = GetSystemMetrics(SM_CXSCREEN);
LogContext.lcOutExtY = -GetSystemMetrics(SM_CYSCREEN);
LogContext.lcSysOrgX = 0;
LogContext.lcSysOrgY = 0;
LogContext.lcSysExtX = GetSystemMetrics(SM_CXSCREEN);
LogContext.lcSysExtY = GetSystemMetrics(SM_CYSCREEN);
if (TrackingMode == EASYTAB_TRACKING_MODE_RELATIVE)
{
LogContext.lcPktMode |= PK_X | PK_Y; // TODO: Should this be included in the
// PACKETMODE macro define up top?
LogContext.lcSysMode = 1;
if (RelativeModeSensitivity > 1.0f)
{
RelativeModeSensitivity = 1.0f;
}
else if (RelativeModeSensitivity < 0.0f)
{
RelativeModeSensitivity = 0.0f;
}
// Wintab expects sensitivity to be a 32-bit fixed point number
// with the radix point between the two words. Thus, the type
// contains 16 bits to the left of the radix point and 16 bits to
// the right of it.
//
// 0x10000 Hex
// = 65,536 Decimal
// = 0000 0000 0000 0001 . 0000 0000 0000 0000 Binary
// = 1.0 Fixed Point
uint32_t Sensitivity = (uint32_t)(0x10000 * RelativeModeSensitivity);
if (MoveCursor)
{
LogContext.lcSysSensX = LogContext.lcSysSensY = Sensitivity;
}
else
{
LogContext.lcSensX = LogContext.lcSensY = Sensitivity;
}
}
EasyTab->Context = EasyTab->WTOpenA(Window, &LogContext, TRUE);
if (!EasyTab->Context)
{
OutputDebugStringA("Wintab context couldn't be opened.\n");
return EASYTAB_WACOM_WIN32_ERROR;
}
// Get tablet capabilites
{
EasyTab->MaxPressure = Pressure.axMax;
EasyTab->RangeX = RangeX.axMax;
EasyTab->RangeY = RangeY.axMax;
}
}
return EASYTAB_OK;
}
#undef GETPROCADDRESS
EasyTabResult EasyTab_HandleEvent(HWND Window, UINT Message, LPARAM LParam, WPARAM WParam)
{
PACKET Packet = { 0 };
if (Message == WT_PACKET &&
(HCTX)LParam == EasyTab->Context &&
EasyTab->WTPacket(EasyTab->Context, (UINT)WParam, &Packet))
{
POINT Point = { 0 };
Point.x = Packet.pkX;
Point.y = Packet.pkY;
ScreenToClient(Window, &Point);
EasyTab->PosX = Point.x;
EasyTab->PosY = Point.y;
EasyTab->Pressure = (float)Packet.pkNormalPressure / (float)EasyTab->MaxPressure;
EasyTab->Buttons = Packet.pkButtons;
return EASYTAB_OK;
}
return EASYTAB_EVENT_NOT_HANDLED;
}
void EasyTab_Unload()
{
if (EasyTab->Context) { EasyTab->WTClose(EasyTab->Context); }
if (EasyTab->Dll) { FreeLibrary(EasyTab->Dll); }
free(EasyTab);
EasyTab = NULL;
}
#endif // WIN32
// -----------------------------------------------------------------------------
#endif // EASYTAB_IMPLEMENTATION

1
Externals/glfw vendored Submodule

@ -0,0 +1 @@
Subproject commit 3eaf1255b29fdf5c2895856c7be7d7185ef2b241

7987
Externals/imageIO/stb_image.h vendored Normal file

File diff suppressed because it is too large Load diff

1724
Externals/imageIO/stb_image_write.h vendored Normal file

File diff suppressed because it is too large Load diff

1
Externals/imgui vendored Submodule

@ -0,0 +1 @@
Subproject commit 4144d7d772a800f08693b8b13f7c81f1f22a73c4

1
Externals/lalr vendored Submodule

@ -0,0 +1 @@
Subproject commit 6d16a6bb60490a2ee4e86f689c86e647b300c7fb

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