Compare commits

..

488 Commits

Author SHA1 Message Date
889fe04255 [nostalgia/studio] Set version to 2024.05.0
All checks were successful
Build / build (push) Successful in 2m29s
2024-05-23 22:11:52 -05:00
eed115b287 [keel] Fix a GCC break
All checks were successful
Build / build (push) Successful in 2m39s
2024-05-17 21:13:15 -05:00
7233da75ea [ox/std] Remove dedicated keys array from SmallMap
All checks were successful
Build / build (push) Successful in 2m31s
2024-05-11 01:59:40 -05:00
30797c710b [ox/std] Add small sz option to SmallMap 2024-05-11 00:53:31 -05:00
e8041121d0 [ox/std] Add missing oxExpect to timeMapStrToUuid
All checks were successful
Build / build (push) Successful in 2m32s
2024-05-11 00:26:57 -05:00
d054528e49 [ox/std] Remove empty if from SmallMap
Some checks failed
Build / build (push) Has been cancelled
2024-05-11 00:24:37 -05:00
09d840cfd0 [ox/std] Add some functions for comparing HashMap and SmallMap
All checks were successful
Build / build (push) Successful in 2m31s
2024-05-10 23:58:35 -05:00
aeb1ef3b12 [ox/std] Cleanup SmallMap, make it easier to make potential changes 2024-05-10 23:58:22 -05:00
b66f61c217 [ox/std] Add hash function for UUID 2024-05-10 23:55:41 -05:00
b089bf460b [ox/std] Optimize Array compare 2024-05-10 23:54:22 -05:00
cd60c4abaf [ox/std] Fix bugs in HashMap and SmallMap
All checks were successful
Build / build (push) Successful in 2m30s
2024-05-10 22:10:34 -05:00
d1845448c3 [ox/std] Add == and != operators to UUID 2024-05-10 22:10:14 -05:00
c4f6ee0026 [nostalgia,olympic] Make performPackTransforms update type id when needed 2024-05-10 19:51:03 -05:00
17f28d43d1 [ox/clargs] Replace C string with StringView
All checks were successful
Build / build (push) Successful in 2m27s
2024-05-10 01:30:54 -05:00
043df533b7 [ox] Cleanup string len handling
Some checks failed
Build / build (push) Has been cancelled
Remove UTF-8 parsing. It is a rare enough need that it should have a specialized call when needed.
Better to have a more optimal length fetch for typical case.
2024-05-10 01:29:13 -05:00
bec75d2eba [ox/std] Fix memory leak in Vector 2024-05-09 23:12:36 -05:00
f624c720f9 [studio] Fix broken readClaw call
All checks were successful
Build / build (push) Successful in 2m29s
2024-05-08 23:54:06 -05:00
204e5bbff4 [ox/std] Add SmallMap
All checks were successful
Build / build (push) Successful in 2m28s
2024-05-08 23:46:12 -05:00
1ecf197a9e [nostalgia] Remove .idea directory 2024-05-08 23:44:05 -05:00
74a8a7d751 [ox/std] Remove incomplete writeF32toa
All checks were successful
Build / build (push) Successful in 2m28s
2024-05-08 23:43:12 -05:00
331f721292 [olympic,nostalgia] Cleanup
All checks were successful
Build / build (push) Successful in 2m31s
2024-05-08 23:35:34 -05:00
63486c23d4 [ox] Cleanup 2024-05-08 23:35:05 -05:00
47a6a410c4 [ox/std] Update Vector memory map for preloader
All checks were successful
Build / build (push) Successful in 2m31s
2024-05-03 23:41:16 -05:00
d82c082256 [buildcore] Add error message to pybb debug for missing debugger
All checks were successful
Build / build (push) Successful in 2m29s
2024-05-03 22:58:36 -05:00
227f3cd9f5 [nostalgia/core/studio] Update itoa usages
All checks were successful
Build / build (push) Successful in 2m34s
2024-05-03 20:32:18 -05:00
20ff0f89fe [ox/std] Rework itoa 2024-05-03 20:31:40 -05:00
4061b8314e [ox/model] Remove broken global var
All checks were successful
Build / build (push) Successful in 2m29s
2024-05-03 00:12:34 -05:00
18bb50626d [ox/std] Add String::append(StringView), cleanup
All checks were successful
Build / build (push) Successful in 2m30s
2024-05-03 00:07:03 -05:00
6a4b48221f [nostalgia,studio] Fixes for Ox changes 2024-05-03 00:00:05 -05:00
d2a3cfa72e [ox/std] Remove append operators from IString
This is because the append operators cannot report the failure that is possible with IString
2024-05-02 23:59:19 -05:00
7c4e2a6564 [ox/std] Cleanup IString 2024-05-02 23:33:39 -05:00
e30ebce4c0 [nostalgia] Add pyenv to .gitignore
All checks were successful
Build / build (push) Successful in 2m34s
2024-05-02 23:15:01 -05:00
7163947efd [ox/std] Cleanup 2024-05-02 23:14:03 -05:00
0a0a6e306d [studio] Move UndoCommand implementation to its own file 2024-05-02 22:50:25 -05:00
97bc9332d3 [nostalgia/core] Fix TileSheetV1 to use PaletteV1 2024-05-02 22:48:35 -05:00
9caf7099b6 [keel] Fix for Ox change 2024-05-02 22:21:04 -05:00
fda1280d29 [ox/std] Make substr always take and return a StringView 2024-05-02 22:20:25 -05:00
59aa4ad21a [cityhash] Cleanup 2024-05-02 22:20:01 -05:00
1a8afa1a98 [nostalgia/sample_project] Add missing type descriptor 2024-05-02 22:11:52 -05:00
cdbc2d6cc8 [olympic/studio] Move UndoCommand to its own file 2024-05-02 22:09:35 -05:00
acd93337d4 [ox/std] Fix Integer assignment operator return
All checks were successful
Build / build (push) Successful in 2m27s
2024-04-29 22:54:34 -05:00
cebd3b0a0f [ox/std] Fix Integer assignment operator return 2024-04-29 22:52:34 -05:00
43e2e2155b [ox/std] Cleanup 2024-04-29 22:48:22 -05:00
be1f90955b [ox/std] Make safeDelete constexpr
All checks were successful
Build / build (push) Successful in 2m32s
2024-04-29 22:43:27 -05:00
0f2c18d554 [ox/std] Add std::string(_view) variant of MaybeView
All checks were successful
Build / build (push) Successful in 2m29s
2024-04-25 23:03:38 -05:00
0c0ccd1a69 [nostalgia/core/studio] Cleanup scratchpad code
All checks were successful
Build / build (push) Successful in 2m32s
2024-04-24 23:09:50 -05:00
1b629da8fc [ox/std] Make Vector::contains always noexcept
All checks were successful
Build / build (push) Successful in 2m29s
2024-04-24 21:39:02 -05:00
32e4702dc7 [ox] Improve hasing and MaybeView
All checks were successful
Build / build (push) Successful in 2m29s
* Add CityHash dep
* Use CityHash for HashMap
* Make MaybeView more versatile
* Cleanup some inappropriate MaybeView uses
2024-04-24 20:59:37 -05:00
6b47133c22 [nostalgia] Cleanup StudioModules
All checks were successful
Build / build (push) Successful in 2m22s
2024-04-24 00:58:10 -05:00
0764720f9a [nostalgia,olympic] Update for Ox changes 2024-04-24 00:54:43 -05:00
78955376d6 [glutils] Update for Ox changes 2024-04-24 00:54:25 -05:00
a00a0bd2ff [ox] Rename BString to IString 2024-04-24 00:54:02 -05:00
ed4f0e1f2b [nostalgia,olympic] Replace oxIgnoreError with std::ignore 2024-04-22 23:43:22 -05:00
ea1feb726e [ox] Remove oxIgnoreError 2024-04-22 23:40:42 -05:00
e9a6a09629 [ox] Run liccor
All checks were successful
Build / build (push) Successful in 2m20s
2024-04-21 17:01:48 -05:00
d7f309750e Merge commit 'c0baf7efca0e4c3a86a018ad2564d9df7b07c133'
All checks were successful
Build / build (push) Successful in 2m22s
2024-04-21 13:13:26 -05:00
84205879d4 [olympic] Cleanup ItemMaker, remove unnecessary copy
All checks were successful
Build / build (push) Successful in 2m22s
2024-04-21 10:32:42 -05:00
ebf3a6961e [ox/std] Add String constructor that takes a StringLiteral 2024-04-21 10:31:26 -05:00
eeb2a5a151 [olympic/studio] Add new ImGui util functions 2024-04-21 10:24:53 -05:00
453f2750dd [nostalgia/core/studio] Cleanup context types 2024-04-21 10:24:29 -05:00
189ba4c545 [olympic/studio] Make studio::run static 2024-04-21 10:23:55 -05:00
057738088e [olympic] Change TypeId building to use constexpr globals 2024-04-21 10:23:22 -05:00
272eabc732 [nostalgia/core/opengl] Unbind vertex arrays when done with them 2024-04-21 10:22:32 -05:00
a02566697a [glutils] Remove trailing whitespace 2024-04-21 10:21:44 -05:00
dfd27afd67 [ox/std] Add implicit String constructor for str literals
All checks were successful
Build / build (push) Successful in 2m20s
Also make String more constexpr friendly
2024-04-18 23:59:47 -05:00
6bfe184261 [ox/std] Remove unnecessary copying from HashMap::expand
All checks were successful
Build / build (push) Successful in 2m21s
2024-04-18 23:39:33 -05:00
700d7016d5 [nostalgia] Update for Ox changes 2024-04-18 23:33:06 -05:00
922323833c [ox] Cleanup 2024-04-18 23:32:54 -05:00
3b8d13dce3 [nostalgia,olympic] Fixes for Ox update
All checks were successful
Build / build (push) Successful in 2m25s
2024-04-18 19:25:07 -05:00
a20d7fd923 [ox] Cleanup 2024-04-18 19:24:56 -05:00
6808adc8a1 [ox/std] Replace ox::ignore with std::ignore 2024-04-13 00:35:49 -05:00
abc076d657 [ox/std] Cleanup 2024-04-13 00:10:09 -05:00
1b790a34c4 [ox/std] Fix Signed_c and Unsigned_c 2024-04-13 00:07:40 -05:00
9220271630 [nostalgia/core] Update pack transforms to use ModelTypeId_v 2024-04-10 22:20:26 -05:00
7941a514ba [ox/model] Add constexpr ModelTypeId_v 2024-04-10 00:00:48 -05:00
0c09c5306e [ox/std] Fix sfmt constexpr problems 2024-04-09 23:47:18 -05:00
3ff91af86b [ox/std] Sort of fix custom assert 2024-04-09 23:46:54 -05:00
79b42e1df7 [ox/std] Fix some Vector constexpr problems 2024-04-09 23:46:12 -05:00
5eec9085f8 [ox/std] Add nodiscard to some string functions 2024-04-09 22:40:37 -05:00
af7c89564c [ox/std] Add ox::ignore 2024-04-09 22:40:20 -05:00
2c0e02277c [ox/std] Add assert to AnyPtr::Wrap::copyTo to ensure sufficiently large buff
All checks were successful
Build / build (push) Successful in 2m39s
2024-03-24 02:22:37 -05:00
e3c74637db [turbine] Make applicationData return const&
All checks were successful
Build / build (push) Successful in 2m35s
2024-03-23 17:19:33 -05:00
41e08d67aa [turbine] Make keyEventHandler nodiscard 2024-03-23 17:12:44 -05:00
50f3479d10 [ox/std] Make AnyPtr constexpr
All checks were successful
Build / build (push) Successful in 2m38s
2024-03-23 17:05:20 -05:00
1616ca7018 [turbine] Replace WrapPtr with ox::AnyPtr
All checks were successful
Build / build (push) Successful in 2m33s
2024-03-23 16:53:04 -05:00
3fa247e3d4 [ox/std] Add AnyPtr 2024-03-23 16:52:43 -05:00
27f1df8f33 [nostalgia,olympic] Further reduce use of applicationData 2024-03-23 16:07:49 -05:00
a4f0c7cdb5 [nostalgia/core/studio] Remove applicationData usages
All checks were successful
Build / build (push) Successful in 2m35s
2024-03-23 14:52:30 -05:00
6a52319156 [turbine] Cleanup applicationData
All checks were successful
Build / build (push) Successful in 2m38s
2024-03-17 20:59:14 -05:00
205f2a698c [turbine] Fix applicationData to properly return null 2024-03-17 20:05:01 -05:00
82f02896c9 [turbine] Cleanup type safety code for application data
All checks were successful
Build / build (push) Successful in 2m35s
2024-03-17 14:33:14 -05:00
aa43cb3d8d [turbine] Add some type safety to application data
All checks were successful
Build / build (push) Successful in 2m34s
2024-03-16 23:10:44 -05:00
05d08a7687 Merge commit 'd6403991d49292d4f2b7d441636949472ca2b249'
All checks were successful
Build / build (push) Successful in 2m22s
2024-03-14 23:33:20 -05:00
c6750d50fc [studio/modlib] Add ig::ChildStackItem 2024-03-14 23:32:05 -05:00
dade484d87 [olympic/studio] Make StudioContext::ui a ref instead of ptr 2024-03-14 23:31:01 -05:00
04f3d6b491 [keel] Fix some static const vars to be constexpr
All checks were successful
Build / build (push) Successful in 2m23s
2024-02-29 23:53:36 -06:00
b015fe88b7 [ox/std] Make ranges predicates const refs 2024-02-17 11:43:25 -06:00
db2dc28f92 [keel] Remove use of removed ModelValue operator
All checks were successful
Build / build (push) Successful in 2m24s
2024-02-11 20:35:48 -06:00
74fb051ef2 [ox] Remove panicing ModelValue operators 2024-02-11 20:35:19 -06:00
24fda7d589 [ox] Make serialize and allocate Writer_c functions take refs
All checks were successful
Build / build (push) Successful in 2m18s
2024-02-11 19:39:29 -06:00
a60cdf0a61 Merge commit '9c712cc38ae706b021807b271899bce56c234fa5' 2024-02-11 17:30:45 -06:00
b97d7d9956 [ox/preloader] Remove debug code
Some checks are pending
Build / build (push) Waiting to run
2024-02-11 17:29:54 -06:00
ce1eea817d [olympic/keel] Remove debug line 2024-02-11 17:28:19 -06:00
9a0a2fd46a Merge commit '56f9d7a4634c9de9b09df390c4385c67ab646607' 2024-02-11 17:24:22 -06:00
4e50889b5c [ox/model,ox/preloader] Add ability to handle inline arrays
Some checks are pending
Build / build (push) Waiting to run
2024-02-11 17:23:38 -06:00
9c0acf1b8f Merge commit 'ace68f7c1d870ed53e69c55ba53709a9425388be' 2024-02-04 10:21:12 -06:00
ee05118478 [ox] Add ability for ModelValue to represent inline arrays, add to preloader
Some checks failed
Build / build (push) Failing after 17s
2024-02-04 10:19:30 -06:00
a41e93c582 Merge commit '8e0467ca5fdb3f983738a97c17cba742a0d233fd' 2024-02-01 21:07:56 -06:00
59fa39070f [keel] Update pack for Preloader changes
All checks were successful
Build / build (push) Successful in 2m19s
2024-02-01 21:07:42 -06:00
c55994f67d [ox/std] Add Vector::capacity 2024-02-01 21:06:53 -06:00
e81d28a681 [ox] Fix various preloader problems 2024-02-01 21:06:35 -06:00
0626c2a815 [ox/fs] Add comparison operator for FileAddress 2024-02-01 21:02:46 -06:00
dbcd37d7ea Merge commit '0d61e5a064382a7076b62d32b25c70298ee0706e' 2024-01-31 23:18:13 -06:00
10a12f2ab2 [nostalgia/core] Add getTileCnt to header
All checks were successful
Build / build (push) Successful in 2m23s
2024-01-31 23:17:59 -06:00
2667be88f6 [nostalgia/core] Add largestPage function for Palette 2024-01-31 23:17:46 -06:00
5972d8acef [nostalgia/core] Fix TileSetEntry model 2024-01-31 23:17:28 -06:00
9c026e1a6c [nostalgia/core/studio] Add function to remove unused data from TileSheets 2024-01-31 23:17:09 -06:00
1dff26d895 [nostalgia/core] Add getTileCnt and fix getTileIdx 2024-01-31 23:16:41 -06:00
ff2eb5b11b [olympic/keel] Remove const r-value funcion from AssetRef 2024-01-31 23:15:53 -06:00
6a500345b4 Merge commit '057272347486efe5046691f32f51604e3a594e6a' 2024-01-31 23:13:34 -06:00
28b1c6dcf4 [ox/preloader] Fix case where alignOf always used NativePlatSpec
All checks were successful
Build / build (push) Successful in 2m21s
2024-01-31 23:07:40 -06:00
ef9cb8bea4 [olympic/modlib] Add ListBox to ImGui util 2024-01-30 21:46:38 -06:00
0d106bde21 [ox/oc] Fix objects to always write when members of arrays 2024-01-30 21:45:58 -06:00
f038b89ab4 Merge commit 'cfc27a384b00388fc1ce30ac47c266ddd1f8e6f1' 2024-01-28 18:05:09 -06:00
b75bbc4d20 [olympic,nostalgia] Change order of oxModelFieldRename args
All checks were successful
Build / build (push) Successful in 2m22s
2024-01-28 18:03:50 -06:00
227dd68a4f [ox/model] Change order of oxModelFieldRename args 2024-01-28 18:03:50 -06:00
02db760b8c [olympic] Add more ImGui helpers, studio::Editor::pushCommand 2024-01-28 18:03:12 -06:00
09c57545bc [ox/std] Add Vector::at
All checks were successful
Build / build (push) Successful in 2m22s
2024-01-28 16:29:39 -06:00
b9fddd47c2 Merge commit 'db978290f3465d2da30a27a98b12face50bbe091' 2024-01-27 23:55:20 -06:00
f128664a81 [olympic/studio] Add ig::IndentStackItem
All checks were successful
Build / build (push) Successful in 2m28s
2024-01-27 23:54:57 -06:00
e84df7801e [glutils] Add ProgramSource::vboLen 2024-01-27 23:53:32 -06:00
caa59f3724 [nostalgia/core] Add functions for mapping tile idx to subsheet 2024-01-27 23:52:40 -06:00
1cf09433e8 [nostalgia/core/studio] Cleanup TileSheetEditor with new GlUtils helpers 2024-01-27 23:51:51 -06:00
9948346ce4 [ox/model] Fix clangd false alarm 2024-01-27 23:40:16 -06:00
aa8200beed [glutils] Add helper functions for setting up shaders 2024-01-27 23:39:03 -06:00
961ab75662 Merge commit 'ae1f8ce11a81624f376be3a3dd56e80ba479dd89' 2024-01-20 15:41:04 -06:00
124c7029bd [olympic/studio] Change Studio modules to pass StudioContext instead of turbine::Context
All checks were successful
Build / build (push) Successful in 2m23s
2024-01-20 15:40:08 -06:00
d740609c8e Merge commit '6640e00ad9ee5b731a2ddb06da31436463c3ae65' 2024-01-20 15:02:16 -06:00
5d1f680a51 [nostalgia/core] Cleanup TileSheetEditor with new ImGui util functions
All checks were successful
Build / build (push) Successful in 2m21s
2024-01-20 14:59:43 -06:00
08be822bdd [ox/fs] Add FileAddress::operator==(FileAddress) 2024-01-19 20:22:52 -06:00
c2e34b6456 Merge commit 'a9128caf4ddd187f14496b84242dfe07ee9a6467'
All checks were successful
Build / build (push) Successful in 2m32s
2024-01-19 01:09:23 -06:00
173d3f4bc7 [olympic/studio] Add PushButton, PopupBtns, ComboBox, and IDStackItem to ImGui utils 2024-01-19 01:09:10 -06:00
8a29c0952c [olympic/studio] Fix imguiutil.hpp name, add StudioContext::tctx 2024-01-19 00:15:28 -06:00
5848bc8eb7 [nostalgia/core/studio] Change Subsheet Editor button position
All checks were successful
Build / build (push) Successful in 2m21s
2024-01-18 22:09:09 -06:00
7ba66787f8 [nostalgia/core/studio] Cleanup
All checks were successful
Build / build (push) Successful in 2m29s
2024-01-18 01:27:31 -06:00
e367575974 [olympic/studio] Fix NewMenu not to overwrite existing files or create a file without name
All checks were successful
Build / build (push) Successful in 2m30s
2024-01-18 00:24:11 -06:00
2bc2003caa [nostalgia/core/studio] Add key shortcuts for switching Palette pages
All checks were successful
Build / build (push) Successful in 2m22s
2024-01-17 22:48:53 -06:00
b31062e609 [nostalgia] Update liccor file 2024-01-17 22:36:09 -06:00
e4285bd48b [nostalgia/studio] Tweak background color of TileSheet editor
All checks were successful
Build / build (push) Successful in 2m20s
2024-01-17 22:23:22 -06:00
a76638cc86 [olympic/studio] Make Project::romFS return a reference 2024-01-17 22:08:22 -06:00
5433fd9b1d [nostalgia/core] Add new version of Palette with pages
All checks were successful
Build / build (push) Successful in 2m35s
2024-01-17 01:30:29 -06:00
b46cb65b7f [nostalgia/studio] Add version
All checks were successful
Build / build (push) Successful in 2m24s
2024-01-05 21:54:22 -06:00
877349df46 [nostalgia/core/studio] Increase max tilesheet export size, fix input handling when popups open 2024-01-04 22:47:57 -06:00
5418c06296 [olympic] Change olympic::s_version to olympic::appVersion
All checks were successful
Build / build (push) Successful in 2m17s
2024-01-01 14:14:16 -06:00
dd9c1100c3 [glutils] Update copyright for 2024
All checks were successful
Build / build (push) Successful in 2m16s
2024-01-01 12:06:57 -06:00
db82aee7c7 [teagba] Update copyright for 2024 2024-01-01 12:06:57 -06:00
edf15858ca [teagba] Update copyright for 2024
All checks were successful
Build / build (push) Successful in 2m19s
2024-01-01 12:04:09 -06:00
d1efbb2ffa [ox] Update copyright for 2024 2024-01-01 12:03:16 -06:00
051623f4b5 [olympic,nostalgia] Update copyright for 2024 2024-01-01 12:02:40 -06:00
055d64b125 [olympic] Add support for an AppLib app specific version
All checks were successful
Build / build (push) Successful in 2m20s
2023-12-31 23:18:17 -06:00
de9f842640 [ox/std] Add error.hpp include to memory.hpp
All checks were successful
Build / build (push) Successful in 2m15s
2023-12-31 22:52:10 -06:00
200e586768 Add .idea to .gitignore 2023-12-31 22:52:10 -06:00
f1609519a7 [olympic] Cleanup 2023-12-31 22:52:10 -06:00
e452d9db4f [nostalgia] Add python3-mypy to Debian deps 2023-12-31 22:52:10 -06:00
43a87b606e [nostalgia] Ensure pkg-gba reads .current_build without a new line
All checks were successful
Build / build (push) Successful in 2m20s
2023-12-30 13:59:10 -06:00
8acc6244d5 [olympic/keel] Improve error clarity on pack some common failures 2023-12-30 13:58:42 -06:00
bd2aeee276 [ox/claw] Improve error clarity when loading ModelObjects 2023-12-30 13:57:51 -06:00
89fab5cc20 [ox/fs] Remove stdc++fs from library list on Linux
All checks were successful
Build / build (push) Successful in 2m10s
2023-12-30 01:05:46 -06:00
1c06ea677f [nostalgia] Add links to Tonc and GBATEK to developer-handbook
All checks were successful
Build / build (push) Successful in 2m7s
2023-12-29 19:05:10 -06:00
6b948ee069 Merge commit '932c3e57e93d63dc98c454015afea941416ff423'
All checks were successful
Build / build (push) Successful in 2m8s
2023-12-29 18:44:06 -06:00
72dddcaee5 [ox] Fix TypeDescWriter segfault 2023-12-29 18:42:59 -06:00
7c824e910c [nostalgia] Remove Jenkinsfiles
All checks were successful
Build / build (push) Successful in 2m5s
2023-12-29 02:28:53 -06:00
a0c8146396 [nostalgia/core/studio] East const some function args
All checks were successful
Build / build (push) Successful in 2m5s
2023-12-29 00:06:18 -06:00
d5b232f5d5 [olympic/studio] Fix array bounds issue
All checks were successful
Build / build (push) Successful in 2m5s
2023-12-28 23:52:31 -06:00
c79fe3be43 [buildcore] Make CMake configure failure trigger failed return code
Some checks failed
Build / build (push) Has been cancelled
2023-12-28 23:50:30 -06:00
1df4e78084 [olympic/studio] Add new project menu, make file creation open file
Some checks failed
Build / build (push) Failing after 2m7s
2023-12-28 23:45:38 -06:00
ffbdb09c31 [olympic/turbine/glfw] Add shift key support 2023-12-28 23:41:33 -06:00
b35a956e4f [olympic/studio] Cleanup unused expression
All checks were successful
Build / build (push) Successful in 2m10s
2023-12-28 01:08:35 -06:00
d3847caab4 [olympic/studio] Make Project::writeObj only write descriptor if it does not already exist or if debug build
All checks were successful
Build / build (push) Successful in 2m9s
2023-12-28 00:24:18 -06:00
ae066a914c [olympic/studio] Fix Project::writeObj to ensure parent directory of file exists
All checks were successful
Build / build (push) Successful in 2m7s
2023-12-28 00:06:15 -06:00
67543af806 [ox/oc] Remove some unnecessary code
All checks were successful
Build / build (push) Successful in 2m3s
2023-12-27 23:50:02 -06:00
6b774ec285 [ox/oc] Fix array writing to write all values
All checks were successful
Build / build (push) Successful in 2m6s
This is necessary because OC array sizes are determined through the presence of the data.
2023-12-27 23:47:52 -06:00
4b9758f478 [nostalgia/core] Move most TileSheet member functions out of class
All checks were successful
Build / build (push) Successful in 2m4s
2023-12-27 23:10:38 -06:00
bf12b15fe6 [nostalgia/sample_project] Update some tilesheets to version 4 format 2023-12-26 20:28:55 -06:00
a7328eb5ef [nostalgia/core/studio] Reduce indent for Subsheet editor 2023-12-26 20:18:07 -06:00
b52124a0c5 [nostalgia/core/studio] Revert new subsheet index increment to happen after index assignment 2023-12-26 20:14:30 -06:00
eae9972f85 [nostalgia/sample_project] Add missing type descriptors 2023-12-26 18:55:35 -06:00
d83e392964 [nostalgia/core] Cleanup, revert CompactTileSheet version to 1
All checks were successful
Build / build (push) Successful in 2m2s
2023-12-26 18:50:33 -06:00
e2d0a784f1 [olympic/keel] Cleanup 2023-12-26 18:37:02 -06:00
f08821422a [nostalgia/core/studio] Change TileSheets to back to MC
All checks were successful
Build / build (push) Successful in 2m4s
2023-12-26 17:56:03 -06:00
6a2954f82b [nostalgia/core] Remove id from TileSheetV3::Subsheet, add TileSheetV4
Some checks failed
Build / build (push) Has been cancelled
2023-12-26 17:28:41 -06:00
9c19655ce2 [nostalgia/core] Fix build, add SubSheet ID to SubSheet Editor view
All checks were successful
Build / build (push) Successful in 2m5s
2023-12-26 16:37:09 -06:00
087c834b25 [nostalgia/core/studio] Fix Add SubSheet to increment idIt before using it
Some checks failed
Build / build (push) Failing after 23s
2023-12-26 16:34:40 -06:00
79bdbf2eaa [nostalgia/core] Add id to TileSheetV3::SubSheet model 2023-12-26 16:31:54 -06:00
2bdc3def74 [nostalgia/core/opengl] Implement flip X and flip Y for BG tiles
All checks were successful
Build / build (push) Successful in 2m4s
2023-12-26 12:34:35 -06:00
e7a663901a [nostalgia/core/opengl] Fix duplicate and missing symbol
All checks were successful
Build / build (push) Successful in 2m6s
2023-12-26 11:59:14 -06:00
ffdc0ddb97 [nostalgia/core] Add support for specifying palette banks
Some checks failed
Build / build (push) Failing after 40s
2023-12-26 11:54:31 -06:00
e941781f21 [ox/std] Cleanup Result::copyTo variants
All checks were successful
Build / build (push) Successful in 2m4s
2023-12-25 00:54:59 -06:00
b869f490c3 [ox/std] Add or_value to Optional, Result
All checks were successful
Build / build (push) Successful in 2m4s
2023-12-25 00:51:17 -06:00
caf8d93c21 [nostalgia] Delete .gitlab-ci.yml
All checks were successful
Build / build (push) Successful in 2m6s
2023-12-25 00:42:36 -06:00
afbf2caf97 [nostalgia] Remove conan from devenv
All checks were successful
Build / build (push) Successful in 2m5s
2023-12-24 06:41:18 -06:00
20914eaade [nostalgia] Add Gitea action file 2023-12-24 06:38:28 -06:00
c5f76ff558 [nostalgia/core] Add setBgBpp function 2023-12-23 21:33:52 -06:00
050339ba09 [nostalgia] Update developer-handbook 2023-12-23 19:08:18 -06:00
45ec39f77b [ox/std] Add Result::orVal 2023-12-23 17:52:20 -06:00
319fbb2600 [nostalgia] Add .lldbinit 2023-12-23 17:41:18 -06:00
f43d97a17e [nostalgia] Add missing type descriptors 2023-12-23 17:40:17 -06:00
a0974637a3 [nostalgia] Add missing test tilesheets 2023-12-23 17:39:43 -06:00
c90a8449be [olympic/turbine] Fix some broken CMake vars 2023-12-23 15:30:54 -06:00
95dcd6bee7 [teagba] Fix not to rely on TURBINE_BUILD_TYPE 2023-12-23 15:30:22 -06:00
5b167fd53b [nfde] Bump minimum CMake for NFDE to silence CMake warning 2023-12-23 15:01:21 -06:00
a701a241eb [imgui] Add target_include_directories for ImGui 2023-12-23 14:35:12 -06:00
9907bb8f1d [nostalgia] Allow building Studio mods without Studio app 2023-12-23 14:34:32 -06:00
9cb6bd4a32 [teagba] Cleanup CMake 2023-12-23 12:25:12 -06:00
2dba592a42 [nostalgia,olympic] Cleanup CMake 2023-12-23 12:23:47 -06:00
978f2f9c4f [nostalgia/core/gba] Cleanup 2023-12-23 01:50:26 -06:00
2bad4ee416 Add OLYMPIC_BUILD_STUDIO CMake var 2023-12-23 01:25:51 -06:00
46d1313797 [nostalgia/core] Get TileSheetSet working with 8bpp setting 2023-12-23 01:24:56 -06:00
fcf6f00797 [nostalgia/core] Get TileSheetSet working 2023-12-22 22:38:46 -06:00
ef6e3af735 [ox/model] Fix infinite recursion caused by have a vector of the same type in ModelValue 2023-12-22 19:44:04 -06:00
80d0df2f46 [ox/fs] Cleanup FileAddress model 2023-12-22 19:40:30 -06:00
9db10ec4a1 [ox/mc] Fix serialization of negative numbers in non-64 bit values 2023-12-22 19:36:42 -06:00
c460e0f9e0 [olympic/studio] Fix NewMenu to clear item name on reopen 2023-12-22 04:49:13 -06:00
3fa9d132ae [ox/mc] Fix issue with -1 union index 2023-12-22 04:42:13 -06:00
907ead2948 [ox/std] Fix Optional deref operator, in_place constructor 2023-12-22 04:41:39 -06:00
8526b3fa51 [nostalgia/core] Add loading multiple tile sheets 2023-12-22 01:03:41 -06:00
6de0e882e9 [teagba] Change sprite buffer to fully update on every VSync 2023-12-22 01:02:24 -06:00
d29118d783 [nostalgia/core] Cleanup graphics API 2023-12-21 21:18:31 -06:00
8395128efa [teagba] Update to newer conventions 2023-12-21 21:18:01 -06:00
77c86b9516 [ox/preloader] Add missing typenames 2023-12-20 23:04:34 -06:00
6d2a20e8bd [nostalgia/core/opengl] Allow GL implementation to customize sprite count and size 2023-12-20 23:01:56 -06:00
056284c857 [sample_project] Add ~ and | to charset 2023-12-20 22:08:26 -06:00
3787f6adb2 Make gitignore ignore all .gba and .sav files 2023-12-20 22:06:49 -06:00
ce34d450b9 [nostalgia/player] Turn player back into test sandbox 2023-12-20 20:13:54 -06:00
8fa47e961d [nostalgia/core/opengl] Disable depth testing once core scene is drawn 2023-12-20 19:22:47 -06:00
4e4cec1b64 [teagba] Change a reinterpret_cast to bit_cast 2023-12-20 19:01:31 -06:00
9840b6fdee [nostalgia/core] Add a background priority option 2023-12-20 19:00:23 -06:00
d0c90c39e0 [nostalgia/core/opengl] Cleanup priority, ensure sprites draw over BGs by default 2023-12-20 18:59:41 -06:00
7ba6fb3ac5 [ox/fs] Fix log message 2023-12-19 23:38:29 -06:00
8dd6adc554 [nostalgia/core] Specify a maximum for priority level 2023-12-19 23:06:14 -06:00
0093778f64 [nostalgia/core/opengl] Cleanup sprite enable/disable code 2023-12-19 22:55:41 -06:00
59016ee894 [nostalgia/core] Fix OpenGL sprites, add priority 2023-12-19 22:37:18 -06:00
2b8dbb88b2 [teagba] Fix applySpriteUpdates to reset update counter 2023-12-17 18:40:12 -06:00
7bc1d90be8 Restore some global CMake setting that were moved to nostalgia 2023-12-16 20:08:26 -06:00
cfb7d4f861 [nostalgia/studio] Add icon 2023-12-16 10:51:14 -06:00
7a6e94959c [nostalgia] Move nostalgia install vars to nostalgia dir CMakeLists.txt 2023-12-16 10:45:04 -06:00
eb1846278b [nostalgia/studio] Update app name 2023-12-16 10:35:28 -06:00
00c2a39dba [olympic] Cleanup 2023-12-16 03:05:57 -06:00
56f59b29fe [nostalgia/core/studio] Add scale option to TileSheet export 2023-12-16 02:58:54 -06:00
9b11fa4e91 [olympic/keel] Fix some unsafe pointer accesses, disconnect signals on asset move 2023-12-15 01:33:08 -06:00
72e54da017 [olympic/turbine] East const Turbine, cleanup 2023-12-15 00:54:55 -06:00
58d13a3ad9 [olympic/studio/modlib] East const Studio 2023-12-15 00:49:55 -06:00
5ae6df7e05 [olympic/applib] East const applib 2023-12-15 00:26:31 -06:00
f71d4d3efd [olympic/keel] Finish east consting Keel 2023-12-15 00:22:56 -06:00
4b824ddef4 [olympic] Change readClaw to take ref to TypeStore 2023-12-14 23:56:14 -06:00
8b3b8d50d6 [ox/claw] Change readClaw to take ref to TypeStore 2023-12-14 23:56:02 -06:00
1f2e9917f1 [nostalgia/core/opengl] Cleanup fragment shader 2023-12-14 23:47:00 -06:00
13ddbd981e [olympic,nostalgia] Cleanup some reinterpret_casts 2023-12-14 23:39:30 -06:00
3a781f6704 [ox/std] Improve r/l-value correctness of Result::to, make unwrap nodiscard 2023-12-14 22:41:05 -06:00
30909f85a3 [ox/std] Fix Result::copyTo 2023-12-14 22:33:03 -06:00
9cc27f5be9 [ox/std] Fix error handling for Result::copyTo 2023-12-14 22:28:16 -06:00
cdc7428eb6 [olympic,nostalgia] Update Result copyTo and moveTo calls to take refs 2023-12-14 22:26:55 -06:00
d31938ba4f [ox] Make Result copyTo and moveTo take refs 2023-12-14 22:26:17 -06:00
935099f8d4 [nostalgia] Re-enable Scene module 2023-12-14 22:03:39 -06:00
63608229e1 [nostalgia/scene/studio] Remove Scene maker from New Item wizard 2023-12-14 22:01:26 -06:00
e6803af22f [ox/mc] Fix more Clang issues 2023-12-14 21:35:02 -06:00
db961739ad [olympic/studio] Fix several crashes 2023-12-14 21:34:46 -06:00
2167a46266 [olympic/studio] Make copy/cut/paste enabled function noexcept 2023-12-14 19:37:24 -06:00
d1c6ab9f77 [nostalgia/core/studio] Cleanup TileSheetEditor, make it set copy/cut/paste enabled/disabled 2023-12-14 19:36:10 -06:00
c426decd99 [ox/oc] Fix C string writing 2023-12-14 19:28:14 -06:00
496afd66ea [ox/fs] Fix segfault in FileAddress 2023-12-14 19:27:47 -06:00
ad7f696a71 [glutils] Fix GLFrameBuffer to use right delete function 2023-12-14 19:08:37 -06:00
819e93bb1c [olympic/studio,nostalgia] Change Editor item name to item path, make
TileSheetEditorImGui inherit from Editor
2023-12-13 23:15:53 -06:00
960889749d [ox] Fix some template issue that come up with some versions of Clang, fix empty string read in OC 2023-12-13 22:46:13 -06:00
1b93b2038f [olympic,nostalgia] Move item name/path studio::Editor 2023-12-12 23:06:14 -06:00
d056323679 [nostalgia,olympic] Remove src as include directory 2023-12-12 20:31:05 -06:00
b10d9b6118 [developer-handbook] Cleanup ordering of Claw section 2023-12-12 20:24:31 -06:00
bd44fcf6ad [nfde] Update minimum CMake version 2023-12-12 20:24:20 -06:00
a1de7fbd8a [olympic,nostalgia] Make Applib an interface library that publicly exports applib.cpp 2023-12-12 20:23:54 -06:00
debeb83119 [glutils] Move glutils to deps 2023-12-11 22:57:59 -06:00
e2545a956b [olympic] Move keel, turbine, and studio to olympic 2023-12-11 22:48:22 -06:00
a60765b338 Use project name in Makefile throughout and pass to pkg-gba 2023-12-11 22:26:20 -06:00
dc233286b4 [nostalgia] Update logo 2023-12-11 22:21:45 -06:00
5b929b8796 [nostalgia] Move Olympic app parameters to NostalgiaProfile library 2023-12-11 22:21:01 -06:00
aea1aabcd7 [nostalgia] Restructure module register guards to behave more like include guards 2023-12-11 22:19:10 -06:00
3b8a9af97b [keel] Remove NostalgiaKeelModules as a dependency of keel 2023-12-11 22:16:16 -06:00
d54853a8b5 [studio/applib] Cleanup 2023-12-10 22:18:48 -06:00
d06412a6fe [nostalgia/tools] Remove old pack.cpp file 2023-12-10 22:16:23 -06:00
937e88ce7a [keel] Add missing file 2023-12-10 22:14:06 -06:00
9a5bdebbd7 [nostalgia] Rename nost-pack to nostalgia-pack 2023-12-10 22:12:02 -06:00
a2361c3fd9 [keel,nostalgia] AppLib-ize nost-pack 2023-12-10 22:10:37 -06:00
d6f0fe0cc8 [studio/applib] Remove separate logger instantiation 2023-12-10 21:35:01 -06:00
e3b2c66d70 [olympic/applib] Change applib run arguments 2023-12-10 21:33:45 -06:00
6dec1bf5ed [olympic/applib] Cleanup unused header 2023-12-10 21:10:35 -06:00
af1f674bc0 [olympic/applib] Move run function to olympic namespace 2023-12-10 21:07:17 -06:00
6a1e2f7566 [olympic/applib] Make applib module loading optional 2023-12-10 20:59:15 -06:00
393259a010 [nostalgia,olympic,studio] Add Olympic applib system, convert Studio to use it 2023-12-10 20:39:08 -06:00
b6b59e77f5 [nostalgia/core/studio] Cleanup TileSheetEditor commands 2023-12-10 17:27:18 -06:00
4a94672fdc [nostalgia/core/studio] Fix some use after move bugs 2023-12-10 17:17:03 -06:00
d22c968561 [nostalgia/core/studio] String hygiene change 2023-12-10 17:13:42 -06:00
79c85c2a33 [turbine] Cleanup 2023-12-10 17:03:58 -06:00
3ac3b7b5e6 [nostalgia,studio] Cleanup 2023-12-10 17:03:51 -06:00
8c9ebbedae [nostalgia,studio] Replace some String returns with StringView 2023-12-10 15:09:51 -06:00
dbd98fe18b [nostalgia/core/studio] Really pedantic formatting change 2023-12-10 02:00:54 -06:00
7418a7126a [nostalgia/core/studio] Restructure core studio for maintainability 2023-12-10 01:50:52 -06:00
d5a1e11ec5 [nostalgia/scene/studio] Fix vertical resizing to crop from bottom of view 2023-12-10 00:16:02 -06:00
f4a93d8419 [glutils] Change frame buffers to just use linear filtering 2023-12-10 00:10:51 -06:00
e923c73c91 [nostalgia/scene/studio] Simplify check for framebuffer resizing 2023-12-09 23:53:34 -06:00
4a9f035014 Disable some annoying clang-tidy warnings 2023-12-09 23:39:03 -06:00
b5ee68c90b [nostalgia/scene/studio] Fix SceneEditorView to work after switching tabs 2023-12-09 23:24:14 -06:00
e906237d76 [nostalgia/core/opengl] Remove debug line 2023-12-09 23:23:39 -06:00
6bcf29b8f2 [nostalgia/core] Cleanup 2023-12-09 23:20:48 -06:00
406388c042 [README] Add libgtk-3-dev to Debian dependency list 2023-12-09 23:20:12 -06:00
371044d63d [nostalgia] Fix scaling of SceneEditorView not to be completely broken 2023-12-09 23:18:04 -06:00
62c671e823 [nostalgia/core] Cleanup on TileSheet 2023-12-09 17:46:16 -06:00
0ac494998f [glutils] Add wrapper function around resizeInitFrameBuffer 2023-12-09 17:13:58 -06:00
500c012713 [nostalgia/core/studio] Cleanup TileSheetEditor constructor 2023-12-09 17:12:04 -06:00
1c4fb80702 Remove debug build from GitLab CI 2023-12-09 15:18:51 -06:00
a4fac4c1d3 [ox/fs] Some cleanup for FileAddress 2023-12-09 15:06:06 -06:00
115941a787 [nostalgia/core/studio] Fix palette selection reversion on undo of palette change 2023-12-09 12:57:16 -06:00
65a179e314 [nostalgia/player] Make error output actually check for error 2023-12-09 11:22:10 -06:00
eed240eacc [ox/mc] Fix test struct model, fix zeroing out of empty vectors in unions 2023-12-09 11:21:27 -06:00
cc7c7ac9d7 [ox/std] Fix more functions to work with UPter custom deleters 2023-12-09 01:33:33 -06:00
9a80196fa6 [nostalgia/core] Make Context definition private 2023-12-09 01:27:31 -06:00
8804819e17 [ox/model] Remove another const_cast 2023-12-09 00:50:14 -06:00
ade6af8698 [ox] Add optional typename to satisfy clangd 2023-12-09 00:49:37 -06:00
cd0958c691 [ox] Cleanup some const_casts 2023-12-09 00:49:03 -06:00
40a3c28fbf [turbine] Remove dead code 2023-12-09 00:32:39 -06:00
def994f406 [turbine/glfw] Enable GLFW_OPENGL_FORWARD_COMPAT on all platforms 2023-12-09 00:18:10 -06:00
e808859e29 [nostalgia/player] Give player a mechanism for reporting failure in release builds 2023-12-09 00:14:30 -06:00
9e9f30fb18 [nostalgia/core] Fix some GL rendering issues 2023-12-09 00:05:14 -06:00
facde6bdce [keel,nostalgia,studio,turbine] Cleanup structure of Turbine 2023-12-09 00:03:31 -06:00
1298051a1a [ox/std] Give UPter alias the other template parameter of UniquePtr 2023-12-08 22:33:36 -06:00
f169c96e78 [ox/claw] Remove ReadClaw from build 2023-12-07 00:15:08 -06:00
1547e8e550 Add OX_NODEBUG to GitLab CI 2023-12-07 00:08:37 -06:00
795b1add64 [nostalgia,studio] Fix includes 2023-12-06 23:59:03 -06:00
db91ea6a63 [glutils,nostalgia] Ptr to ref changes 2023-12-06 23:56:49 -06:00
7e19f45c69 [ox/std] Add SpanView::data() 2023-12-05 22:51:18 -06:00
57ba1caf90 [nostalgia] Cleanup headers 2023-12-05 22:50:03 -06:00
a5bdad448f [nostalgia/core] Cleanup headers, TileSheet versioning 2023-12-05 22:37:22 -06:00
54fcbb1a33 [studio] Adjust size of NewMenu, sort items, rename Quit to Cancel 2023-12-04 21:45:59 -06:00
195fd7a113 [nostalgia,studio] Cleanup, simplify string handling 2023-12-04 21:45:23 -06:00
0d606643f5 [ox/mc,ox/oc] Fix write for ox::Array, cleanup 2023-12-04 21:43:22 -06:00
402f54b3e3 [sample_project] Add ox FileAddress type descriptors 2023-12-04 00:45:59 -06:00
ed5fc079ee [studio/modlib] Fix project data directory in Project 2023-12-04 00:45:31 -06:00
140005799f [glutils,nostalgia/core] Move GlslVersion from GlUtils to Nostalgia Core 2023-12-04 00:40:25 -06:00
7d9a1676e8 [ox/claw] Test cleanup 2023-12-04 00:26:08 -06:00
b61f81abf0 [ox] Make tests more consistent 2023-12-04 00:22:00 -06:00
775efbddc8 [keel] Formatting fixes 2023-12-03 23:49:02 -06:00
1505d7ea37 [keel,nostalgia/tools,studio] Convert some pointers to references 2023-12-03 22:48:30 -06:00
26a2d340d6 [keel,studio] Cleanup string handling 2023-12-03 22:26:25 -06:00
ce514d586c [keel] Cleanup string handling 2023-12-03 22:15:22 -06:00
5cbf789374 [ox/std] Add lastIndexOf(StringView, char) 2023-12-03 22:14:42 -06:00
3f83a254d2 [keel] Fix UUID to path lookups to fail properly 2023-12-03 22:02:00 -06:00
348193ae9e [nostalgia,studio] Cleanup string handling 2023-12-03 22:01:38 -06:00
6b7c002a10 [nostalgia] Style updates 2023-12-03 21:14:20 -06:00
34081a0414 [turbine/gba] Make wake up time static 2023-12-03 20:38:23 -06:00
d23b69ce17 [nostalgia,studio] Cleanup 2023-12-03 19:59:27 -06:00
5717d67462 [nostalgia/core] Cleanup 2023-12-03 19:10:27 -06:00
7666bcc2db [keel,nostalgia] Cleanup pack, move toward further library-ization 2023-12-03 19:09:23 -06:00
8f5173e52a [ox/std] Add CStringView::CStringView(StringLiteral) 2023-12-03 19:06:37 -06:00
9ab3543b32 [ox/std] Rename Result::get to Result::copyTo 2023-12-03 19:03:42 -06:00
d16bbef282 [ox/std] Remove ox_strcpy 2023-12-03 19:03:08 -06:00
a8db357360 [ox/fs] Cleanup unnecessary constructors in FileAddress 2023-12-03 19:02:36 -06:00
566b724d36 [nostalgia] Update to new FileAddress constructor 2023-12-03 10:18:33 -06:00
b13eb0ef70 [ox/fs] Make FileAddress constructor take a StringLiteral 2023-12-03 10:17:24 -06:00
9855a0bcf0 [ox/std] Cleanup 2023-12-02 04:02:42 -06:00
611e2fa7cb [ox/std] Cleanup 2023-12-02 01:13:03 -06:00
95d9aee0cf [ox/std] Cleanup stdlib/non-stdlib specific build path in logging 2023-12-02 00:26:18 -06:00
3de03bf1fd [ox] Make String::String(String const&) explicit 2023-12-01 23:39:40 -06:00
742427584a [keel,nostalgia/core] Remove implicit String::String(String const&) calls 2023-12-01 23:38:59 -06:00
91fd0d0786 Disable GLFW tests, example programs, and docs in build 2023-12-01 23:00:17 -06:00
53262c53c4 [keel] Fix formatting 2023-12-01 22:54:27 -06:00
b212385b17 [studio] Cleanup ItemMaker constructors 2023-12-01 22:54:00 -06:00
453e08497d [keel,nostalgia] Make core calls take Context references instead of pointers 2023-12-01 22:53:21 -06:00
72c130d8a9 [ox/std] Fix Result move constructor, add & and && variants of unwrap 2023-12-01 22:50:25 -06:00
9904399724 [keel,studio,turbine] Finish removing implicit String(const char*) calls 2023-12-01 22:44:24 -06:00
1a1c8ae6cc [ox] Make ox::String::String(const char*) explicit 2023-12-01 22:36:24 -06:00
e9822bf124 [nostalgia,studio] Remove implicit ox::String::String(const char*) calls 2023-12-01 22:35:02 -06:00
644abd7f22 Get rid of separate test stage in gitlab-ci 2023-12-01 01:03:53 -06:00
1e8d8c8b9e [buildcore] Use python3 variable instead of python3 directly 2023-12-01 01:00:58 -06:00
eccb8c4fb3 Make gitlab-ci build release and test with release, debug, and asan 2023-12-01 00:53:51 -06:00
6b3974eb93 [buildcore] Make mypy run with python3 -m 2023-12-01 00:51:23 -06:00
f6058f4e07 Add gitlab-ci file 2023-12-01 00:50:45 -06:00
ecb09930db [turbine/glfw] Partially revert debug change 2023-12-01 00:06:58 -06:00
fc5e63a4d7 [ox/std] Make substr support CStringView, and always return a StringView 2023-11-30 23:15:51 -06:00
232a166833 [keel,nostalgia,studio] Make keel use references in place of a lot of pointers 2023-11-30 23:15:16 -06:00
95ba8eb138 [glutils] Do some cleanup with ox::CStringView 2023-11-30 22:06:03 -06:00
a37df08c19 [keel] Make Context::appName a BasicString<32> to generally avoid allocations while ensuring that Context owns a copy 2023-11-30 21:46:17 -06:00
0fc7e7005c [keel,nostalgia/tools/pack,studio] Cleanup 2023-11-30 21:45:03 -06:00
68a0dd9660 [ox/std] Give Vector MaybeSV in places where it makes sense 2023-11-30 21:28:11 -06:00
d635a954fa [ox/std] Add missing file, add more string types 2023-11-30 21:24:05 -06:00
d0f19fd51d [teagba] Make some globals static 2023-11-30 01:29:53 -06:00
dd16577b50 [ox/fs] Change substr function form 2023-11-30 01:02:29 -06:00
c0aa119155 [ox/fs] Add FileSystem::write variants that take Spans 2023-11-30 01:02:05 -06:00
3c9ce4436a [ox/fs] Make FileAddress::getPath return a StringView 2023-11-30 01:01:01 -06:00
2a692fc46e [ox/std] Add Span::data() 2023-11-30 01:00:38 -06:00
e543131f0d [nostalgia,studio] Cleanup Studio 2023-11-30 00:57:47 -06:00
c085c50b30 [nostalgia/pack] Update for Keel 2023-11-30 00:56:53 -06:00
bb8fb0469a [keel] Cleanup pack 2023-11-29 20:33:09 -06:00
15bc41dd35 [ox/std] Fix StringView(BaseStringView const&) constructor 2023-11-29 00:35:34 -06:00
85e7375f6f [buildcore] Cleanup 2023-11-28 23:34:12 -06:00
da98aa864c [keel,nostalgia,studio,turbine] Fixes for ox::String explicit change 2023-11-28 23:32:29 -06:00
3a62650d62 [ox/std] Make String(StringView) constructor explicit, add StringLiteral 2023-11-28 23:31:11 -06:00
7008ebfb40 [ox/std] Make HashMap use StringView for string lookups 2023-11-28 23:29:10 -06:00
709dc36d0b [ox/mc] Fix read test 2023-11-27 22:02:38 -06:00
540ed9b3f9 [keel,nostalgia,turbine] Change log channel delimiter from :: to . 2023-11-25 20:59:01 -06:00
ecc49a63b0 [ox] Change log channel delimiter from :: to . 2023-11-25 20:58:35 -06:00
c8ad05215f [glutils] Fix destructors 2023-11-24 13:46:46 -06:00
79b6046813 [nostalgia/studio] Fix main argc and argv for Windows 2023-11-24 11:10:28 -06:00
ed5271166e Update developer handbook 2023-11-23 18:22:22 -06:00
b946e428ad [keel,nostalgia,turbine] Cleanup 2023-11-23 01:46:11 -06:00
a84a829769 [ox] Cleanup String/StringView conversions, MallocaPtr 2023-11-23 01:34:16 -06:00
5b91ad25c2 [teagba] Fix MSVC warning 2023-11-14 20:24:21 -06:00
98983d1229 [nostalgia/core] Cleanup 2023-11-14 20:23:50 -06:00
b12097769e [ox/std] Fix MSVC warnings 2023-11-14 20:23:21 -06:00
99a7a2cbfc [buildcore] Fix arch output for host_env to be more consistent 2023-11-14 20:21:49 -06:00
e9c5134286 [ox/model] Fix compile error when instantiating ModelHandlerAdaptor for readers 2023-11-14 20:21:02 -06:00
b7a1236bae [ox/model] Fix MSVC warning 2023-11-14 20:19:25 -06:00
d386bc8c91 [ox/mc] Fix MC read alloca in a loop 2023-11-13 23:42:09 -06:00
3eec0a149d [ox/mc] Cleanup 2023-11-13 22:59:11 -06:00
8d2c8df014 [ox/mc] Fix an unwanted formatting "correction" from Visual Studio 2023-11-13 21:53:21 -06:00
18ace3ceff [ox/mc] Fix use of uncaptured var in lambda 2023-11-13 21:50:11 -06:00
8ddc8f40e5 [buildcore] Fix hostevn cmd to return OS instead of hostname 2023-11-13 21:46:53 -06:00
d7a6bc4ae4 [nostalgia/core/opengl] Fix sprite drawing for instances of core that are not application wide 2023-11-13 21:43:35 -06:00
597a8c736e [ox/mc] Fix alloca use in loop 2023-11-12 00:53:25 -06:00
d9b676d1b2 [ox/std] 32 bit system fixes 2023-11-12 00:41:47 -06:00
158115c29f [ox] Fix most MSVC warnings 2023-11-12 00:31:13 -06:00
109f272650 [nostalgia] More changes to accommodate for Windows 2023-11-12 00:14:52 -06:00
77e475980d [ox/model] Restore assert in modelFieldCount 2023-11-11 23:30:34 -06:00
f6d2d96ff9 [turbine] Cleanup 2023-11-11 23:24:21 -06:00
81d092e967 [buildcore] Windows fixes 2023-11-11 22:35:34 -06:00
3fbb2a0086 [ox/logconn] MSVC fixes 2023-11-11 21:57:25 -06:00
59c11e5309 [nostalgia] Make Windows builds of player and studio WIN32 apps 2023-11-11 21:45:23 -06:00
ce20282be0 [ox/std] MSVC fix 2023-11-11 21:14:59 -06:00
7ee52db6a1 [ox] MSVC fixes 2023-11-11 20:24:11 -06:00
868adae053 [nostalgia] Cleanup 2023-11-05 10:19:27 -06:00
4ae6fd7c17 [ox/std] Add uint_t 2023-11-05 10:18:39 -06:00
4d09eecb0d [ox/std] Fix Linux-AArch64 build 2023-10-30 01:20:21 -05:00
66d7627ed8 [ox/claw] Add missing file 2023-10-22 21:16:39 -05:00
bd9e27f977 Make gba-run and pkg-gba trigger build 2023-10-22 21:14:29 -05:00
ebb8b12c4e [ox/fs] Add ox::Buffer constructor to FileSystemTemplate 2023-10-22 20:35:57 -05:00
1f78ea1f37 [ox] Add Reader_c and make MetalClawReader use it 2023-10-22 16:42:03 -05:00
4ab710b155 [nostalgia/core] Move most TileSheet functions to cpp file 2023-10-21 01:19:04 -05:00
5eaa86a934 Update main Makefile to use host debugger 2023-09-30 13:40:13 -05:00
ba30caa9b2 [ox/std] Add SpanView 2023-09-30 13:38:19 -05:00
72346162a5 [keel,nostalgia] Add id() function to Keel modules 2023-09-30 13:34:45 -05:00
5cdf241321 [ox/preloader] Fix for what appears to be a bug in Apple Clang 2023-09-28 21:01:18 -05:00
b797b937f8 [nostalgia] Add Debian section to README.md 2023-09-24 10:17:18 -05:00
206b2825c8 [ox/std] Add Span type 2023-09-16 18:32:06 -05:00
b6f86551e9 [ox/std] Make assert functions take StringViews instead of C strings 2023-09-02 01:11:40 -05:00
1a7e551025 [ox/std] Fix Vector for MSVC 2023-08-30 21:01:20 -05:00
cc0da5dd6a [ox] Tell CMake that Ox is C++ only 2023-08-26 22:39:33 -05:00
e0bdb06b2a [buildcore] Update buildcore 2023-08-26 00:53:28 -05:00
6e0de04591 [buildcore] Update buildcore 2023-08-25 00:13:32 -05:00
897ee83984 Update main Makefile for new buildcore 2023-08-25 00:12:49 -05:00
84e82b224b [buildcore] Update buildcore 2023-08-25 00:12:40 -05:00
257389129f [buildcore] Update buildcore 2023-08-24 00:04:24 -05:00
6bd7a84ddd [ox] Cleanup, fix GBA build 2023-08-10 00:26:45 -05:00
f4ef762952 [ox/std] Fix broken invocation of Vector::reserveInsert 2023-08-09 00:31:56 -05:00
c1c41cfc99 [nfde] Cleanup CMakeLists to label UNIX systems generically as UNIX 2023-08-09 00:06:37 -05:00
987cd34df0 [ox/std] Fix Linux build 2023-08-09 00:04:08 -05:00
da6eb40966 [ox/std] Make ox::make handle std::exception to report what() 2023-08-09 00:01:17 -05:00
ead3fd39c4 [nostalgia/core/studio] Cleanup error handling for TileSheet open fail 2023-08-09 00:00:42 -05:00
d2b77804ff [glfw] Make GLFW use default library type 2023-08-08 23:59:33 -05:00
df709ad391 [nostalgia] Fix FreeBSD build 2023-08-08 23:58:08 -05:00
020a3ec3f4 [nfde] Fix FreeBSD build 2023-08-08 23:57:43 -05:00
e5a7d8c0a9 [ox] Fix FreeBSD build 2023-08-08 23:57:09 -05:00
ea266da691 [buildcore] Fix setup-build.py for FreeBSD 2023-08-05 19:01:44 -05:00
30017fd32e [nostalgia] Run liccor 2023-08-04 22:11:19 -05:00
22f8504e5a [turbine] Make window render during resizing 2023-07-16 14:18:29 -05:00
f514b33b06 [ox/std] Fix some type implicit conversions in ox_itoa 2023-07-16 13:53:28 -05:00
6e94c2be8d [studio] Remove debug print 2023-07-16 10:14:27 -05:00
3b24d6dee7 [studio] Add border to project explorer 2023-07-16 00:23:45 -05:00
660c320ee9 [studio] Cleanup main window drawing 2023-07-15 21:10:24 -05:00
4cf96878a9 [keel,nostalgia/core/studio] Fix asset update notifications 2023-07-15 20:14:35 -05:00
9ceb1df49e [nostalgia/core/studio] Remove unnecessary netsting level in PaletteEditor 2023-07-15 13:16:05 -05:00
ddcb53a535 [ox/std] Make mgba logging functions compile on all platforms 2023-07-11 21:58:22 -05:00
8ba461d77c [nostalgia] Update Mac path for run-studio 2023-07-02 18:31:04 -05:00
2b7e3c93e0 [nostalgia] Change pkg-gba to use the build copy of nost-pack 2023-07-02 00:10:58 -05:00
016f567c04 [nostalgia] Rewrite pkg-gba in Python 2023-07-01 19:58:57 -05:00
79d43b56fb [gbabuildcore] Fix for updated build paths 2023-07-01 16:19:29 -05:00
261b28f59f [nostalgia] Remove host from build path 2023-07-01 16:18:22 -05:00
d04d48124e [keel] Correct test path 2023-07-01 16:18:08 -05:00
280130c3cd [ox] Correct tests path 2023-07-01 16:17:41 -05:00
e89751dd72 Make libraries build as shared libraries on non-Apple/MS systems 2023-07-01 16:04:24 -05:00
da27447a4a [lodepng] Add install for lodepng 2023-07-01 16:03:58 -05:00
6166ab15db [ox] Make tests search in {build output}/bin dir for tests 2023-07-01 16:03:19 -05:00
498 changed files with 15406 additions and 10038 deletions

View File

@ -4,10 +4,9 @@ Checks: '-*,
cppcoreguidelines-interfaces-global-init, cppcoreguidelines-interfaces-global-init,
cppcoreguidelines-narrowing-conversions, cppcoreguidelines-narrowing-conversions,
cppcoreguidelines-pro-type-member-init, cppcoreguidelines-pro-type-member-init,
cppcoreguidelines-pro-type-static-cast-downcast, -cppcoreguidelines-pro-type-static-cast-downcast,
cppcoreguidelines-slicing, cppcoreguidelines-slicing,
google-default-arguments, google-default-arguments,
google-explicit-constructor,
google-runtime-operator, google-runtime-operator,
hicpp-exception-baseclass, hicpp-exception-baseclass,
hicpp-multiway-paths-covered, hicpp-multiway-paths-covered,
@ -53,10 +52,12 @@ readability-uniqueptr-delete-release,
readability-use-anyofallof, readability-use-anyofallof,
cert-*, cert-*,
misc-*, misc-*,
-misc-include-cleaner
-misc-use-anonymous-namespace, -misc-use-anonymous-namespace,
readability-duplicate-include, readability-duplicate-include,
-misc-non-private-member-variables-in-classes, -misc-non-private-member-variables-in-classes,
-misc-no-recursion, -misc-no-recursion,
-misc-include-cleaner,
bugprone-*, bugprone-*,
clang-analyzer-*, clang-analyzer-*,
modernize-*, modernize-*,

View File

@ -0,0 +1,19 @@
name: Build
run-name: ${{ gitea.actor }} build and test
on: [push]
jobs:
build:
runs-on: nostalgia
steps:
- name: Check out repository code
uses: actions/checkout@v3
- run: make purge configure-debug
- run: make build
- run: make test
- run: make purge configure-asan
- run: make build
- run: make test
- run: make purge configure-release
- run: make build
- run: make test

8
.gitignore vendored
View File

@ -2,9 +2,12 @@
.clangd .clangd
.current_build .current_build
.conanbuild .conanbuild
.idea
.mypy_cache .mypy_cache
.stfolder .stfolder
.stignore
scripts/__pycache__ scripts/__pycache__
pyenv
CMakeLists.txt.user CMakeLists.txt.user
ROM.oxfs ROM.oxfs
Session.vim Session.vim
@ -13,8 +16,7 @@ compile_commands.json
dist dist
graph_info.json graph_info.json
imgui.ini imgui.ini
nostalgia.gba *.gba
nostalgia.sav *.sav
nostalgia_media.oxfs
studio_state.json studio_state.json
tags tags

8
.idea/.gitignore generated vendored
View File

@ -1,8 +0,0 @@
# Default ignored files
/shelf/
/workspace.xml
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml
# Editor-based HTTP Client requests
/httpRequests/

View File

@ -1,22 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<code_scheme name="Project" version="173">
<Objective-C>
<option name="INDENT_NAMESPACE_MEMBERS" value="0" />
<option name="INDENT_CLASS_MEMBERS" value="8" />
<option name="INDENT_VISIBILITY_KEYWORDS" value="4" />
</Objective-C>
<Objective-C-extensions>
<extensions>
<pair source="cpp" header="hpp" fileNamingConvention="LOWERCASE" />
<pair source="c" header="h" fileNamingConvention="NONE" />
<pair source="cu" header="cuh" fileNamingConvention="NONE" />
</extensions>
</Objective-C-extensions>
<codeStyleSettings language="ObjectiveC">
<indentOptions>
<option name="USE_TAB_CHARACTER" value="true" />
<option name="SMART_TABS" value="true" />
</indentOptions>
</codeStyleSettings>
</code_scheme>
</component>

View File

@ -1,5 +0,0 @@
<component name="ProjectCodeStyleConfiguration">
<state>
<option name="PREFERRED_PROJECT_CODE_STYLE" value="DrinkingTea" />
</state>
</component>

View File

@ -1,17 +0,0 @@
/*
* Copyright 2016 - 2021 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#[[#pragma]]# once
${NAMESPACES_OPEN}
class ${NAME} {
};
${NAMESPACES_CLOSE}

View File

@ -1,13 +0,0 @@
/*
* Copyright 2016 - 2021 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#[[#include]]# "${HEADER_FILENAME}"
${NAMESPACES_OPEN}
${NAMESPACES_CLOSE}

View File

@ -1,24 +0,0 @@
<component name="InspectionProjectProfileManager">
<profile version="1.0">
<option name="myName" value="Project Default" />
<inspection_tool class="ClangTidy" enabled="true" level="WARNING" enabled_by_default="true">
<option name="clangTidyChecks" value="-*,cppcoreguidelines-interfaces-global-init,cppcoreguidelines-narrowing-conversions,cppcoreguidelines-pro-type-member-init,cppcoreguidelines-pro-type-static-cast-downcast,cppcoreguidelines-slicing,google-default-arguments,google-explicit-constructor,google-runtime-operator,hicpp-exception-baseclass,hicpp-multiway-paths-covered,mpi-buffer-deref,mpi-type-mismatch,openmp-use-default-none,performance-faster-string-find,performance-for-range-copy,performance-implicit-conversion-in-loop,performance-inefficient-algorithm,performance-inefficient-string-concatenation,performance-inefficient-vector-operation,performance-move-const-arg,performance-move-constructor-init,performance-no-automatic-move,performance-noexcept-move-constructor,performance-trivially-destructible,performance-type-promotion-in-math-fn,performance-unnecessary-copy-initialization,performance-unnecessary-value-param,readability-avoid-const-params-in-decls,readability-const-return-type,readability-container-size-empty,readability-convert-member-functions-to-static,readability-delete-null-pointer,readability-deleted-default,readability-inconsistent-declaration-parameter-name,readability-make-member-function-const,readability-misleading-indentation,readability-misplaced-array-index,readability-non-const-parameter,readability-redundant-control-flow,readability-redundant-declaration,readability-redundant-function-ptr-dereference,readability-redundant-smartptr-get,readability-redundant-string-cstr,readability-redundant-string-init,readability-simplify-subscript-expr,readability-static-accessed-through-instance,readability-static-definition-in-anonymous-namespace,readability-string-compare,readability-uniqueptr-delete-release,readability-use-anyofallof,cert-*,misc-*,readability-duplicate-include,-misc-non-private-member-variables-in-classes,-misc-no-recursion,bugprone-*,clang-analyzer-*,modernize-*,portability-*,-modernize-use-trailing-return-type,-bugprone-easily-swappable-parameters" />
</inspection_tool>
<inspection_tool class="Clazy" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ConstantConditionsOC" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ConstantFunctionResult" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="ConstantParameter" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="DanglingPointers" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="EndlessLoop" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="InfiniteRecursion" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="LocalValueEscapesScope" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="LoopDoesntUseConditionVariable" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="NullDereference" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="NullDereferences" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UnreachableCallsOfFunction" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UnreachableCode" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UnusedLocalVariable" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UnusedParameter" enabled="false" level="WARNING" enabled_by_default="false" />
<inspection_tool class="UnusedValue" enabled="false" level="WARNING" enabled_by_default="false" />
</profile>
</component>

17
.idea/misc.xml generated
View File

@ -1,17 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompDBSettings">
<option name="linkedExternalProjectsSettings">
<CompDBProjectSettings>
<option name="externalProjectPath" value="$PROJECT_DIR$" />
<option name="modules">
<set>
<option value="$PROJECT_DIR$" />
</set>
</option>
</CompDBProjectSettings>
</option>
</component>
<component name="CompDBWorkspace" PROJECT_DIR="$PROJECT_DIR$" />
<component name="ExternalStorageConfigurationManager" enabled="true" />
</project>

8
.idea/nostalgia.iml generated
View File

@ -1,8 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module version="4">
<component name="FacetManager">
<facet type="Python" name="Python facet">
<configuration sdkName="Python 3.8" />
</facet>
</component>
</module>

6
.idea/vcs.xml generated
View File

@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

View File

@ -2,4 +2,4 @@
source: source:
- src - src
copyright_notice: |- copyright_notice: |-
Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.

1
.lldbinit Normal file
View File

@ -0,0 +1 @@
type summary add --summary-string "${var.m_buff.m_items}" ox::String

View File

@ -11,34 +11,26 @@ endif()
include(deps/buildcore/base.cmake) include(deps/buildcore/base.cmake)
set(NOSTALGIA_BUILD_PLAYER ON CACHE BOOL "Build Player")
set(NOSTALGIA_BUILD_STUDIO ON CACHE BOOL "Build Studio")
set(OX_ENABLE_TRACEHOOK OFF CACHE BOOL "Generate OxTraceHook shared library for uprobes") set(OX_ENABLE_TRACEHOOK OFF CACHE BOOL "Generate OxTraceHook shared library for uprobes")
if(BUILDCORE_TARGET STREQUAL "gba") if(BUILDCORE_TARGET STREQUAL "gba")
set(NOSTALGIA_BUILD_STUDIO OFF)
set(TURBINE_BUILD_TYPE "GBA")
include(deps/gbabuildcore/base.cmake) include(deps/gbabuildcore/base.cmake)
else() else()
set(TURBINE_BUILD_TYPE "Native")
set(CMAKE_POSITION_INDEPENDENT_CODE ON) set(CMAKE_POSITION_INDEPENDENT_CODE ON)
endif() endif()
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
if(APPLE) if(APPLE)
set(CMAKE_MACOSX_RPATH OFF) set(CMAKE_MACOSX_RPATH OFF)
set(CMAKE_INSTALL_NAME_DIR "@executable_path/../Library/nostalgia")
set(NOSTALGIA_DIST_BIN nostalgia-studio.app/Contents/MacOS)
set(NOSTALGIA_DIST_LIB nostalgia-studio.app/Contents/Library)
set(NOSTALGIA_DIST_MODULE nostalgia-studio.app/Contents/Plugins)
set(NOSTALGIA_DIST_RESOURCES nostalgia-studio.app/Contents/Resources)
set(NOSTALGIA_DIST_MAC_APP_CONTENTS nostalgia-studio.app/Contents)
else() else()
set(CMAKE_INSTALL_RPATH "$ORIGIN" "$ORIGIN/../lib/ox" "$ORIGIN/../lib/nostalgia" "$ORIGIN/../") if(UNIX)
set(BUILD_SHARED_LIBS ON)
endif()
set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE) set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
set(NOSTALGIA_DIST_BIN bin)
set(NOSTALGIA_DIST_LIB lib)
set(NOSTALGIA_DIST_MODULE lib/nostalgia/modules)
set(NOSTALGIA_DIST_RESOURCES share)
endif() endif()
add_subdirectory(deps/ox) add_subdirectory(deps/ox)
@ -50,14 +42,18 @@ add_subdirectory(deps/teagba)
if(NOT BUILDCORE_TARGET STREQUAL "gba") if(NOT BUILDCORE_TARGET STREQUAL "gba")
include_directories( include_directories(
SYSTEM SYSTEM
deps/glfw/deps
deps/glfw/include deps/glfw/include
deps/imgui deps/imgui
deps/imgui/backends deps/imgui/backends
deps/nfde/src/include deps/nfde/src/include
/usr/local/include
) )
add_subdirectory(deps/glad) add_subdirectory(deps/glad)
set(GLFW_BUILD_EXAMPLES OFF)
set(GLFW_BUILD_TESTS OFF)
set(GLFW_BUILD_DOCS OFF)
add_subdirectory(deps/glfw) add_subdirectory(deps/glfw)
add_subdirectory(deps/glutils)
add_subdirectory(deps/imgui) add_subdirectory(deps/imgui)
add_subdirectory(deps/lodepng) add_subdirectory(deps/lodepng)
add_subdirectory(deps/nfde) add_subdirectory(deps/nfde)

View File

@ -31,7 +31,6 @@ RUN dnf install -y clang \
python3-pip \ python3-pip \
libglvnd-devel \ libglvnd-devel \
gtk3-devel gtk3-devel
RUN pip install conan
############################################################################### ###############################################################################
# Install devkitARM # Install devkitARM

View File

@ -1,39 +1,40 @@
PROJECT_NAME=nostalgia BC_VAR_PROJECT_NAME=nostalgia
BC_VAR_PROJECT_NAME_CAP=Nostalgia
BUILDCORE_PATH=deps/buildcore BUILDCORE_PATH=deps/buildcore
include ${BUILDCORE_PATH}/base.mk include ${BUILDCORE_PATH}/base.mk
ifeq ($(OS),darwin) ifeq ($(BC_VAR_OS),darwin)
NOSTALGIA_STUDIO=./build/${HOST}/${CURRENT_BUILD}/src/nostalgia/studio/nostalgia-studio.app/Contents/MacOS/nostalgia-studio NOSTALGIA_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}Studio.app/Contents/MacOS/${BC_VAR_PROJECT_NAME_CAP}Studio
MGBA=/Applications/mGBA.app/Contents/MacOS/mGBA MGBA=/Applications/mGBA.app/Contents/MacOS/mGBA
else else
NOSTALGIA_STUDIO=./build/${HOST}/${CURRENT_BUILD}/src/nostalgia/studio/nostalgia-studio NOSTALGIA_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}Studio
MGBA=mgba-qt MGBA=mgba-qt
endif endif
.PHONY: pkg-gba .PHONY: pkg-gba
pkg-gba: install pkg-gba: build
${ENV_RUN} ./scripts/pkg-gba sample_project ${BC_CMD_ENVRUN} ${BC_PY3} ./scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME}
.PHONY: run .PHONY: run
run: build run: build
./build/${HOST}/${CURRENT_BUILD}/src/nostalgia/player/nostalgia sample_project ./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME} sample_project
.PHONY: run-studio .PHONY: run-studio
run-studio: build run-studio: build
${NOSTALGIA_STUDIO} ${NOSTALGIA_STUDIO}
.PHONY: gba-run .PHONY: gba-run
gba-run: pkg-gba gba-run: pkg-gba
${MGBA} nostalgia.gba ${MGBA} ${BC_VAR_PROJECT_NAME}.gba
.PHONY: debug .PHONY: debug
debug: build debug: build
${DEBUGGER} ./build/${HOST}/${CURRENT_BUILD}/src/nostalgia/player/nostalgia sample_project ${BC_CMD_HOST_DEBUGGER} ./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME} sample_project
.PHONY: debug-studio .PHONY: debug-studio
debug-studio: build debug-studio: build
${DEBUGGER} ${NOSTALGIA_STUDIO} ${BC_CMD_HOST_DEBUGGER} ${NOSTALGIA_STUDIO}
.PHONY: configure-gba .PHONY: configure-gba
configure-gba: configure-gba:
${ENV_RUN} ${SETUP_BUILD} --toolchain=deps/gbabuildcore/cmake/modules/GBA.cmake --target=gba --current_build=0 --build_type=release --build_root=${BUILD_PATH} ${BC_CMD_SETUP_BUILD} --toolchain=deps/gbabuildcore/cmake/modules/GBA.cmake --target=gba --current_build=0 --build_type=release --build_root=${BC_VAR_BUILD_PATH}
.PHONY: configure-gba-debug .PHONY: configure-gba-debug
configure-gba-debug: configure-gba-debug:
${ENV_RUN} ${SETUP_BUILD} --toolchain=deps/gbabuildcore/cmake/modules/GBA.cmake --target=gba --current_build=0 --build_type=debug --build_root=${BUILD_PATH} ${BC_CMD_SETUP_BUILD} --toolchain=deps/gbabuildcore/cmake/modules/GBA.cmake --target=gba --current_build=0 --build_type=debug --build_root=${BC_VAR_BUILD_PATH}

View File

@ -8,6 +8,15 @@
* Install Ninja, Make, and CMake * Install Ninja, Make, and CMake
* Consider also installing ccache for faster subsequent build times * Consider also installing ccache for faster subsequent build times
### Debian
For Debian (and probably other Linux distros, but the package names will
probably differ), install the following additional packages:
* pkg-config
* xorg-dev
* libgtk-3-dev
* python3-mypy
## Build ## Build
Build options: release, debug, asan, gba, gba-debug Build options: release, debug, asan, gba, gba-debug

188
deps/buildcore/base.mk vendored
View File

@ -9,89 +9,99 @@
ifeq (${OS},Windows_NT) ifeq (${OS},Windows_NT)
SHELL := powershell.exe SHELL := powershell.exe
.SHELLFLAGS := -NoProfile -Command .SHELLFLAGS := -NoProfile -Command
OS=windows BC_VAR_OS=windows
HOST_ENV=${OS}
else else
OS=$(shell uname | tr [:upper:] [:lower:]) BC_VAR_OS=$(shell uname | tr [:upper:] [:lower:])
HOST_ENV=${OS}-$(shell uname -m)
endif endif
DEVENV=devenv$(shell pwd | sed 's/\//-/g') ifneq ($(shell which python3 2> /dev/null),)
DEVENV_IMAGE=${PROJECT_NAME}-devenv BC_CMD_HOST_PY3=python3
ifneq ($(shell which docker 2> /dev/null),) else
ifeq ($(shell docker inspect --format="{{.State.Status}}" ${DEVENV} 2>&1),running) ifeq ($(shell python -c 'import sys; print(sys.version_info[0])'),3)
ENV_RUN=docker exec -i -t --user $(shell id -u ${USER}) ${DEVENV} BC_CMD_HOST_PY3=python
else
echo 'Please install Python3 on host'
exit 1
endif endif
endif endif
ifneq ($(shell ${ENV_RUN} which python3 2> /dev/null),) ifdef BC_VAR_USE_DOCKER_DEVENV
PYTHON3=python3 ifneq ($(shell which docker 2> /dev/null),)
else BC_VAR_DEVENV=devenv$(shell pwd | sed 's/\//-/g')
ifeq ($(shell ${ENV_RUN} python -c 'import sys; print(sys.version_info[0])'),3) BC_VAR_DEVENV_IMAGE=${BC_VAR_PROJECT_NAME}-devenv
PYTHON3=python ifeq ($(shell docker inspect --format="{{.State.Status}}" ${BC_VAR_DEVENV} 2>&1),running)
BC_CMD_ENVRUN=docker exec -i -t --user $(shell id -u ${USER}) ${BC_VAR_DEVENV}
endif endif
endif
ifneq ($(shell ${BC_CMD_ENVRUN} which python3 2> /dev/null),)
BC_CMD_PY3=${BC_CMD_ENVRUN} python3
else
ifeq ($(shell ${BC_CMD_ENVRUN} python -c 'import sys; print(sys.version_info[0])'),3)
BC_CMD_PY3=${BC_CMD_ENVRUN} python
else
echo 'Please install Python3 in devenv'
exit 1
endif
endif
else
BC_CMD_PY3=${BC_CMD_HOST_PY3}
endif endif
SCRIPTS=${BUILDCORE_PATH}/scripts BC_VAR_SCRIPTS=${BUILDCORE_PATH}/scripts
SETUP_BUILD=${PYTHON3} ${SCRIPTS}/setup-build.py BC_CMD_SETUP_BUILD=${BC_CMD_PY3} ${BC_VAR_SCRIPTS}/setup-build.py
PYBB=${PYTHON3} ${SCRIPTS}/pybb.py BC_CMD_PYBB=${BC_CMD_PY3} ${BC_VAR_SCRIPTS}/pybb.py
CMAKE_BUILD=${PYBB} cmake-build BC_CMD_HOST_PYBB=${BC_CMD_HOST_PY3} ${BC_VAR_SCRIPTS}/pybb.py
GET_ENV=${PYBB} getenv BC_CMD_CMAKE_BUILD=${BC_CMD_PYBB} cmake-build
CTEST=${PYBB} ctest-all BC_CMD_GETENV=${BC_CMD_PYBB} getenv
RM_RF=${PYBB} rm BC_CMD_CTEST=${BC_CMD_PYBB} ctest-all
HOST=$(shell ${PYBB} hostname) BC_CMD_RM_RF=${BC_CMD_PYBB} rm
BUILDCORE_HOST_SPECIFIC_BUILDPATH=$(shell ${GET_ENV} BUILDCORE_HOST_SPECIFIC_BUILDPATH) BC_CMD_MKDIR_P=${BC_CMD_PYBB} mkdir
ifneq (${BUILDCORE_HOST_SPECIFIC_BUILDPATH},) BC_CMD_CAT=${BC_CMD_PYBB} cat
BUILD_PATH=build/${HOST} BC_CMD_DEBUGGER=${BC_CMD_PYBB} debug
else BC_CMD_HOST_DEBUGGER=${BC_CMD_HOST_PYBB} debug
BUILD_PATH=build BC_VAR_HOSTENV=$(shell ${BC_CMD_ENVRUN} ${BC_CMD_PYBB} hostenv)
endif BC_VAR_BUILD_PATH=build
ifdef USE_VCPKG BC_VAR_CURRENT_BUILD=$(BC_VAR_HOSTENV)-$(shell ${BC_CMD_ENVRUN} ${BC_CMD_CAT} .current_build)
ifndef VCPKG_DIR_BASE
VCPKG_DIR_BASE=.vcpkg
endif
ifndef VCPKG_VERSION
VCPKG_VERSION=2020.06
endif
VCPKG_TOOLCHAIN=--toolchain=${VCPKG_DIR}/scripts/buildsystems/vcpkg.cmake
endif
ifeq ($(OS),darwin)
DEBUGGER=lldb --
else
DEBUGGER=gdb --args
endif
VCPKG_DIR=$(VCPKG_DIR_BASE)/$(VCPKG_VERSION)-$(HOST_ENV) ifdef BC_VAR_USE_VCPKG
CURRENT_BUILD=$(HOST_ENV)-$(shell ${ENV_RUN} ${PYBB} cat .current_build) ifndef BC_VAR_VCPKG_DIR_BASE
BC_VAR_VCPKG_DIR_BASE=.vcpkg
endif
ifndef BC_VAR_VCPKG_VERSION
BC_VAR_VCPKG_VERSION=2023.08.09
endif
endif
.PHONY: build .PHONY: build
build: build:
${ENV_RUN} ${CMAKE_BUILD} ${BUILD_PATH} ${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH}
.PHONY: install .PHONY: install
install: install:
${ENV_RUN} ${CMAKE_BUILD} ${BUILD_PATH} install ${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} install
.PHONY: clean .PHONY: clean
clean: clean:
${ENV_RUN} ${CMAKE_BUILD} ${BUILD_PATH} clean ${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} clean
.PHONY: purge .PHONY: purge
purge: purge:
${ENV_RUN} ${RM_RF} .current_build ${BC_CMD_RM_RF} .current_build
${ENV_RUN} ${RM_RF} ${BUILD_PATH} ${BC_CMD_RM_RF} ${BC_VAR_BUILD_PATH}
${ENV_RUN} ${RM_RF} dist ${BC_CMD_RM_RF} dist
${BC_CMD_RM_RF} compile_commands.json
.PHONY: test .PHONY: test
test: build test: build
${ENV_RUN} mypy ${SCRIPTS} ${BC_CMD_ENVRUN} ${BC_CMD_PY3} -m mypy ${BC_VAR_SCRIPTS}
${ENV_RUN} ${CMAKE_BUILD} ${BUILD_PATH} test ${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} test
.PHONY: test-verbose .PHONY: test-verbose
test-verbose: build test-verbose: build
${ENV_RUN} ${CTEST} ${BUILD_PATH} --output-on-failure ${BC_CMD_CTEST} ${BC_VAR_BUILD_PATH} --output-on-failure
.PHONY: test-rerun-verbose .PHONY: test-rerun-verbose
test-rerun-verbose: build test-rerun-verbose: build
${ENV_RUN} ${CTEST} ${BUILD_PATH} --rerun-failed --output-on-failure ${BC_CMD_CTEST} ${BC_VAR_BUILD_PATH} --rerun-failed --output-on-failure
ifdef BC_VAR_USE_DOCKER_DEVENV
.PHONY: devenv-image .PHONY: devenv-image
devenv-image: devenv-image:
docker build . -t ${DEVENV_IMAGE} docker build . -t ${BC_VAR_DEVENV_IMAGE}
.PHONY: devenv-create .PHONY: devenv-create
devenv-create: devenv-create:
docker run -d \ docker run -d \
@ -103,73 +113,77 @@ devenv-create:
-v $(shell pwd):/usr/src/project \ -v $(shell pwd):/usr/src/project \
-v /dev/shm:/dev/shm \ -v /dev/shm:/dev/shm \
--restart=always \ --restart=always \
--name ${DEVENV} \ --name ${BC_VAR_DEVENV} \
-t ${DEVENV_IMAGE} bash -t ${BC_VAR_DEVENV_IMAGE} bash
.PHONY: devenv-destroy .PHONY: devenv-destroy
devenv-destroy: devenv-destroy:
docker rm -f ${DEVENV} docker rm -f ${BC_VAR_DEVENV}
ifdef ENV_RUN ifdef BC_CMD_ENVRUN
.PHONY: devenv-shell .PHONY: devenv-shell
devenv-shell: devenv-shell:
${ENV_RUN} bash ${BC_CMD_ENVRUN} bash
endif
endif endif
ifdef USE_VCPKG ifdef BC_VAR_USE_VCPKG
BC_VAR_VCPKG_TOOLCHAIN=--toolchain=${BC_VAR_VCPKG_DIR}/scripts/buildsystems/vcpkg.cmake
BC_VAR_VCPKG_DIR=$(BC_VAR_VCPKG_DIR_BASE)/$(BC_VAR_VCPKG_VERSION)-$(BC_VAR_HOSTENV)
.PHONY: vcpkg .PHONY: vcpkg
vcpkg: ${VCPKG_DIR} vcpkg-install vcpkg: ${BC_VAR_VCPKG_DIR} vcpkg-install
${VCPKG_DIR}: ${BC_VAR_VCPKG_DIR}:
${ENV_RUN} ${RM_RF} ${VCPKG_DIR} ${BC_CMD_RM_RF} ${BC_VAR_VCPKG_DIR}
${ENV_RUN} mkdir -p ${VCPKG_DIR_BASE} ${BC_CMD_PYBB} mkdir ${BC_VAR_VCPKG_DIR_BASE}
${ENV_RUN} git clone -b release --depth 1 --branch ${VCPKG_VERSION} https://github.com/microsoft/vcpkg.git ${VCPKG_DIR} ${BC_CMD_ENVRUN} git clone -b release --depth 1 --branch ${BC_VAR_VCPKG_VERSION} https://github.com/microsoft/vcpkg.git ${BC_VAR_VCPKG_DIR}
ifneq (${OS},windows) ifneq (${BC_VAR_OS},windows)
${ENV_RUN} ${VCPKG_DIR}/bootstrap-vcpkg.sh ${BC_CMD_ENVRUN} ${BC_VAR_VCPKG_DIR}/bootstrap-vcpkg.sh
else else
${ENV_RUN} ${VCPKG_DIR}/bootstrap-vcpkg.bat ${BC_CMD_ENVRUN} ${BC_VAR_VCPKG_DIR}/bootstrap-vcpkg.bat
endif endif
.PHONY: vcpkg-install .PHONY: vcpkg-install
vcpkg-install: vcpkg-install:
ifneq (${OS},windows) ifneq (${BC_VAR_OS},windows)
${VCPKG_DIR}/vcpkg install ${VCPKG_PKGS} ${BC_CMD_ENVRUN} ${BC_VAR_VCPKG_DIR}/vcpkg install ${BC_VAR_VCPKG_PKGS}
else else
${VCPKG_DIR}/vcpkg install --triplet x64-windows ${VCPKG_PKGS} ${BC_CMD_ENVRUN} ${BC_VAR_VCPKG_DIR}/vcpkg install --triplet x64-windows ${BC_VAR_VCPKG_PKGS}
endif endif
else ifdef USE_CONAN # USE_VCPKG ################################################ else ifdef USE_CONAN # USE_VCPKG / USE_CONAN ####################################
.PHONY: setup-conan .PHONY: setup-conan
conan-config: conan-config:
${ENV_RUN} conan profile new ${PROJECT_NAME} --detect --force ${BC_CMD_ENVRUN} conan profile new ${BC_VAR_PROJECT_NAME} --detect --force
ifeq ($(OS),linux) ifeq ($(BC_VAR_OS),linux)
${ENV_RUN} conan profile update settings.compiler.libcxx=libstdc++11 ${PROJECT_NAME} ${BC_CMD_ENVRUN} conan profile update settings.compiler.libcxx=libstdc++11 ${BC_VAR_PROJECT_NAME}
else else
${ENV_RUN} conan profile update settings.compiler.cppstd=20 ${PROJECT_NAME} ${BC_CMD_ENVRUN} conan profile update settings.compiler.cppstd=20 ${BC_VAR_PROJECT_NAME}
ifeq ($(OS),windows) ifeq ($(BC_VAR_OS),windows)
${ENV_RUN} conan profile update settings.compiler.runtime=static ${PROJECT_NAME} ${BC_CMD_ENVRUN} conan profile update settings.compiler.runtime=static ${BC_VAR_PROJECT_NAME}
endif endif
endif endif
.PHONY: conan .PHONY: conan
conan: conan:
${ENV_RUN} ${PYBB} conan-install ${PROJECT_NAME} ${BC_CMD_PYBB} conan-install ${BC_VAR_PROJECT_NAME}
endif # USE_VCPKG ############################################### endif # USE_CONAN ###############################################
ifeq (${OS},darwin) ifeq (${BC_VAR_OS},darwin)
.PHONY: configure-xcode .PHONY: configure-xcode
configure-xcode: configure-xcode:
${ENV_RUN} ${SETUP_BUILD} ${VCPKG_TOOLCHAIN} --build_tool=xcode --current_build=0 --build_root=${BUILD_PATH} ${BC_CMD_SETUP_BUILD} ${BC_VAR_VCPKG_TOOLCHAIN} --build_tool=xcode --current_build=0 --build_root=${BC_VAR_BUILD_PATH}
endif endif
.PHONY: configure-release .PHONY: configure-release
configure-release: configure-release:
${ENV_RUN} ${SETUP_BUILD} ${VCPKG_TOOLCHAIN} --build_type=release --build_root=${BUILD_PATH} ${BC_CMD_SETUP_BUILD} ${BC_VAR_VCPKG_TOOLCHAIN} --build_type=release --build_root=${BC_VAR_BUILD_PATH}
.PHONY: configure-debug .PHONY: configure-debug
configure-debug: configure-debug:
${ENV_RUN} ${SETUP_BUILD} ${VCPKG_TOOLCHAIN} --build_type=debug --build_root=${BUILD_PATH} ${BC_CMD_SETUP_BUILD} ${BC_VAR_VCPKG_TOOLCHAIN} --build_type=debug --build_root=${BC_VAR_BUILD_PATH}
.PHONY: configure-asan .PHONY: configure-asan
configure-asan: configure-asan:
${ENV_RUN} ${SETUP_BUILD} ${VCPKG_TOOLCHAIN} --build_type=asan --build_root=${BUILD_PATH} ${BC_CMD_SETUP_BUILD} ${BC_VAR_VCPKG_TOOLCHAIN} --build_type=asan --build_root=${BC_VAR_BUILD_PATH}

View File

@ -18,18 +18,20 @@ import subprocess
import sys import sys
from typing import List, Optional from typing import List, Optional
import util
def mkdir(path: str):
if not os.path.exists(path):
os.mkdir(path)
# this exists because Windows is utterly incapable of providing a proper rm -rf def mkdir(path: str) -> int:
def rm(path: str): try:
if (os.path.exists(path) or os.path.islink(path)) and not os.path.isdir(path): util.mkdir_p(path)
os.remove(path) except Exception:
elif os.path.isdir(path): return 1
shutil.rmtree(path) return 0
def rm_multi(paths: List[str]):
for path in paths:
util.rm(path)
def ctest_all() -> int: def ctest_all() -> int:
@ -70,16 +72,13 @@ def conan() -> int:
err = 0 err = 0
try: try:
mkdir(conan_dir) mkdir(conan_dir)
except: except Exception:
return 1 return 1
if err != 0: if err != 0:
return err return err
args = ['conan', 'install', '../', '--build=missing', '-pr', project_name] args = ['conan', 'install', '../', '--build=missing', '-pr', project_name]
os.chdir(conan_dir) os.chdir(conan_dir)
err = subprocess.run(args).returncode return subprocess.run(args).returncode
if err != 0:
return err
return 0
def cat(paths: List[str]) -> int: def cat(paths: List[str]) -> int:
@ -87,48 +86,70 @@ def cat(paths: List[str]) -> int:
try: try:
with open(path) as f: with open(path) as f:
data = f.read() data = f.read()
sys.stdout.write(data) print(data)
except FileNotFoundError: except FileNotFoundError:
sys.stderr.write('cat: {}: no such file or directory\n'.format(path)) sys.stderr.write(f'cat: {path}: no such file or directory\n')
return 1 return 1
sys.stdout.write('\n')
return 0 return 0
def debug(paths: List[str]) -> int:
if shutil.which('gdb') is not None:
args = ['gdb', '--args']
elif shutil.which('lldb') is not None:
args = ['lldb', '--']
else:
sys.stderr.write('debug: could not find a supported debugger\n')
return 1
args.extend(paths)
return subprocess.run(args).returncode
def get_env(var_name: str) -> int: def get_env(var_name: str) -> int:
if var_name not in os.environ: if var_name not in os.environ:
return 1 return 1
sys.stdout.write(os.environ[var_name]) print(os.environ[var_name])
return 0 return 0
def hostname() -> int: def hostname() -> int:
sys.stdout.write(platform.node()) print(platform.node())
return 0 return 0
def host_env() -> int:
os_name = platform.system().lower()
arch = util.get_arch()
print(f'{os_name}-{arch}')
return 0
def clarg(idx: int) -> Optional[str]:
return sys.argv[idx] if len(sys.argv) > idx else None
def main() -> int: def main() -> int:
err = 0 err = 0
if sys.argv[1] == 'mkdir': if sys.argv[1] == 'mkdir':
try: err = mkdir(sys.argv[2])
mkdir(sys.argv[2])
except:
err = 1
elif sys.argv[1] == 'rm': elif sys.argv[1] == 'rm':
for i in range(2, len(sys.argv)): rm_multi(sys.argv[2:])
rm(sys.argv[i])
elif sys.argv[1] == 'conan-install': elif sys.argv[1] == 'conan-install':
err = conan() err = conan()
elif sys.argv[1] == 'ctest-all': elif sys.argv[1] == 'ctest-all':
err = ctest_all() err = ctest_all()
elif sys.argv[1] == 'cmake-build': elif sys.argv[1] == 'cmake-build':
err = cmake_build(sys.argv[2], sys.argv[3] if len(sys.argv) > 3 else None) err = cmake_build(sys.argv[2], clarg(3))
elif sys.argv[1] == 'cat': elif sys.argv[1] == 'cat':
err = cat(sys.argv[2:]) err = cat(sys.argv[2:])
elif sys.argv[1] == 'debug':
err = debug(sys.argv[2:])
elif sys.argv[1] == 'getenv': elif sys.argv[1] == 'getenv':
err = get_env(sys.argv[2]) err = get_env(sys.argv[2])
elif sys.argv[1] == 'hostname': elif sys.argv[1] == 'hostname':
err = hostname() err = hostname()
elif sys.argv[1] == 'hostenv':
err = host_env()
else: else:
sys.stderr.write('Command not found\n') sys.stderr.write('Command not found\n')
err = 1 err = 1

View File

@ -15,18 +15,35 @@ import shutil
import subprocess import subprocess
import sys import sys
from pybb import mkdir, rm import util
def main() -> int: def main() -> int:
parser = argparse.ArgumentParser() parser = argparse.ArgumentParser()
parser.add_argument('--target', help='Platform target', parser.add_argument(
default='{:s}-{:s}'.format(sys.platform, platform.machine())) '--target',
parser.add_argument('--build_type', help='Build type (asan,debug,release)', default='release') help='Platform target',
parser.add_argument('--build_tool', help='Build tool (default,xcode)', default='') default=f'{util.get_os()}-{util.get_arch()}')
parser.add_argument('--build_root', help='Path to the root of build directories (must be in project dir)', default='build') parser.add_argument(
parser.add_argument('--toolchain', help='Path to CMake toolchain file', default='') '--build_type',
parser.add_argument('--current_build', help='Indicates whether or not to make this the active build', default=1) help='Build type (asan,debug,release)',
default='release')
parser.add_argument(
'--build_tool',
help='Build tool (default,xcode)',
default='')
parser.add_argument(
'--build_root',
help='Path to the root build directory (must be in project dir)',
default='build')
parser.add_argument(
'--toolchain',
help='Path to CMake toolchain file',
default='')
parser.add_argument(
'--current_build',
help='Indicates whether or not to make this the active build',
default=1)
args = parser.parse_args() args = parser.parse_args()
if args.build_type == 'asan': if args.build_type == 'asan':
@ -64,10 +81,10 @@ def main() -> int:
return 1 return 1
project_dir = os.getcwd() project_dir = os.getcwd()
build_dir = '{:s}/{:s}/{:s}'.format(project_dir, args.build_root, build_config) build_dir = f'{project_dir}/{args.build_root}/{build_config}'
rm(build_dir) util.rm(build_dir)
cmake_cmd = [ cmake_cmd = [
'cmake', '-S', project_dir, '-B', build_dir, build_tool, 'cmake', '-S', project_dir, '-B', build_dir,
'-DCMAKE_EXPORT_COMPILE_COMMANDS=ON', '-DCMAKE_EXPORT_COMPILE_COMMANDS=ON',
'-DCMAKE_TOOLCHAIN_FILE={:s}'.format(args.toolchain), '-DCMAKE_TOOLCHAIN_FILE={:s}'.format(args.toolchain),
'-DCMAKE_BUILD_TYPE={:s}'.format(build_type_arg), '-DCMAKE_BUILD_TYPE={:s}'.format(build_type_arg),
@ -75,22 +92,27 @@ def main() -> int:
'-DBUILDCORE_BUILD_CONFIG={:s}'.format(build_config), '-DBUILDCORE_BUILD_CONFIG={:s}'.format(build_config),
'-DBUILDCORE_TARGET={:s}'.format(args.target), '-DBUILDCORE_TARGET={:s}'.format(args.target),
] ]
if build_tool != '':
cmake_cmd.append(build_tool)
if qt_path != '': if qt_path != '':
cmake_cmd.append(qt_path) cmake_cmd.append(qt_path)
if platform.system() == 'Windows': if platform.system() == 'Windows':
cmake_cmd.append('-A x64') cmake_cmd.append('-A x64')
subprocess.run(cmake_cmd) cmake_err = subprocess.run(cmake_cmd).returncode
if cmake_err != 0:
return cmake_err
mkdir('dist') util.mkdir_p('dist')
if int(args.current_build) != 0: if int(args.current_build) != 0:
cb = open('.current_build', 'w') cb = open('.current_build', 'w')
cb.write(args.build_type) cb.write(args.build_type)
cb.close() cb.close()
rm('compile_commands.json') util.rm('compile_commands.json')
if platform.system() != 'Windows': if platform.system() != 'Windows':
os.symlink('{:s}/compile_commands.json'.format(build_dir), 'compile_commands.json') os.symlink(f'{build_dir}/compile_commands.json',
'compile_commands.json')
return 0 return 0

38
deps/buildcore/scripts/util.py vendored Normal file
View File

@ -0,0 +1,38 @@
#
# Copyright 2016 - 2021 gary@drinkingtea.net
#
# This Source Code Form is subject to the terms of the Mozilla Public
# License, v. 2.0. If a copy of the MPL was not distributed with this
# file, You can obtain one at http://mozilla.org/MPL/2.0/.
#
import os
import platform
import shutil
def mkdir_p(path: str):
if not os.path.exists(path):
os.mkdir(path)
# this exists because Windows is utterly incapable of providing a proper rm -rf
def rm(path: str):
file_exists = os.path.exists(path)
is_link = os.path.islink(path)
is_dir = os.path.isdir(path)
if (file_exists or is_link) and not is_dir:
os.remove(path)
elif os.path.isdir(path):
shutil.rmtree(path)
def get_os() -> str:
return platform.system().lower()
def get_arch() -> str:
arch = platform.machine()
if arch.lower() == 'amd64':
arch = 'x86_64'
return arch

View File

@ -24,8 +24,8 @@ add_definitions(-DARM7)
include(FindPackageHandleStandardArgs) include(FindPackageHandleStandardArgs)
macro(OBJCOPY_FILE EXE_NAME) macro(OBJCOPY_FILE EXE_NAME)
set(FO ${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.bin) set(FO ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${EXE_NAME}.bin)
set(FI ${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}) set(FI ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${EXE_NAME})
message(STATUS ${FO}) message(STATUS ${FO})
# run objcopy # run objcopy

View File

@ -88,7 +88,7 @@ if (CMAKE_VERSION VERSION_LESS "3.16" AND APPLE)
LANGUAGE C) LANGUAGE C)
endif() endif()
add_library(glfw OBJECT ${glfw_SOURCES} ${glfw_HEADERS}) add_library(glfw ${glfw_SOURCES} ${glfw_HEADERS})
set_target_properties(glfw PROPERTIES set_target_properties(glfw PROPERTIES
OUTPUT_NAME ${GLFW_LIB_NAME} OUTPUT_NAME ${GLFW_LIB_NAME}
VERSION ${GLFW_VERSION_MAJOR}.${GLFW_VERSION_MINOR} VERSION ${GLFW_VERSION_MAJOR}.${GLFW_VERSION_MINOR}

6
deps/glutils/.liccor.yml vendored Normal file
View File

@ -0,0 +1,6 @@
---
source:
- include
- src
copyright_notice: |-
Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.

10
deps/glutils/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,10 @@
project(GlUtils CXX)
add_subdirectory(src)
install(
DIRECTORY
include/glutils
DESTINATION
include
)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. * Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/ */
#pragma once #pragma once
@ -9,15 +9,17 @@
#include <glad/glad.h> #include <glad/glad.h>
#include <ox/std/bounds.hpp> #include <ox/std/bounds.hpp>
#include <ox/std/cstringview.hpp>
#include <ox/std/error.hpp> #include <ox/std/error.hpp>
#include <ox/std/size.hpp>
#include <ox/std/string.hpp> #include <ox/std/string.hpp>
#include <ox/std/vector.hpp> #include <ox/std/vector.hpp>
namespace glutils { namespace glutils {
constexpr ox::StringView GlslVersion = "#version 330"; struct Empty {
virtual ~Empty() noexcept = default;
struct Empty {}; };
struct TextureBase { struct TextureBase {
@ -41,6 +43,8 @@ struct TextureBase {
return *this; return *this;
} }
virtual ~TextureBase() noexcept = default;
}; };
@ -60,7 +64,7 @@ struct GLObject: public Base {
o.id = 0; o.id = 0;
} }
~GLObject() noexcept { ~GLObject() noexcept override {
del(id); del(id);
} }
@ -107,7 +111,7 @@ extern template struct GLObject<deleteProgram>;
extern template struct GLObject<deleteShader>; extern template struct GLObject<deleteShader>;
using GLBuffer = GLObject<deleteBuffer>; using GLBuffer = GLObject<deleteBuffer>;
using GLFrameBuffer = GLObject<deleteBuffer>; using GLFrameBuffer = GLObject<deleteFrameBuffer>;
using GLRenderBuffer = GLObject<deleteRenderBuffer>; using GLRenderBuffer = GLObject<deleteRenderBuffer>;
using GLShader = GLObject<deleteShader>; using GLShader = GLObject<deleteShader>;
using GLProgram = GLObject<deleteProgram>; using GLProgram = GLObject<deleteProgram>;
@ -146,10 +150,39 @@ class FrameBufferBind {
void bind(const FrameBuffer &fb) noexcept; void bind(const FrameBuffer &fb) noexcept;
struct ShaderVarSet {
GLsizei len{};
ox::String name;
};
ox::Result<GLProgram> buildShaderProgram(const GLchar *vert, const GLchar *frag, const GLchar *geo = nullptr) noexcept; struct ProgramSource {
ox::Vector<glutils::ShaderVarSet> const shaderParams;
GLsizei const rowLen = [this] {
GLsizei len{};
for (auto const&v : shaderParams) {
len += v.len;
}
return len;
}();
GLsizei const vboLen = rowLen * 4;
ox::String const vertShader{};
ox::String const fragShader{};
ox::String const geomShader{};
};
ox::Result<GLProgram> buildShaderProgram(const ox::String &vert, const ox::String &frag, const ox::String &geo = "") noexcept; ox::Result<GLProgram> buildShaderProgram(ProgramSource const&src) noexcept;
ox::Result<GLProgram> buildShaderProgram(
ox::CStringView const&vert,
ox::CStringView const&frag,
ox::CStringView const&geo = "") noexcept;
void setupShaderParams(
GLProgram const&shader,
ox::Vector<ShaderVarSet> const&vars,
GLsizei vertexRowLen) noexcept;
void setupShaderParams(GLProgram const&shader, ox::Vector<ShaderVarSet> const&vars) noexcept;
glutils::GLVertexArray generateVertexArrayObject() noexcept; glutils::GLVertexArray generateVertexArrayObject() noexcept;
@ -158,10 +191,14 @@ glutils::GLBuffer generateBuffer() noexcept;
[[nodiscard]] [[nodiscard]]
FrameBuffer generateFrameBuffer(int width, int height) noexcept; FrameBuffer generateFrameBuffer(int width, int height) noexcept;
void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept;
/** /**
* Resizes a FrameBuffer, and creates if it does not already exist. * Resizes a FrameBuffer, and creates if it does not already exist.
*/ */
void resizeInitFrameBuffer(FrameBuffer *fb, int width, int height) noexcept; void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept;
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const&sz) noexcept;
struct BufferSet { struct BufferSet {
glutils::GLVertexArray vao; glutils::GLVertexArray vao;
@ -172,9 +209,9 @@ struct BufferSet {
ox::Vector<GLuint> elements; ox::Vector<GLuint> elements;
}; };
void sendVbo(const BufferSet &bs) noexcept; void sendVbo(BufferSet const&bs) noexcept;
void sendEbo(const BufferSet &bs) noexcept; void sendEbo(BufferSet const&bs) noexcept;
void clearScreen() noexcept; void clearScreen() noexcept;

View File

@ -3,19 +3,17 @@ add_library(
glutils.cpp glutils.cpp
) )
target_include_directories(
GlUtils PUBLIC
../include
)
target_link_libraries( target_link_libraries(
GlUtils PUBLIC GlUtils PUBLIC
OxStd OxStd
glad glad
) )
install(
FILES
glutils.hpp
DESTINATION
include/glutils
)
install( install(
TARGETS TARGETS
GlUtils GlUtils

View File

@ -1,12 +1,12 @@
/* /*
* Copyright 2016 - 2023 Gary Talent (gary@drinkingtea.net). All rights reserved. * Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/ */
#include <ox/std/assert.hpp> #include <ox/std/assert.hpp>
#include <ox/std/bstring.hpp> #include <ox/std/istring.hpp>
#include <ox/std/trace.hpp> #include <ox/std/trace.hpp>
#include "glutils.hpp" #include "glutils/glutils.hpp"
namespace glutils { namespace glutils {
@ -88,25 +88,55 @@ static ox::Result<GLShader> buildShader(
return shader; return shader;
} }
ox::Result<GLProgram> buildShaderProgram(const GLchar *vert, const GLchar *frag, const GLchar *geo) noexcept { ox::Result<GLProgram> buildShaderProgram(ProgramSource const&src) noexcept {
GLProgram prgm(glCreateProgram()); oxRequireM(program, buildShaderProgram(
oxRequire(vs, buildShader(GL_VERTEX_SHADER, vert, "vshad")); src.vertShader,
glAttachShader(prgm, vs); src.fragShader,
if (geo && ox_strlen(geo) != 0) { src.geomShader));
oxRequire(gs, buildShader(GL_GEOMETRY_SHADER, geo, "gshad")); setupShaderParams(program, src.shaderParams, src.rowLen);
glAttachShader(prgm, gs); return std::move(program);
}
void setupShaderParams(
GLProgram const&shader,
ox::Vector<ShaderVarSet> const&vars,
GLsizei vertexRowLen) noexcept {
// setup vars
for (auto lenWritten = 0LU; auto const&v : vars) {
auto const attr = static_cast<GLuint>(glGetAttribLocation(shader, v.name.c_str()));
glEnableVertexAttribArray(attr);
glVertexAttribPointer(
attr, v.len, GL_FLOAT, GL_FALSE,
vertexRowLen * static_cast<GLsizei>(sizeof(float)),
std::bit_cast<void*>(uintptr_t{lenWritten * sizeof(float)}));
lenWritten += static_cast<size_t>(v.len);
} }
oxRequire(fs, buildShader(GL_FRAGMENT_SHADER, frag, "fshad")); }
glAttachShader(prgm, fs);
glLinkProgram(prgm); void setupShaderParams(GLProgram const&shader, ox::Vector<ShaderVarSet> const&vars) noexcept {
return prgm; // get row len
GLsizei vertexRowLen{};
for (auto const&v : vars) {
vertexRowLen += v.len;
}
setupShaderParams(shader, vars, vertexRowLen);
} }
ox::Result<GLProgram> buildShaderProgram( ox::Result<GLProgram> buildShaderProgram(
const ox::String &vert, ox::CStringView const&vert,
const ox::String &frag, ox::CStringView const&frag,
const ox::String &geo) noexcept { ox::CStringView const&geo) noexcept {
return buildShaderProgram(vert.c_str(), frag.c_str(), geo.c_str()); GLProgram prgm(glCreateProgram());
oxRequire(vs, buildShader(GL_VERTEX_SHADER, vert.c_str(), "vshad"));
glAttachShader(prgm, vs);
if (geo.c_str() && geo.bytes() != 0) {
oxRequire(gs, buildShader(GL_GEOMETRY_SHADER, geo.c_str(), "gshad"));
glAttachShader(prgm, gs);
}
oxRequire(fs, buildShader(GL_FRAGMENT_SHADER, frag.c_str(), "fshad"));
glAttachShader(prgm, fs);
glLinkProgram(prgm);
return prgm;
} }
GLVertexArray generateVertexArrayObject() noexcept { GLVertexArray generateVertexArrayObject() noexcept {
@ -133,8 +163,9 @@ FrameBuffer generateFrameBuffer(int width, int height) noexcept {
glGenTextures(1, &fb.color.id); glGenTextures(1, &fb.color.id);
glBindTexture(GL_TEXTURE_2D, fb.color); glBindTexture(GL_TEXTURE_2D, fb.color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR); glGenerateMipmap(GL_TEXTURE_2D);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR); glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR_MIPMAP_LINEAR);
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.color, 0); glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D, fb.color, 0);
// depth texture // depth texture
glGenRenderbuffers(1, &fb.depth.id); glGenRenderbuffers(1, &fb.depth.id);
@ -150,21 +181,19 @@ FrameBuffer generateFrameBuffer(int width, int height) noexcept {
return fb; return fb;
} }
void resizeInitFrameBuffer(FrameBuffer *fb, int width, int height) noexcept { void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
if (!*fb) {
*fb = generateFrameBuffer(width, height);
return;
}
width = ox::max(1, width); width = ox::max(1, width);
height = ox::max(1, height); height = ox::max(1, height);
fb->width = width; fb.width = width;
fb->height = height; fb.height = height;
glBindFramebuffer(GL_FRAMEBUFFER, *fb); glBindFramebuffer(GL_FRAMEBUFFER, fb);
// color texture // color texture
glBindTexture(GL_TEXTURE_2D, fb->color); glBindTexture(GL_TEXTURE_2D, fb.color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr); glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
// depth texture // depth texture
glBindRenderbuffer(GL_RENDERBUFFER, fb->depth); glBindRenderbuffer(GL_RENDERBUFFER, fb.depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height); glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
// restore primary FB // restore primary FB
glBindFramebuffer(GL_FRAMEBUFFER, 0); glBindFramebuffer(GL_FRAMEBUFFER, 0);
@ -172,13 +201,25 @@ void resizeInitFrameBuffer(FrameBuffer *fb, int width, int height) noexcept {
glBindRenderbuffer(GL_RENDERBUFFER, 0); glBindRenderbuffer(GL_RENDERBUFFER, 0);
} }
void sendVbo(const BufferSet &bs) noexcept { void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
if (!fb) {
fb = generateFrameBuffer(width, height);
return;
}
resizeFrameBuffer(fb, width, height);
}
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const&sz) noexcept {
resizeInitFrameBuffer(fb, sz.width, sz.height);
}
void sendVbo(BufferSet const&bs) noexcept {
const auto bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.vertices)::value_type) * bs.vertices.size()); const auto bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.vertices)::value_type) * bs.vertices.size());
glBindBuffer(GL_ARRAY_BUFFER, bs.vbo); glBindBuffer(GL_ARRAY_BUFFER, bs.vbo);
glBufferData(GL_ARRAY_BUFFER, bufferSize, bs.vertices.data(), GL_DYNAMIC_DRAW); glBufferData(GL_ARRAY_BUFFER, bufferSize, bs.vertices.data(), GL_DYNAMIC_DRAW);
} }
void sendEbo(const BufferSet &bs) noexcept { void sendEbo(BufferSet const&bs) noexcept {
const auto bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.elements)::value_type) * bs.elements.size()); const auto bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.elements)::value_type) * bs.elements.size());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bs.ebo); glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bs.ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferSize, bs.elements.data(), GL_STATIC_DRAW); glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferSize, bs.elements.data(), GL_STATIC_DRAW);

View File

@ -15,3 +15,8 @@ add_library(
backends/imgui_impl_glfw.cpp backends/imgui_impl_glfw.cpp
backends/imgui_impl_opengl3.cpp backends/imgui_impl_opengl3.cpp
) )
target_include_directories(
imgui SYSTEM PUBLIC
.
)

View File

@ -12,3 +12,11 @@ target_include_directories(
lodepng PUBLIC SYSTEM lodepng PUBLIC SYSTEM
include include
) )
install(
TARGETS
lodepng
DESTINATION
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)

View File

@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.2) cmake_minimum_required(VERSION 3.10)
project(nativefiledialog-extended) project(nativefiledialog-extended)
if(NOT MSVC) if(NOT MSVC)
@ -11,7 +11,7 @@ if(WIN32)
elseif(APPLE) elseif(APPLE)
set(nfd_PLATFORM PLATFORM_MACOS) set(nfd_PLATFORM PLATFORM_MACOS)
elseif(UNIX AND NOT APPLE) elseif(UNIX AND NOT APPLE)
set(nfd_PLATFORM PLATFORM_LINUX) set(nfd_PLATFORM PLATFORM_UNIX)
endif() endif()
message("nfd Platform: ${nfd_PLATFORM}") message("nfd Platform: ${nfd_PLATFORM}")

View File

@ -10,13 +10,12 @@ if(nfd_PLATFORM STREQUAL PLATFORM_WIN32)
list(APPEND SOURCE_FILES nfd_win.cpp) list(APPEND SOURCE_FILES nfd_win.cpp)
endif() endif()
if(nfd_PLATFORM STREQUAL PLATFORM_LINUX) if(nfd_PLATFORM STREQUAL PLATFORM_UNIX)
find_package(PkgConfig REQUIRED) find_package(PkgConfig REQUIRED)
# for Linux, we support GTK3 and xdg-desktop-portal # for Linux, we support GTK3 and xdg-desktop-portal
option(NFD_PORTAL "Use xdg-desktop-portal instead of GTK" OFF) option(NFD_PORTAL "Use xdg-desktop-portal instead of GTK" OFF)
if(NOT NFD_PORTAL) if(NOT NFD_PORTAL)
pkg_check_modules(GTK3 REQUIRED gtk+-3.0) pkg_check_modules(GTK3 REQUIRED IMPORTED_TARGET gtk+-3.0)
message("Using GTK version: ${GTK3_VERSION}")
list(APPEND SOURCE_FILES nfd_gtk.cpp) list(APPEND SOURCE_FILES nfd_gtk.cpp)
else() else()
pkg_check_modules(DBUS REQUIRED dbus-1) pkg_check_modules(DBUS REQUIRED dbus-1)
@ -31,19 +30,17 @@ if(nfd_PLATFORM STREQUAL PLATFORM_MACOS)
endif() endif()
# Define the library # Define the library
add_library(${TARGET_NAME} OBJECT add_library(${TARGET_NAME}
${SOURCE_FILES}) ${SOURCE_FILES})
# Allow includes from include/ # Allow includes from include/
target_include_directories(${TARGET_NAME} target_include_directories(${TARGET_NAME}
PUBLIC include/) PUBLIC include/)
if(nfd_PLATFORM STREQUAL PLATFORM_LINUX) if(nfd_PLATFORM STREQUAL PLATFORM_UNIX)
if(NOT NFD_PORTAL) if(NOT NFD_PORTAL)
target_include_directories(${TARGET_NAME}
PRIVATE ${GTK3_INCLUDE_DIRS})
target_link_libraries(${TARGET_NAME} target_link_libraries(${TARGET_NAME}
PRIVATE ${GTK3_LIBRARIES}) PRIVATE PkgConfig::GTK3)
else() else()
target_include_directories(${TARGET_NAME} target_include_directories(${TARGET_NAME}
PRIVATE ${DBUS_INCLUDE_DIRS}) PRIVATE ${DBUS_INCLUDE_DIRS})

2
deps/ox/.liccor.yml vendored
View File

@ -2,7 +2,7 @@
source: source:
- src - src
copyright_notice: |- copyright_notice: |-
Copyright 2015 - 2022 gary@drinkingtea.net Copyright 2015 - 2024 gary@drinkingtea.net
This Source Code Form is subject to the terms of the Mozilla Public This Source Code Form is subject to the terms of the Mozilla Public
License, v. 2.0. If a copy of the MPL was not distributed with this License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,7 +1,7 @@
cmake_minimum_required(VERSION 3.19) cmake_minimum_required(VERSION 3.19)
set(CMAKE_POLICY_DEFAULT_CMP0110 NEW) # requires CMake 3.19 set(CMAKE_POLICY_DEFAULT_CMP0110 NEW) # requires CMake 3.19
project(Ox) project(Ox CXX)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules) list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
include(address_sanitizer) include(address_sanitizer)
@ -82,4 +82,5 @@ if(OX_USE_STDLIB)
set(JSONCPP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/jsoncpp/include") set(JSONCPP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/jsoncpp/include")
add_subdirectory(deps/jsoncpp) add_subdirectory(deps/jsoncpp)
endif() endif()
add_subdirectory(deps/cityhash)
add_subdirectory(src) add_subdirectory(src)

30
deps/ox/deps/cityhash/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,30 @@
cmake_minimum_required(VERSION 3.19)
set(CMAKE_POLICY_DEFAULT_CMP0110 NEW) # requires CMake 3.19
project(CityHash CXX)
set(CMAKE_CXX_STANDARD 20)
set(CMAKE_CXX_STANDARD_REQUIRED ON)
set(CMAKE_CXX_EXTENSIONS OFF)
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
set(NOSTALGIA_BUILD_PLAYER OFF)
set(NOSTALGIA_BUILD_STUDIO_APP OFF)
set(CMAKE_ARCHIVE_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_LIBRARY_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/lib)
set(CMAKE_RUNTIME_OUTPUT_DIRECTORY ${CMAKE_BINARY_DIR}/bin)
if(APPLE)
set(CMAKE_MACOSX_RPATH OFF)
else()
if(UNIX)
set(BUILD_SHARED_LIBS ON)
endif()
set(CMAKE_INSTALL_RPATH "$ORIGIN/../lib")
set(CMAKE_BUILD_WITH_INSTALL_RPATH TRUE)
endif()
add_library(CityHash INTERFACE)
target_include_directories(CityHash INTERFACE include)

View File

@ -0,0 +1,674 @@
// Copyright (c) 2011 Google, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
//
// CityHash, by Geoff Pike and Jyrki Alakuijala
//
// http://code.google.com/p/cityhash/
//
// This file provides a few functions for hashing strings. All of them are
// high-quality functions in the sense that they pass standard tests such
// as Austin Appleby's SMHasher. They are also fast.
//
// For 64-bit x86 code, on short strings, we don't know of anything faster than
// CityHash64 that is of comparable quality. We believe our nearest competitor
// is Murmur3. For 64-bit x86 code, CityHash64 is an excellent choice for hash
// tables and most other hashing (excluding cryptography).
//
// For 64-bit x86 code, on long strings, the picture is more complicated.
// On many recent Intel CPUs, such as Nehalem, Westmere, Sandy Bridge, etc.,
// CityHashCrc128 appears to be faster than all competitors of comparable
// quality. CityHash128 is also good but not quite as fast. We believe our
// nearest competitor is Bob Jenkins' Spooky. We don't have great data for
// other 64-bit CPUs, but for long strings we know that Spooky is slightly
// faster than CityHash on some relatively recent AMD x86-64 CPUs, for example.
// Note that CityHashCrc128 is declared in citycrc.h.
//
// For 32-bit x86 code, we don't know of anything faster than CityHash32 that
// is of comparable quality. We believe our nearest competitor is Murmur3A.
// (On 64-bit CPUs, it is typically faster to use the other CityHash variants.)
//
// Functions in the CityHash family are not suitable for cryptography.
//
// Please see CityHash's README file for more details on our performance
// measurements and so on.
//
// WARNING: This code has been only lightly tested on big-endian platforms!
// It is known to work well on little-endian platforms that have a small penalty
// for unaligned reads, such as current Intel and AMD moderate-to-high-end CPUs.
// It should work on all 32-bit and 64-bit platforms that allow unaligned reads;
// bug reports are welcome.
//
// By the way, for some hash functions, given strings a and b, the hash
// of a+b is easily derived from the hashes of a and b. This property
// doesn't hold for any hash functions in this file.
#ifndef CITY_HASH_H_
#define CITY_HASH_H_
#if __has_include(<cstdint>)
#include <cstdint>
#else
typedef signed char int8_t;
typedef unsigned char uint8_t;
typedef short int16_t;
typedef unsigned short uint16_t;
typedef int int32_t;
typedef unsigned int uint32_t;
typedef unsigned uint_t;
#if defined(__arm__) || defined(__ppc__)
typedef long long int64_t;
typedef unsigned long long uint64_t;
typedef __INTMAX_TYPE__ intmax_t;
typedef __UINTMAX_TYPE__ uintmax_t;
#else
typedef long int64_t;
typedef unsigned long uint64_t;
typedef int64_t intmax_t;
typedef uint64_t uintmax_t;
#endif
#if defined(_LP64) || defined(__ppc64__) || defined(__aarch64__)
typedef long intptr_t;
typedef unsigned long uintptr_t;
#elif defined(_WIN64)
typedef int64_t intptr_t;
typedef uint64_t uintptr_t;
#elif defined(_LP32) || defined(__ppc__) || defined(_WIN32) || defined(__arm__)
typedef int32_t intptr_t;
typedef uint32_t uintptr_t;
#else
#error intptr_t, and uintptr_t undefined
#endif
using size_t = decltype(alignof(int));
#endif
namespace cityhash::detail {
template<typename T>
struct remove_reference {
using type = T;
};
template<typename T>
struct remove_reference<T&> {
using type = T;
};
template<typename T>
struct remove_reference<T&&> {
using type = T;
};
template<typename T>
using remove_reference_t = typename remove_reference<T>::type;
template<typename T>
constexpr remove_reference_t<T> &&move(T &&t) noexcept {
return static_cast<remove_reference_t<T>&&>(t);
}
template<typename T>
using remove_reference_t = typename remove_reference<T>::type;
template<typename T1, typename T2>
struct pair {
T1 first{};
T2 second{};
constexpr pair() noexcept = default;
constexpr pair(T1 a, T2 b) noexcept: first(detail::move(a)), second(detail::move(b)) {}
};
template<typename T>
constexpr void swap(T &a, T &b) noexcept {
auto temp = detail::move(a);
a = detail::move(b);
b = detail::move(temp);
}
}
namespace cityhash {
using uint128 = cityhash::detail::pair<uint64_t, uint64_t>;
namespace detail {
template<typename T>
[[nodiscard]]
constexpr T byteSwap(T i) noexcept {
if constexpr(sizeof(T) == 1) {
return i;
} else if constexpr(sizeof(T) == 2) {
return static_cast<T>(i << 8) | static_cast<T>(i >> 8);
} else if constexpr(sizeof(T) == 4) {
return ((i >> 24) & 0x000000ff) |
((i >> 8) & 0x0000ff00) |
((i << 8) & 0x00ff0000) |
((i << 24) & 0xff000000);
} else if constexpr(sizeof(T) == 8) {
return ((i >> 56) & 0x00000000000000ff) |
((i >> 40) & 0x000000000000ff00) |
((i >> 24) & 0x0000000000ff0000) |
((i >> 8) & 0x00000000ff000000) |
((i << 8) & 0x000000ff00000000) |
((i << 24) & 0x0000ff0000000000) |
((i << 40) & 0x00ff000000000000) |
((i << 56) & 0xff00000000000000);
}
}
[[nodiscard]]
constexpr uint64_t Uint128Low64(const uint128& x) noexcept { return x.first; }
[[nodiscard]]
constexpr uint64_t Uint128High64(const uint128& x) noexcept { return x.second; }
// Hash 128 input bits down to 64 bits of output.
// This is intended to be a reasonably good hash function.
[[nodiscard]]
constexpr uint64_t Hash128to64(const uint128& x) noexcept {
// Murmur-inspired hashing.
const uint64_t kMul = 0x9ddfea08eb382d69ULL;
uint64_t a = (detail::Uint128Low64(x) ^ detail::Uint128High64(x)) * kMul;
a ^= (a >> 47);
uint64_t b = (detail::Uint128High64(x) ^ a) * kMul;
b ^= (b >> 47);
b *= kMul;
return b;
}
[[nodiscard]]
constexpr uint64_t UNALIGNED_LOAD64(const char *p) noexcept {
uint64_t result{};
result |= static_cast<uint64_t>(p[0]);
result |= static_cast<uint64_t>(p[1]) << 8;
result |= static_cast<uint64_t>(p[2]) << 16;
result |= static_cast<uint64_t>(p[3]) << 24;
result |= static_cast<uint64_t>(p[4]) << 32;
result |= static_cast<uint64_t>(p[5]) << 40;
result |= static_cast<uint64_t>(p[6]) << 48;
result |= static_cast<uint64_t>(p[7]) << 56;
//memcpy(&result, p, sizeof(result));
return result;
}
[[nodiscard]]
constexpr uint32_t UNALIGNED_LOAD32(const char *p) noexcept {
uint32_t result{};
result |= static_cast<uint32_t>(p[0]);
result |= static_cast<uint32_t>(p[1]) << 8;
result |= static_cast<uint32_t>(p[2]) << 16;
result |= static_cast<uint32_t>(p[3]) << 24;
//memcpy(&result, p, sizeof(result));
return result;
}
#ifdef WORDS_BIGENDIAN
#define uint32_in_expected_order(x) (detail::byteSwap<uint32_t>(x))
#define uint64_in_expected_order(x) (detail::byteSwap<uint64_t>(x))
#else
#define uint32_in_expected_order(x) (x)
#define uint64_in_expected_order(x) (x)
#endif
#if !defined(LIKELY)
#if HAVE_BUILTIN_EXPECT
#define LIKELY(x) (__builtin_expect(!!(x), 1))
#else
#define LIKELY(x) (x)
#endif
#endif
[[nodiscard]]
constexpr uint64_t Fetch64(const char *p) noexcept {
return uint64_in_expected_order(UNALIGNED_LOAD64(p));
}
[[nodiscard]]
constexpr uint32_t Fetch32(const char *p) noexcept {
return uint32_in_expected_order(UNALIGNED_LOAD32(p));
}
// Some primes between 2^63 and 2^64 for various uses.
constexpr uint64_t k0 = 0xc3a5c85c97cb3127ULL;
constexpr uint64_t k1 = 0xb492b66fbe98f273ULL;
constexpr uint64_t k2 = 0x9ae16a3b2f90404fULL;
// Magic numbers for 32-bit hashing. Copied from Murmur3.
constexpr uint32_t c1 = 0xcc9e2d51;
constexpr uint32_t c2 = 0x1b873593;
// A 32-bit to 32-bit integer hash copied from Murmur3.
[[nodiscard]]
constexpr uint32_t fmix(uint32_t h) noexcept {
h ^= h >> 16;
h *= 0x85ebca6b;
h ^= h >> 13;
h *= 0xc2b2ae35;
h ^= h >> 16;
return h;
}
[[nodiscard]]
constexpr uint32_t Rotate32(uint32_t val, int shift) noexcept {
// Avoid shifting by 32: doing so yields an undefined result.
return shift == 0 ? val : ((val >> shift) | (val << (32 - shift)));
}
#undef PERMUTE3
#define PERMUTE3(a, b, c) do { detail::swap(a, b); detail::swap(a, c); } while (0)
[[nodiscard]]
constexpr uint32_t Mur(uint32_t a, uint32_t h) noexcept {
// Helper from Murmur3 for combining two 32-bit values.
a *= detail::c1;
a = Rotate32(a, 17);
a *= detail::c2;
h ^= a;
h = Rotate32(h, 19);
return h * 5 + 0xe6546b64;
}
[[nodiscard]]
constexpr uint32_t Hash32Len13to24(const char *s, size_t len) noexcept {
uint32_t a = Fetch32(s - 4 + (len >> 1));
uint32_t b = Fetch32(s + 4);
uint32_t c = Fetch32(s + len - 8);
uint32_t d = Fetch32(s + (len >> 1));
uint32_t e = Fetch32(s);
uint32_t f = Fetch32(s + len - 4);
uint32_t h = static_cast<uint32_t>(len);
return detail::fmix(Mur(f, Mur(e, Mur(d, Mur(c, Mur(b, Mur(a, h)))))));
}
[[nodiscard]]
constexpr uint32_t Hash32Len0to4(const char *s, size_t len) noexcept {
uint32_t b = 0;
uint32_t c = 9;
for (size_t i = 0; i < len; i++) {
auto const v = static_cast<signed char>(s[i]);
b = b * detail::c1 + static_cast<uint32_t>(v);
c ^= b;
}
return detail::fmix(Mur(b, Mur(static_cast<uint32_t>(len), c)));
}
[[nodiscard]]
constexpr uint32_t Hash32Len5to12(const char *s, size_t len) noexcept {
uint32_t a = static_cast<uint32_t>(len), b = a * 5, c = 9, d = b;
a += Fetch32(s);
b += Fetch32(s + len - 4);
c += Fetch32(s + ((len >> 1) & 4));
return detail::fmix(Mur(c, Mur(b, Mur(a, d))));
}
// Bitwise right rotate. Normally this will compile to a single
// instruction, especially if the shift is a manifest constant.
[[nodiscard]]
constexpr uint64_t Rotate(uint64_t val, int shift) noexcept {
// Avoid shifting by 64: doing so yields an undefined result.
return shift == 0 ? val : ((val >> shift) | (val << (64 - shift)));
}
[[nodiscard]]
constexpr uint64_t ShiftMix(uint64_t val) noexcept {
return val ^ (val >> 47);
}
[[nodiscard]]
constexpr uint64_t HashLen16(uint64_t u, uint64_t v) noexcept {
return Hash128to64(uint128(u, v));
}
[[nodiscard]]
constexpr uint64_t HashLen16(uint64_t u, uint64_t v, uint64_t mul) noexcept {
// Murmur-inspired hashing.
uint64_t a = (u ^ v) * mul;
a ^= (a >> 47);
uint64_t b = (v ^ a) * mul;
b ^= (b >> 47);
b *= mul;
return b;
}
[[nodiscard]]
constexpr uint64_t HashLen0to16(const char *s, size_t len) noexcept {
if (len >= 8) {
uint64_t mul = detail::k2 + len * 2;
uint64_t a = detail::Fetch64(s) + detail::k2;
uint64_t b = detail::Fetch64(s + len - 8);
uint64_t c = detail::Rotate(b, 37) * mul + a;
uint64_t d = (detail::Rotate(a, 25) + b) * mul;
return HashLen16(c, d, mul);
}
if (len >= 4) {
uint64_t mul = detail::k2 + len * 2;
uint64_t a = Fetch32(s);
return HashLen16(len + (a << 3), Fetch32(s + len - 4), mul);
}
if (len > 0) {
uint8_t a = static_cast<uint8_t>(s[0]);
uint8_t b = static_cast<uint8_t>(s[len >> 1]);
uint8_t c = static_cast<uint8_t>(s[len - 1]);
uint32_t y = static_cast<uint32_t>(a) + (static_cast<uint32_t>(b) << 8);
uint32_t z = static_cast<uint32_t>(len) + (static_cast<uint32_t>(c) << 2);
return ShiftMix(y * detail::k2 ^ z * detail::k0) * detail::k2;
}
return detail::k2;
}
// This probably works well for 16-byte strings as well, but it may be overkill
// in that case.
[[nodiscard]]
constexpr uint64_t HashLen17to32(const char *s, size_t len) noexcept {
uint64_t mul = detail::k2 + len * 2;
uint64_t a = detail::Fetch64(s) * detail::k1;
uint64_t b = detail::Fetch64(s + 8);
uint64_t c = detail::Fetch64(s + len - 8) * mul;
uint64_t d = detail::Fetch64(s + len - 16) * detail::k2;
return HashLen16(detail::Rotate(a + b, 43) + detail::Rotate(c, 30) + d,
a + detail::Rotate(b + detail::k2, 18) + c, mul);
}
// Return a 16-byte hash for 48 bytes. Quick and dirty.
// Callers do best to use "random-looking" values for a and b.
[[nodiscard]]
constexpr detail::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(
uint64_t w, uint64_t x, uint64_t y, uint64_t z, uint64_t a, uint64_t b) noexcept {
a += w;
b = detail::Rotate(b + a + z, 21);
uint64_t c = a;
a += x;
a += y;
b += detail::Rotate(a, 44);
return detail::pair(a + z, b + c);
}
// Return a 16-byte hash for s[0] ... s[31], a, and b. Quick and dirty.
[[nodiscard]]
constexpr detail::pair<uint64_t, uint64_t> WeakHashLen32WithSeeds(
const char* s, uint64_t a, uint64_t b) noexcept {
return WeakHashLen32WithSeeds(detail::Fetch64(s),
detail::Fetch64(s + 8),
detail::Fetch64(s + 16),
detail::Fetch64(s + 24),
a,
b);
}
// Return an 8-byte hash for 33 to 64 bytes.
[[nodiscard]]
constexpr uint64_t HashLen33to64(const char *s, size_t len) noexcept {
uint64_t mul = detail::k2 + len * 2;
uint64_t a = detail::Fetch64(s) * detail::k2;
uint64_t b = detail::Fetch64(s + 8);
uint64_t c = detail::Fetch64(s + len - 24);
uint64_t d = detail::Fetch64(s + len - 32);
uint64_t e = detail::Fetch64(s + 16) * detail::k2;
uint64_t f = detail::Fetch64(s + 24) * 9;
uint64_t g = detail::Fetch64(s + len - 8);
uint64_t h = detail::Fetch64(s + len - 16) * mul;
uint64_t u = detail::Rotate(a + g, 43) + (detail::Rotate(b, 30) + c) * 9;
uint64_t v = ((a + g) ^ d) + f + 1;
uint64_t w = detail::byteSwap((u + v) * mul) + h;
uint64_t x = detail::Rotate(e + f, 42) + c;
uint64_t y = (detail::byteSwap((v + w) * mul) + g) * mul;
uint64_t z = e + f + c;
a = detail::byteSwap((x + z) * mul + y) + b;
b = ShiftMix((z + a) * mul + d + h) * mul;
return b + x;
}
// A subroutine for CityHash128(). Returns a decent 128-bit hash for strings
// of any length representable in signed long. Based on City and Murmur.
[[nodiscard]]
constexpr uint128 CityMurmur(const char *s, size_t len, uint128 seed) noexcept {
uint64_t a = detail::Uint128Low64(seed);
uint64_t b = detail::Uint128High64(seed);
uint64_t c = 0;
uint64_t d = 0;
if (len <= 16) {
a = ShiftMix(a * detail::k1) * detail::k1;
c = b * detail::k1 + HashLen0to16(s, len);
d = ShiftMix(a + (len >= 8 ? detail::Fetch64(s) : c));
} else {
c = HashLen16(detail::Fetch64(s + len - 8) + detail::k1, a);
d = HashLen16(b + len, c + detail::Fetch64(s + len - 16));
a += d;
// len > 16 here, so do...while is safe
do {
a ^= ShiftMix(detail::Fetch64(s) * detail::k1) * detail::k1;
a *= detail::k1;
b ^= a;
c ^= ShiftMix(detail::Fetch64(s + 8) * detail::k1) * detail::k1;
c *= detail::k1;
d ^= c;
s += 16;
len -= 16;
} while (len > 16);
}
a = HashLen16(a, c);
b = HashLen16(d, b);
return uint128(a ^ b, HashLen16(b, a));
}
}
[[nodiscard]]
constexpr uint32_t CityHash32(const char *s, size_t len) noexcept {
if (len <= 24) {
return len <= 12 ?
(len <= 4 ? detail::Hash32Len0to4(s, len) : detail::Hash32Len5to12(s, len)) :
detail::Hash32Len13to24(s, len);
}
// len > 24
uint32_t h = static_cast<uint32_t>(len), g = detail::c1 * h, f = g;
uint32_t a0 = detail::Rotate32(detail::Fetch32(s + len - 4) * detail::c1, 17) * detail::c2;
uint32_t a1 = detail::Rotate32(detail::Fetch32(s + len - 8) * detail::c1, 17) * detail::c2;
uint32_t a2 = detail::Rotate32(detail::Fetch32(s + len - 16) * detail::c1, 17) * detail::c2;
uint32_t a3 = detail::Rotate32(detail::Fetch32(s + len - 12) * detail::c1, 17) * detail::c2;
uint32_t a4 = detail::Rotate32(detail::Fetch32(s + len - 20) * detail::c1, 17) * detail::c2;
h ^= a0;
h = detail::Rotate32(h, 19);
h = h * 5 + 0xe6546b64;
h ^= a2;
h = detail::Rotate32(h, 19);
h = h * 5 + 0xe6546b64;
g ^= a1;
g = detail::Rotate32(g, 19);
g = g * 5 + 0xe6546b64;
g ^= a3;
g = detail::Rotate32(g, 19);
g = g * 5 + 0xe6546b64;
f += a4;
f = detail::Rotate32(f, 19);
f = f * 5 + 0xe6546b64;
size_t iters = (len - 1) / 20;
do {
uint32_t a0 = detail::Rotate32(detail::Fetch32(s) * detail::c1, 17) * detail::c2;
uint32_t a1 = detail::Fetch32(s + 4);
uint32_t a2 = detail::Rotate32(detail::Fetch32(s + 8) * detail::c1, 17) * detail::c2;
uint32_t a3 = detail::Rotate32(detail::Fetch32(s + 12) * detail::c1, 17) * detail::c2;
uint32_t a4 = detail::Fetch32(s + 16);
h ^= a0;
h = detail::Rotate32(h, 18);
h = h * 5 + 0xe6546b64;
f += a1;
f = detail::Rotate32(f, 19);
f = f * detail::c1;
g += a2;
g = detail::Rotate32(g, 18);
g = g * 5 + 0xe6546b64;
h ^= a3 + a1;
h = detail::Rotate32(h, 19);
h = h * 5 + 0xe6546b64;
g ^= a4;
g = detail::byteSwap(g) * 5;
h += a4 * 5;
h = detail::byteSwap(h);
f += a0;
PERMUTE3(f, h, g);
s += 20;
} while (--iters != 0);
g = detail::Rotate32(g, 11) * detail::c1;
g = detail::Rotate32(g, 17) * detail::c1;
f = detail::Rotate32(f, 11) * detail::c1;
f = detail::Rotate32(f, 17) * detail::c1;
h = detail::Rotate32(h + g, 19);
h = h * 5 + 0xe6546b64;
h = detail::Rotate32(h, 17) * detail::c1;
h = detail::Rotate32(h + f, 19);
h = h * 5 + 0xe6546b64;
h = detail::Rotate32(h, 17) * detail::c1;
return h;
}
[[nodiscard]]
constexpr uint64_t CityHash64(const char *s, size_t len) noexcept {
if (len <= 32) {
if (len <= 16) {
return detail::HashLen0to16(s, len);
} else {
return detail::HashLen17to32(s, len);
}
} else if (len <= 64) {
return detail::HashLen33to64(s, len);
}
// For strings over 64 bytes we hash the end first, and then as we
// loop we keep 56 bytes of state: v, w, x, y, and z.
uint64_t x = detail::Fetch64(s + len - 40);
uint64_t y = detail::Fetch64(s + len - 16) + detail::Fetch64(s + len - 56);
uint64_t z = detail::HashLen16(detail::Fetch64(s + len - 48) + len, detail::Fetch64(s + len - 24));
detail::pair<uint64_t, uint64_t> v = detail::WeakHashLen32WithSeeds(s + len - 64, len, z);
detail::pair<uint64_t, uint64_t> w = detail::WeakHashLen32WithSeeds(s + len - 32, y + detail::k1, x);
x = x * detail::k1 + detail::Fetch64(s);
// Decrease len to the nearest multiple of 64, and operate on 64-byte chunks.
len = (len - 1) & ~static_cast<size_t>(63);
do {
x = detail::Rotate(x + y + v.first + detail::Fetch64(s + 8), 37) * detail::k1;
y = detail::Rotate(y + v.second + detail::Fetch64(s + 48), 42) * detail::k1;
x ^= w.second;
y += v.first + detail::Fetch64(s + 40);
z = detail::Rotate(z + w.first, 33) * detail::k1;
v = detail::WeakHashLen32WithSeeds(s, v.second * detail::k1, x + w.first);
w = detail::WeakHashLen32WithSeeds(s + 32, z + w.second, y + detail::Fetch64(s + 16));
detail::swap(z, x);
s += 64;
len -= 64;
} while (len != 0);
return detail::HashLen16(detail::HashLen16(v.first, w.first) + detail::ShiftMix(y) * detail::k1 + z,
detail::HashLen16(v.second, w.second) + x);
}
[[nodiscard]]
constexpr uint64_t CityHash64WithSeeds(const char *s, size_t len,
uint64_t seed0, uint64_t seed1) noexcept {
return detail::HashLen16(CityHash64(s, len) - seed0, seed1);
}
[[nodiscard]]
constexpr uint64_t CityHash64WithSeed(const char *s, size_t len, uint64_t seed) noexcept {
return CityHash64WithSeeds(s, len, detail::k2, seed);
}
[[nodiscard]]
constexpr uint128 CityHash128WithSeed(const char *s, size_t len, uint128 seed) noexcept {
if (len < 128) {
return detail::CityMurmur(s, len, seed);
}
// We expect len >= 128 to be the common case. Keep 56 bytes of state:
// v, w, x, y, and z.
detail::pair<uint64_t, uint64_t> v, w;
uint64_t x = detail::Uint128Low64(seed);
uint64_t y = detail::Uint128High64(seed);
uint64_t z = len * detail::k1;
v.first = detail::Rotate(y ^ detail::k1, 49) * detail::k1 + detail::Fetch64(s);
v.second = detail::Rotate(v.first, 42) * detail::k1 + detail::Fetch64(s + 8);
w.first = detail::Rotate(y + z, 35) * detail::k1 + x;
w.second = detail::Rotate(x + detail::Fetch64(s + 88), 53) * detail::k1;
// This is the same inner loop as CityHash64(), manually unrolled.
do {
x = detail::Rotate(x + y + v.first + detail::Fetch64(s + 8), 37) * detail::k1;
y = detail::Rotate(y + v.second + detail::Fetch64(s + 48), 42) * detail::k1;
x ^= w.second;
y += v.first + detail::Fetch64(s + 40);
z = detail::Rotate(z + w.first, 33) * detail::k1;
v = detail::WeakHashLen32WithSeeds(s, v.second * detail::k1, x + w.first);
w = detail::WeakHashLen32WithSeeds(s + 32, z + w.second, y + detail::Fetch64(s + 16));
detail::swap(z, x);
s += 64;
x = detail::Rotate(x + y + v.first + detail::Fetch64(s + 8), 37) * detail::k1;
y = detail::Rotate(y + v.second + detail::Fetch64(s + 48), 42) * detail::k1;
x ^= w.second;
y += v.first + detail::Fetch64(s + 40);
z = detail::Rotate(z + w.first, 33) * detail::k1;
v = detail::WeakHashLen32WithSeeds(s, v.second * detail::k1, x + w.first);
w = detail::WeakHashLen32WithSeeds(s + 32, z + w.second, y + detail::Fetch64(s + 16));
detail::swap(z, x);
s += 64;
len -= 128;
} while (LIKELY(len >= 128));
x += detail::Rotate(v.first + z, 49) * detail::k0;
y = y * detail::k0 + detail::Rotate(w.second, 37);
z = z * detail::k0 + detail::Rotate(w.first, 27);
w.first *= 9;
v.first *= detail::k0;
// If 0 < len < 128, hash up to 4 chunks of 32 bytes each from the end of s.
for (size_t tail_done = 0; tail_done < len; ) {
tail_done += 32;
y = detail::Rotate(x + y, 42) * detail::k0 + v.second;
w.first += detail::Fetch64(s + len - tail_done + 16);
x = x * detail::k0 + w.first;
z += w.second + detail::Fetch64(s + len - tail_done);
w.second += v.first;
v = detail::WeakHashLen32WithSeeds(s + len - tail_done, v.first + z, v.second);
v.first *= detail::k0;
}
// At this point our 56 bytes of state should contain more than
// enough information for a strong 128-bit hash. We use two
// different 56-byte-to-8-byte hashes to get a 16-byte final result.
x = detail::HashLen16(x, v.first);
y = detail::HashLen16(y + z, w.first);
return uint128(detail::HashLen16(x + v.second, w.second) + y,
detail::HashLen16(x + w.second, y + v.second));
}
[[nodiscard]]
constexpr uint128 CityHash128(const char *s, size_t len) noexcept {
return len >= 16 ?
CityHash128WithSeed(s + 16, len - 16,
uint128(detail::Fetch64(s), detail::Fetch64(s + 8) + detail::k0)) :
CityHash128WithSeed(s, len, uint128(detail::k0, detail::k1));
}
}
#endif // CITY_HASH_H_

View File

@ -1,3 +1,18 @@
if(${CMAKE_SYSTEM_NAME} STREQUAL "Windows")
set(OX_OS_WINDOWS TRUE)
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "FreeBSD")
set(OX_OS_FREEBSD TRUE)
else()
set(OX_OS_FREEBSD FALSE)
endif()
if(${CMAKE_SYSTEM_NAME} STREQUAL "Linux")
set(OX_OS_LINUX TRUE)
else()
set(OX_OS_LINUX FALSE)
endif()
if(OX_USE_STDLIB) if(OX_USE_STDLIB)
add_subdirectory(oc) add_subdirectory(oc)
endif() endif()

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include <ox/std/string.hpp> #include <ox/std/string.hpp>
@ -13,7 +13,7 @@ namespace ox {
ClArgs::ClArgs(int argc, const char **args) noexcept { ClArgs::ClArgs(int argc, const char **args) noexcept {
for (auto i = 0u; i < static_cast<unsigned>(argc); ++i) { for (auto i = 0u; i < static_cast<unsigned>(argc); ++i) {
String arg = args[i]; auto arg = String(args[i]);
if (arg[0] == '-') { if (arg[0] == '-') {
while (arg[0] == '-' && arg.len()) { while (arg[0] == '-' && arg.len()) {
arg = arg.substr(1); arg = arg.substr(1);
@ -21,13 +21,13 @@ ClArgs::ClArgs(int argc, const char **args) noexcept {
m_bools[arg] = true; m_bools[arg] = true;
// parse additional arguments // parse additional arguments
if (i < static_cast<unsigned>(argc) && args[i + 1]) { if (i < static_cast<unsigned>(argc) && args[i + 1]) {
String val = args[i + 1]; auto val = String(args[i + 1]);
if (val.len() && val[i] != '-') { if (val.len() && val[i] != '-') {
if (val == "false") { if (val == "false") {
m_bools[arg] = false; m_bools[arg] = false;
} }
m_strings[arg] = val; m_strings[arg] = val;
if (auto r = ox_atoi(val.c_str()); r.error == 0) { if (auto r = ox::atoi(val.c_str()); r.error == 0) {
m_ints[arg] = r.value; m_ints[arg] = r.value;
} }
++i; ++i;
@ -42,9 +42,9 @@ bool ClArgs::getBool(ox::CRStringView arg, bool defaultValue) const noexcept {
return !err ? *value : defaultValue; return !err ? *value : defaultValue;
} }
String ClArgs::getString(ox::CRStringView arg, const char *defaultValue) const noexcept { String ClArgs::getString(ox::CRStringView arg, ox::StringView defaultValue) const noexcept {
auto [value, err] = m_strings.at(arg); auto [value, err] = m_strings.at(arg);
return !err ? *value : defaultValue; return !err ? ox::String(*value) : ox::String(defaultValue);
} }
int ClArgs::getInt(ox::CRStringView arg, int defaultValue) const noexcept { int ClArgs::getInt(ox::CRStringView arg, int defaultValue) const noexcept {

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -26,7 +26,7 @@ class ClArgs {
bool getBool(ox::CRStringView arg, bool defaultValue) const noexcept; bool getBool(ox::CRStringView arg, bool defaultValue) const noexcept;
[[nodiscard]] [[nodiscard]]
String getString(ox::CRStringView argName, const char *defaultValue) const noexcept; String getString(ox::CRStringView argName, ox::StringView defaultValue) const noexcept;
[[nodiscard]] [[nodiscard]]
int getInt(ox::CRStringView arg, int defaultValue) const noexcept; int getInt(ox::CRStringView arg, int defaultValue) const noexcept;

View File

@ -5,7 +5,6 @@ add_library(
write.cpp write.cpp
) )
if(NOT MSVC) if(NOT MSVC)
target_compile_options(OxClaw PRIVATE -Wsign-conversion) target_compile_options(OxClaw PRIVATE -Wsign-conversion)
target_compile_options(OxClaw PRIVATE -Wconversion) target_compile_options(OxClaw PRIVATE -Wconversion)
@ -17,6 +16,17 @@ target_link_libraries(
$<$<BOOL:${OX_USE_STDLIB}>:OxOrganicClaw> $<$<BOOL:${OX_USE_STDLIB}>:OxOrganicClaw>
) )
#if(OX_USE_STDLIB)
# add_executable(
# readclaw
# readclaw.cpp
# )
# target_link_libraries(
# readclaw PUBLIC
# OxClaw
# )
#endif()
install(TARGETS OxClaw install(TARGETS OxClaw
LIBRARY DESTINATION lib LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib ARCHIVE DESTINATION lib

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -12,34 +12,66 @@
namespace ox { namespace ox {
Result<ClawHeader> readClawHeader(const char *buff, std::size_t buffLen) noexcept { ox::Result<ox::StringView> readClawTypeId(ox::BufferView buff) noexcept {
const auto s1End = ox_strchr(buff, ';', buffLen); auto buffRaw = buff.data();
auto buffLen = buff.size();
size_t outSz{};
const auto s1End = ox::strchr(buffRaw, ';', buffLen);
if (!s1End) { if (!s1End) {
return OxError(1, "Could not read Claw header"); return OxError(1, "Could not read Claw header");
} }
const auto s1Size = static_cast<std::size_t>(s1End - buff); auto const fmtSz = static_cast<std::size_t>(s1End - buffRaw) + 1;
const String fmt(buff, s1Size); buffRaw += fmtSz;
buff += s1Size + 1; buffLen -= fmtSz;
buffLen -= s1Size + 1; outSz += fmtSz;
auto const s2End = ox::strchr(buffRaw, ';', buffLen);
const auto s2End = ox_strchr(buff, ';', buffLen);
if (!s2End) { if (!s2End) {
return OxError(2, "Could not read Claw header"); return OxError(2, "Could not read Claw header");
} }
const auto s2Size = static_cast<std::size_t>(s2End - buff); auto const s2Size = static_cast<std::size_t>(s2End - buffRaw) + 1;
const String typeName(buff, s2Size); buffRaw += s2Size;
buff += s2Size + 1; buffLen -= s2Size;
buffLen -= s2Size + 1; outSz += s2Size;
auto const s3End = ox::strchr(buffRaw, ';', buffLen) + 1;
const auto s3End = ox_strchr(buff, ';', buffLen);
if (!s3End) { if (!s3End) {
return OxError(3, "Could not read Claw header"); return OxError(3, "Could not read Claw header");
} }
const auto s3Size = static_cast<std::size_t>(s3End - buff); auto const s3Size = static_cast<std::size_t>(s3End - buffRaw);
const String versionStr(buff, s3Size); buffRaw += s3Size;
buff += s3Size + 1; buffLen -= s3Size;
buffLen -= s3Size + 1; outSz += s3Size;
return {{buff.data() + fmtSz, outSz - fmtSz - 1}};
}
Result<ClawHeader> readClawHeader(ox::BufferView buff) noexcept {
auto buffRaw = buff.data();
auto buffLen = buff.size();
const auto s1End = ox::strchr(buffRaw, ';', buffLen);
if (!s1End) {
return OxError(1, "Could not read Claw header");
}
auto const s1Size = static_cast<std::size_t>(s1End - buffRaw);
StringView const fmt(buffRaw, s1Size);
buffRaw += s1Size + 1;
buffLen -= s1Size + 1;
auto const s2End = ox::strchr(buffRaw, ';', buffLen);
if (!s2End) {
return OxError(2, "Could not read Claw header");
}
auto const s2Size = static_cast<std::size_t>(s2End - buffRaw);
StringView const typeName(buffRaw, s2Size);
buffRaw += s2Size + 1;
buffLen -= s2Size + 1;
auto const s3End = ox::strchr(buffRaw, ';', buffLen);
if (!s3End) {
return OxError(3, "Could not read Claw header");
}
auto const s3Size = static_cast<std::size_t>(s3End - buffRaw);
StringView const versionStr(buffRaw, s3Size);
buffRaw += s3Size + 1;
buffLen -= s3Size + 1;
ClawHeader hdr; ClawHeader hdr;
if (fmt == "M2") { if (fmt == "M2") {
hdr.fmt = ClawFormat::Metal; hdr.fmt = ClawFormat::Metal;
@ -49,38 +81,31 @@ Result<ClawHeader> readClawHeader(const char *buff, std::size_t buffLen) noexcep
return OxError(4, "Claw format does not match any supported format/version combo"); return OxError(4, "Claw format does not match any supported format/version combo");
} }
hdr.typeName = typeName; hdr.typeName = typeName;
if (auto r = ox_atoi(versionStr.c_str()); r.error == 0) { std::ignore = ox::atoi(versionStr).copyTo(hdr.typeVersion);
hdr.typeVersion = r.value; hdr.data = buffRaw;
}
hdr.data = buff;
hdr.dataSize = buffLen; hdr.dataSize = buffLen;
return hdr; return hdr;
} }
Result<ClawHeader> readClawHeader(const ox::Buffer &buff) noexcept { Result<BufferView> stripClawHeader(ox::BufferView buff) noexcept {
return readClawHeader(buff.data(), buff.size()); oxRequire(header, readClawHeader(buff));
return {{header.data, header.dataSize}};
} }
Result<Buffer> stripClawHeader(const char *buff, std::size_t buffLen) noexcept { Result<ModelObject> readClaw(TypeStore &ts, BufferView buff) noexcept {
oxRequire(header, readClawHeader(buff, buffLen)); oxRequire(header, readClawHeader(buff));
Buffer out(header.dataSize); auto const [t, tdErr] = ts.getLoad(
ox_memcpy(out.data(), header.data, out.size()); header.typeName, header.typeVersion, header.typeParams);
return out; if (tdErr) {
} return OxError(3, "Could not load type descriptor");
}
Result<Buffer> stripClawHeader(const ox::Buffer &buff) noexcept {
return stripClawHeader(buff.data(), buff.size());
}
Result<ModelObject> readClaw(TypeStore *ts, const char *buff, std::size_t buffSz) noexcept {
oxRequire(header, readClawHeader(buff, buffSz));
oxRequire(t, ts->getLoad(header.typeName, header.typeVersion, header.typeParams));
ModelObject obj; ModelObject obj;
oxReturnError(obj.setType(t)); oxReturnError(obj.setType(t));
switch (header.fmt) { switch (header.fmt) {
case ClawFormat::Metal: case ClawFormat::Metal:
{ {
MetalClawReader reader(reinterpret_cast<const uint8_t*>(header.data), header.dataSize); ox::BufferReader br({header.data, header.dataSize});
MetalClawReader reader(br);
ModelHandlerInterface handler(&reader); ModelHandlerInterface handler(&reader);
oxReturnError(model(&handler, &obj)); oxReturnError(model(&handler, &obj));
return obj; return obj;
@ -88,7 +113,7 @@ Result<ModelObject> readClaw(TypeStore *ts, const char *buff, std::size_t buffSz
case ClawFormat::Organic: case ClawFormat::Organic:
{ {
#ifdef OX_USE_STDLIB #ifdef OX_USE_STDLIB
OrganicClawReader reader(header.data, header.dataSize); OrganicClawReader reader({header.data, header.dataSize});
ModelHandlerInterface handler(&reader); ModelHandlerInterface handler(&reader);
oxReturnError(model(&handler, &obj)); oxReturnError(model(&handler, &obj));
return obj; return obj;
@ -102,8 +127,4 @@ Result<ModelObject> readClaw(TypeStore *ts, const char *buff, std::size_t buffSz
return OxError(1); return OxError(1);
} }
Result<ModelObject> readClaw(TypeStore *ts, const Buffer &buff) noexcept {
return readClaw(ts, buff.data(), buff.size());
}
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -8,6 +8,7 @@
#pragma once #pragma once
#include <ox/std/span.hpp>
#include <ox/mc/read.hpp> #include <ox/mc/read.hpp>
#ifdef OX_USE_STDLIB #ifdef OX_USE_STDLIB
#include <ox/oc/read.hpp> #include <ox/oc/read.hpp>
@ -31,17 +32,15 @@ struct ClawHeader {
std::size_t dataSize = 0; std::size_t dataSize = 0;
}; };
Result<ClawHeader> readClawHeader(const char *buff, std::size_t buffLen) noexcept; ox::Result<ox::StringView> readClawTypeId(ox::BufferView buff) noexcept;
Result<ClawHeader> readClawHeader(const ox::Buffer &buff) noexcept; Result<ClawHeader> readClawHeader(ox::BufferView buff) noexcept;
Result<Buffer> stripClawHeader(const char *buff, std::size_t buffLen) noexcept; Result<BufferView> stripClawHeader(ox::BufferView buff) noexcept;
Result<Buffer> stripClawHeader(const ox::Buffer &buff) noexcept;
template<typename T> template<typename T>
Error readClaw(const char *buff, std::size_t buffLen, T *val) { Error readClaw(ox::BufferView buff, T &val) {
oxRequire(header, readClawHeader(buff, buffLen)); oxRequire(header, readClawHeader(buff));
if (header.typeName != getModelTypeName<T>()) { if (header.typeName != getModelTypeName<T>()) {
return OxError(Error_ClawTypeMismatch, "Claw Read: Type mismatch"); return OxError(Error_ClawTypeMismatch, "Claw Read: Type mismatch");
} }
@ -51,15 +50,16 @@ Error readClaw(const char *buff, std::size_t buffLen, T *val) {
switch (header.fmt) { switch (header.fmt) {
case ClawFormat::Metal: case ClawFormat::Metal:
{ {
MetalClawReader reader(reinterpret_cast<const uint8_t*>(header.data), header.dataSize); ox::BufferReader br({header.data, header.dataSize});
MetalClawReader reader(br);
ModelHandlerInterface handler(&reader); ModelHandlerInterface handler(&reader);
return model(&handler, val); return model(&handler, &val);
} }
case ClawFormat::Organic: case ClawFormat::Organic:
{ {
#ifdef OX_USE_STDLIB #ifdef OX_USE_STDLIB
OrganicClawReader reader(header.data, header.dataSize); OrganicClawReader reader(header.data, header.dataSize);
return model(&reader, val); return model(&reader, &val);
#else #else
break; break;
#endif #endif
@ -71,24 +71,12 @@ Error readClaw(const char *buff, std::size_t buffLen, T *val) {
} }
template<typename T> template<typename T>
Result<T> readClaw(const char *buff, std::size_t buffLen) { Result<T> readClaw(ox::BufferView buff) {
T val; Result<T> val;
oxReturnError(readClaw(buff, buffLen, &val)); oxReturnError(readClaw(buff, val.value));
return val; return val;
} }
template<typename T> Result<ModelObject> readClaw(TypeStore &ts, BufferView buff) noexcept;
Error readClaw(const Buffer &buff, T *val) {
return readClaw<T>(buff.data(), buff.size(), val);
}
template<typename T>
Result<T> readClaw(const Buffer &buff) {
return readClaw<T>(buff.data(), buff.size());
}
Result<ModelObject> readClaw(TypeStore *ts, const char *buff, std::size_t buffSz) noexcept;
Result<ModelObject> readClaw(TypeStore *ts, const Buffer &buff) noexcept;
} }

30
deps/ox/src/ox/claw/readclaw.cpp vendored Normal file
View File

@ -0,0 +1,30 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include <cstdio>
#include <ox/std/reader.hpp>
#include <ox/std/trace.hpp>
#include "claw.hpp"
int main(int argc, char **args) {
if (argc > 2) {
oxErr("Too many arguments");
return -1;
}
auto const file = argc == 1 ? stdin : fopen(args[1], "r");
if (fseek(file, 0, SEEK_END)) {
oxErr("Could not get file size\n");
return -2;
}
auto const size = static_cast<std::size_t>(ftell(file));
oxDebugf("{}", size);
return 0;
}

View File

@ -8,7 +8,8 @@ target_link_libraries(
OxClaw OxClaw
) )
add_test("[ox/claw] ClawTest ClawHeaderReader" ClawTest ClawHeaderReader) add_test("[ox/claw] ClawHeaderReader" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawHeaderReader)
add_test("[ox/claw] ClawTest ClawHeaderReader2" ClawTest ClawHeaderReader2) add_test("[ox/claw] ClawHeaderReader2" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawHeaderReader2)
add_test("[ox/claw] ClawTest ClawWriter" ClawTest ClawWriter) add_test("[ox/claw] ClawHeaderReadTypeId" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawHeaderReadTypeId)
add_test("[ox/claw] ClawTest ClawReader" ClawTest ClawReader) add_test("[ox/claw] ClawWriter" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawWriter)
add_test("[ox/claw] ClawReader" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawReader)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -8,11 +8,7 @@
#undef NDEBUG #undef NDEBUG
#include <cassert>
#include <iostream>
#include <map> #include <map>
#include <memory>
#include <string>
#include <ox/claw/format.hpp> #include <ox/claw/format.hpp>
#include <ox/claw/read.hpp> #include <ox/claw/read.hpp>
#include <ox/claw/write.hpp> #include <ox/claw/write.hpp>
@ -33,7 +29,7 @@ struct TestStructNest {
static constexpr auto TypeVersion = 1; static constexpr auto TypeVersion = 1;
bool Bool = false; bool Bool = false;
uint32_t Int = 0; uint32_t Int = 0;
ox::BString<32> String = ""; ox::IString<32> String = "";
}; };
struct TestStruct { struct TestStruct {
@ -51,7 +47,7 @@ struct TestStruct {
int32_t Int8 = 0; int32_t Int8 = 0;
int unionIdx = 1; int unionIdx = 1;
TestUnion Union; TestUnion Union;
ox::BString<32> String = ""; ox::IString<32> String = "";
uint32_t List[4] = {0, 0, 0, 0}; uint32_t List[4] = {0, 0, 0, 0};
TestStructNest EmptyStruct; TestStructNest EmptyStruct;
TestStructNest Struct; TestStructNest Struct;
@ -107,13 +103,13 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) {
return OxError(0); return OxError(0);
} }
static std::map<std::string_view, ox::Error(*)()> tests = { static std::map<ox::StringView, ox::Error(*)()> tests = {
{ {
{ {
"ClawHeaderReader", "ClawHeaderReader",
[] { [] {
ox::String hdr = "O1;com.drinkingtea.ox.claw.test.Header;2;"; constexpr auto hdr = ox::StringLiteral("O1;com.drinkingtea.ox.claw.test.Header;2;");
auto [ch, err] = ox::readClawHeader(hdr.c_str(), hdr.len() + 1); auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.len() + 1});
oxAssert(err, "Error parsing header"); oxAssert(err, "Error parsing header");
oxAssert(ch.fmt == ox::ClawFormat::Organic, "Format wrong"); oxAssert(ch.fmt == ox::ClawFormat::Organic, "Format wrong");
oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header", "Type name wrong"); oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header", "Type name wrong");
@ -124,8 +120,8 @@ static std::map<std::string_view, ox::Error(*)()> tests = {
{ {
"ClawHeaderReader2", "ClawHeaderReader2",
[] { [] {
ox::String hdr = "M2;com.drinkingtea.ox.claw.test.Header2;3;"; constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;");
auto [ch, err] = ox::readClawHeader(hdr.c_str(), hdr.len() + 1); auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.len() + 1});
oxAssert(err, "Error parsing header"); oxAssert(err, "Error parsing header");
oxAssert(ch.fmt == ox::ClawFormat::Metal, "Format wrong"); oxAssert(ch.fmt == ox::ClawFormat::Metal, "Format wrong");
oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header2", "Type name wrong"); oxAssert(ch.typeName == "com.drinkingtea.ox.claw.test.Header2", "Type name wrong");
@ -133,6 +129,16 @@ static std::map<std::string_view, ox::Error(*)()> tests = {
return OxError(0); return OxError(0);
} }
}, },
{
"ClawHeaderReadTypeId",
[] {
constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;awefawf");
constexpr auto expected = ox::StringLiteral("com.drinkingtea.ox.claw.test.Header2;3");
oxRequire(actual, ox::readClawTypeId({hdr.data(), hdr.len() + 1}));
oxExpect(actual, expected);
return ox::Error{};
}
},
{ {
"ClawWriter", "ClawWriter",
[] { [] {
@ -160,7 +166,7 @@ static std::map<std::string_view, ox::Error(*)()> tests = {
testIn.Struct.String = "Test String 2"; testIn.Struct.String = "Test String 2";
const auto [buff, err] = ox::writeMC(testIn); const auto [buff, err] = ox::writeMC(testIn);
oxAssert(err, "writeClaw failed"); oxAssert(err, "writeClaw failed");
oxAssert(ox::readMC(buff.data(), buff.size(), &testOut), "readClaw failed"); oxAssert(ox::readMC(buff, testOut), "readClaw failed");
//std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n"; //std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n";
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch"); oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");
oxAssert(testIn.Int == testOut.Int, "Int value mismatch"); oxAssert(testIn.Int == testOut.Int, "Int value mismatch");
@ -192,14 +198,14 @@ static std::map<std::string_view, ox::Error(*)()> tests = {
}; };
int main(int argc, const char **args) { int main(int argc, const char **args) {
int retval = -1; if (argc < 2) {
if (argc > 0) { oxError("Must specify test to run");
auto testName = args[1];
if (tests.find(testName) != tests.end()) {
retval = static_cast<int>(tests[testName]());
} else {
retval = 1;
} }
auto const testName = args[1];
auto const func = tests.find(testName);
if (func != tests.end()) {
oxAssert(func->second(), "Test returned Error");
return 0;
} }
return retval; return -1;
} }

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include "write.hpp" #include "write.hpp"

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -61,14 +61,14 @@ struct type_version<T, decltype((void) T::TypeVersion, -1)> {
template<typename T> template<typename T>
constexpr const char *getTypeName(const T *t) noexcept { constexpr const char *getTypeName(const T *t) noexcept {
TypeInfoCatcher tnc; TypeInfoCatcher tnc;
oxIgnoreError(model(&tnc, t)); std::ignore = model(&tnc, t);
return tnc.name; return tnc.name;
} }
template<typename T> template<typename T>
constexpr int getTypeVersion(const T *t) noexcept { constexpr int getTypeVersion(const T *t) noexcept {
TypeInfoCatcher tnc; TypeInfoCatcher tnc;
oxIgnoreError(model(&tnc, t)); std::ignore = model(&tnc, t);
return tnc.version; return tnc.version;
} }
@ -88,7 +88,7 @@ ox::Error writeClawHeader(Writer_c auto &writer, const T *t, ClawFormat fmt) noe
oxReturnError(writer.put(';')); oxReturnError(writer.put(';'));
const auto tn = detail::getTypeVersion(t); const auto tn = detail::getTypeVersion(t);
if (tn > -1) { if (tn > -1) {
oxReturnError(ox::itoa(tn, writer)); oxReturnError(ox::writeItoa(tn, writer));
} }
oxReturnError(writer.put(';')); oxReturnError(writer.put(';'));
return {}; return {};

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include "signal.hpp" #include "signal.hpp"

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -245,7 +245,7 @@ class Signal<Error(Args...)> {
} }
Error call(Args... args) noexcept final { Error call(Args... args) noexcept final {
return f(args...); return f(ox::forward<Args>(args)...);
} }
}; };
@ -260,7 +260,7 @@ class Signal<Error(Args...)> {
} }
Error call(Args... args) noexcept final { Error call(Args... args) noexcept final {
return (m_receiver->*(m_methodPtr))(args...); return (m_receiver->*(m_methodPtr))(ox::forward<Args>(args)...);
} }
void cleanup(Signal *signal) noexcept final { void cleanup(Signal *signal) noexcept final {
@ -286,7 +286,7 @@ class Signal<Error(Args...)> {
} }
Error call(Args... args) noexcept final { Error call(Args... args) noexcept final {
return (m_receiver->*(m_methodPtr))(args...); return (m_receiver->*(m_methodPtr))(ox::forward<Args>(args)...);
} }
void cleanup(Signal*) noexcept final { void cleanup(Signal*) noexcept final {
@ -391,14 +391,14 @@ Error Signal<Error(Args...)>::disconnectObject(const void *receiver) const noexc
template<class... Args> template<class... Args>
void Signal<Error(Args...)>::emit(Args... args) const noexcept { void Signal<Error(Args...)>::emit(Args... args) const noexcept {
for (auto &f : m_slots) { for (auto &f : m_slots) {
oxIgnoreError(f->call(args...)); std::ignore = f->call(ox::forward<Args>(args)...);
} }
} }
template<class... Args> template<class... Args>
Error Signal<Error(Args...)>::emitCheckError(Args... args) const noexcept { Error Signal<Error(Args...)>::emitCheckError(Args... args) const noexcept {
for (auto &f : m_slots) { for (auto &f : m_slots) {
oxReturnError(f->call(args...)); oxReturnError(f->call(ox::forward<Args>(args)...));
} }
return OxError(0); return OxError(0);
} }

View File

@ -7,4 +7,4 @@ add_executable(
target_link_libraries(EventTest OxEvent) target_link_libraries(EventTest OxEvent)
add_test("[ox/event] Test 1" EventTest "test1") add_test("[ox/event] Test 1" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/EventTest "test1")

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#undef NDEBUG #undef NDEBUG
@ -21,7 +21,7 @@ struct TestStruct: public ox::SignalHandler {
} }
}; };
std::map<std::string, std::function<ox::Error()>> tests = { std::map<ox::StringView, std::function<ox::Error()>> tests = {
{ {
"test1", "test1",
[] { [] {
@ -39,12 +39,14 @@ std::map<std::string, std::function<ox::Error()>> tests = {
}; };
int main(int argc, const char **args) { int main(int argc, const char **args) {
if (argc > 1) { if (argc < 2) {
auto testName = args[1]; oxError("Must specify test to run");
if (tests.find(testName) != tests.end()) {
oxAssert(tests[testName](), "Test returned Error");
return 0;
} }
auto const testName = args[1];
auto const func = tests.find(testName);
if (func != tests.end()) {
oxAssert(func->second(), "Test returned Error");
return 0;
} }
return -1; return -1;
} }

View File

@ -16,12 +16,6 @@ if(NOT MSVC)
endif() endif()
if(NOT OX_BARE_METAL) if(NOT OX_BARE_METAL)
if(NOT APPLE AND NOT MSVC)
target_link_libraries(
OxFS PUBLIC
stdc++fs
)
endif()
set_property( set_property(
TARGET TARGET
OxFS OxFS
@ -44,7 +38,6 @@ if(NOT OX_BARE_METAL)
target_link_libraries( target_link_libraries(
oxfs-tool oxfs-tool
OxFS OxFS
OxStd
) )
install( install(

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include "filestoretemplate.hpp" #include "filestoretemplate.hpp"

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -204,12 +204,12 @@ Error FileStoreTemplate<size_t>::format(void *buffer, std::size_t bufferSize) {
auto nb = new (buffer) Buffer(static_cast<size_t>(bufferSize)); auto nb = new (buffer) Buffer(static_cast<size_t>(bufferSize));
auto fsData = nb->malloc(sizeof(FileStoreData)).value; auto fsData = nb->malloc(sizeof(FileStoreData)).value;
if (!fsData.valid()) { if (!fsData.valid()) {
oxTrace("ox::fs::FileStoreTemplate::format::fail", "Could not read data section of FileStoreData"); oxTrace("ox.fs.FileStoreTemplate.format.fail", "Could not read data section of FileStoreData");
return OxError(1, "Could not read data section of FileStoreData"); return OxError(1, "Could not read data section of FileStoreData");
} }
auto data = nb->template dataOf<FileStoreData>(fsData); auto data = nb->template dataOf<FileStoreData>(fsData);
if (!data.valid()) { if (!data.valid()) {
oxTrace("ox::fs::FileStoreTemplate::format::fail", "Could not read data section of FileStoreData"); oxTrace("ox.fs.FileStoreTemplate.format.fail", "Could not read data section of FileStoreData");
return OxError(1, "Could not read data section of FileStoreData"); return OxError(1, "Could not read data section of FileStoreData");
} }
new (data) FileStoreData; new (data) FileStoreData;
@ -244,7 +244,7 @@ Error FileStoreTemplate<size_t>::decLinks(uint64_t id) {
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::write(uint64_t id64, const void *data, FsSize_t dataSize, uint8_t fileType) { Error FileStoreTemplate<size_t>::write(uint64_t id64, const void *data, FsSize_t dataSize, uint8_t fileType) {
const auto id = static_cast<size_t>(id64); const auto id = static_cast<size_t>(id64);
oxTracef("ox::fs::FileStoreTemplate::write", "Attempting to write to inode {}", id); oxTracef("ox.fs.FileStoreTemplate.write", "Attempting to write to inode {}", id);
auto existing = find(id); auto existing = find(id);
if (!canWrite(existing, dataSize)) { if (!canWrite(existing, dataSize)) {
oxReturnError(compact()); oxReturnError(compact());
@ -254,10 +254,10 @@ Error FileStoreTemplate<size_t>::write(uint64_t id64, const void *data, FsSize_t
if (canWrite(existing, dataSize)) { if (canWrite(existing, dataSize)) {
// delete the old node if it exists // delete the old node if it exists
if (existing.valid()) { if (existing.valid()) {
oxTracef("ox::fs::FileStoreTemplate::write", "Freeing old version of inode found at offset: {}", existing.offset()); oxTracef("ox.fs.FileStoreTemplate.write", "Freeing old version of inode found at offset: {}", existing.offset());
auto err = m_buffer->free(existing); auto err = m_buffer->free(existing);
if (err) { if (err) {
oxTrace("ox::fs::FileStoreTemplate::write::fail", "Free of old version of inode failed"); oxTrace("ox.fs.FileStoreTemplate.write.fail", "Free of old version of inode failed");
return err; return err;
} }
existing = nullptr; existing = nullptr;
@ -266,12 +266,12 @@ Error FileStoreTemplate<size_t>::write(uint64_t id64, const void *data, FsSize_t
auto dest = m_buffer->malloc(dataSize).value; auto dest = m_buffer->malloc(dataSize).value;
// if first malloc failed, compact and try again // if first malloc failed, compact and try again
if (!dest.valid()) { if (!dest.valid()) {
oxTrace("ox::fs::FileStoreTemplate::write", "Allocation failed, compacting"); oxTrace("ox.fs.FileStoreTemplate.write", "Allocation failed, compacting");
oxReturnError(compact()); oxReturnError(compact());
dest = m_buffer->malloc(dataSize).value; dest = m_buffer->malloc(dataSize).value;
} }
if (dest.valid()) { if (dest.valid()) {
oxTrace("ox::fs::FileStoreTemplate::write", "Memory allocated"); oxTrace("ox.fs.FileStoreTemplate.write", "Memory allocated");
dest->id = id; dest->id = id;
dest->fileType = fileType; dest->fileType = fileType;
auto destData = m_buffer->template dataOf<uint8_t>(dest); auto destData = m_buffer->template dataOf<uint8_t>(dest);
@ -279,27 +279,27 @@ Error FileStoreTemplate<size_t>::write(uint64_t id64, const void *data, FsSize_t
oxAssert(destData.size() == dataSize, "Allocation size does not match data."); oxAssert(destData.size() == dataSize, "Allocation size does not match data.");
// write data if any was provided // write data if any was provided
if (data != nullptr) { if (data != nullptr) {
ox_memcpy(destData, data, dest->size()); ox::memcpy(destData, data, dest->size());
oxTrace("ox::fs::FileStoreTemplate::write", "Data written"); oxTrace("ox.fs.FileStoreTemplate.write", "Data written");
} }
auto fsData = fileStoreData(); auto fsData = fileStoreData();
if (fsData) { if (fsData) {
oxTracef("ox::fs::FileStoreTemplate::write", "Searching for root node at {}", fsData->rootNode.get()); oxTracef("ox.fs.FileStoreTemplate.write", "Searching for root node at {}", fsData->rootNode.get());
auto root = m_buffer->ptr(fsData->rootNode); auto root = m_buffer->ptr(fsData->rootNode);
if (root.valid()) { if (root.valid()) {
oxTracef("ox::fs::FileStoreTemplate::write", oxTracef("ox.fs.FileStoreTemplate.write",
"Placing {} on {} at {}", dest->id.get(), root->id.get(), destData.offset()); "Placing {} on {} at {}", dest->id.get(), root->id.get(), destData.offset());
return placeItem(dest); return placeItem(dest);
} else { } else {
oxTracef("ox::fs::FileStoreTemplate::write", oxTracef("ox.fs.FileStoreTemplate.write",
"Initializing root inode: {} (offset: {}, data size: {})", "Initializing root inode: {} (offset: {}, data size: {})",
dest->id.get(), dest.offset(), destData.size()); dest->id.get(), dest.offset(), destData.size());
fsData->rootNode = dest.offset(); fsData->rootNode = dest.offset();
oxTracef("ox::fs::FileStoreTemplate::write", "Root inode: {}", dest->id.get()); oxTracef("ox.fs.FileStoreTemplate.write", "Root inode: {}", dest->id.get());
return OxError(0); return OxError(0);
} }
} else { } else {
oxTrace("ox::fs::FileStoreTemplate::write::fail", "Could not place item due to absence of FileStore header."); oxTrace("ox.fs.FileStoreTemplate.write.fail", "Could not place item due to absence of FileStore header.");
} }
} }
} }
@ -315,28 +315,28 @@ Error FileStoreTemplate<size_t>::remove(uint64_t id) {
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::read(uint64_t id, void *out, FsSize_t outSize, FsSize_t *size) const { Error FileStoreTemplate<size_t>::read(uint64_t id, void *out, FsSize_t outSize, FsSize_t *size) const {
oxTracef("ox::fs::FileStoreTemplate::read", "Attempting to read from inode {}", id); oxTracef("ox.fs.FileStoreTemplate.read", "Attempting to read from inode {}", id);
auto src = find(static_cast<size_t>(id)); auto src = find(static_cast<size_t>(id));
// error check // error check
if (!src.valid()) { if (!src.valid()) {
oxTracef("ox::fs::FileStoreTemplate::read::fail", "Could not find requested item: {}", id); oxTracef("ox.fs.FileStoreTemplate.read.fail", "Could not find requested item: {}", id);
return OxError(1, "Could not find requested item"); return OxError(1, "Could not find requested item");
} }
auto srcData = m_buffer->template dataOf<uint8_t>(src); auto srcData = m_buffer->template dataOf<uint8_t>(src);
oxTracef("ox::fs::FileStoreTemplate::read::found", "{} found at {} with data section at {}", oxTracef("ox.fs.FileStoreTemplate.read.found", "{} found at {} with data section at {}",
id, src.offset(), srcData.offset()); id, src.offset(), srcData.offset());
oxTracef("ox::fs::FileStoreTemplate::read::outSize", "{} {} {}", srcData.offset(), srcData.size(), outSize); oxTracef("ox.fs.FileStoreTemplate.read.outSize", "{} {} {}", srcData.offset(), srcData.size(), outSize);
// error check // error check
if (!(srcData.valid() && srcData.size() <= outSize)) { if (!(srcData.valid() && srcData.size() <= outSize)) {
oxTracef("ox::fs::FileStoreTemplate::read::fail", "Could not read data section of item: {}", id); oxTracef("ox.fs.FileStoreTemplate.read.fail", "Could not read data section of item: {}", id);
oxTracef("ox::fs::FileStoreTemplate::read::fail", oxTracef("ox.fs.FileStoreTemplate.read.fail",
"Item data section size: {}, Expected size: {}", srcData.size(), outSize); "Item data section size: {}, Expected size: {}", srcData.size(), outSize);
return OxError(1); return OxError(1);
} }
ox_memcpy(out, srcData, srcData.size()); ox::memcpy(out, srcData, srcData.size());
if (size) { if (size) {
*size = src.size(); *size = src.size();
} }
@ -346,28 +346,28 @@ Error FileStoreTemplate<size_t>::read(uint64_t id, void *out, FsSize_t outSize,
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::read(uint64_t id, FsSize_t readStart, FsSize_t readSize, void *out, FsSize_t *size) const { Error FileStoreTemplate<size_t>::read(uint64_t id, FsSize_t readStart, FsSize_t readSize, void *out, FsSize_t *size) const {
oxTracef("ox::fs::FileStoreTemplate::read", "Attempting to read from inode {}", id); oxTracef("ox.fs.FileStoreTemplate.read", "Attempting to read from inode {}", id);
auto src = find(static_cast<size_t>(id)); auto src = find(static_cast<size_t>(id));
// error check // error check
if (!src.valid()) { if (!src.valid()) {
oxTracef("ox::fs::FileStoreTemplate::read::fail", "Could not find requested item: {}", id); oxTracef("ox.fs.FileStoreTemplate.read.fail", "Could not find requested item: {}", id);
return OxError(1); return OxError(1);
} }
auto srcData = m_buffer->template dataOf<uint8_t>(src); auto srcData = m_buffer->template dataOf<uint8_t>(src);
oxTracef("ox::fs::FileStoreTemplate::read::found", "{} found at {} with data section at {}", oxTracef("ox.fs.FileStoreTemplate.read.found", "{} found at {} with data section at {}",
id, src.offset(), srcData.offset()); id, src.offset(), srcData.offset());
oxTracef("ox::fs::FileStoreTemplate::read::readSize", "{} {} {}", srcData.offset(), srcData.size(), readSize); oxTracef("ox.fs.FileStoreTemplate.read.readSize", "{} {} {}", srcData.offset(), srcData.size(), readSize);
// error check // error check
if (!(srcData.valid() && srcData.size() - readStart <= readSize)) { if (!(srcData.valid() && srcData.size() - readStart <= readSize)) {
oxTracef("ox::fs::FileStoreTemplate::read::fail", "Could not read data section of item: {}", id); oxTracef("ox.fs.FileStoreTemplate.read.fail", "Could not read data section of item: {}", id);
oxTracef("ox::fs::FileStoreTemplate::read::fail", oxTracef("ox.fs.FileStoreTemplate.read.fail",
"Item data section size: {}, Expected size: {}", srcData.size(), readSize); "Item data section size: {}, Expected size: {}", srcData.size(), readSize);
return OxError(1); return OxError(1);
} }
ox_memcpy(out, srcData.get() + readStart, readSize); ox::memcpy(out, srcData.get() + readStart, readSize);
if (size) { if (size) {
*size = src.size(); *size = src.size();
} }
@ -379,28 +379,28 @@ template<typename size_t>
template<typename T> template<typename T>
Error FileStoreTemplate<size_t>::read(uint64_t id, FsSize_t readStart, Error FileStoreTemplate<size_t>::read(uint64_t id, FsSize_t readStart,
FsSize_t readSize, T *out, FsSize_t *size) const { FsSize_t readSize, T *out, FsSize_t *size) const {
oxTracef("ox::fs::FileStoreTemplate::read", "Attempting to read from inode {}", id); oxTracef("ox.fs.FileStoreTemplate.read", "Attempting to read from inode {}", id);
auto src = find(static_cast<size_t>(id)); auto src = find(static_cast<size_t>(id));
// error check // error check
if (!src.valid()) { if (!src.valid()) {
oxTracef("ox::fs::FileStoreTemplate::read::fail", "Could not find requested item: {}", id); oxTracef("ox.fs.FileStoreTemplate.read.fail", "Could not find requested item: {}", id);
return OxError(1); return OxError(1);
} }
auto srcData = m_buffer->template dataOf<uint8_t>(src); auto srcData = m_buffer->template dataOf<uint8_t>(src);
oxTracef("ox::fs::FileStoreTemplate::read::found", "{} found at {} with data section at {}", oxTracef("ox.fs.FileStoreTemplate.read.found", "{} found at {} with data section at {}",
id, src.offset(), srcData.offset()); id, src.offset(), srcData.offset());
oxTracef("ox::fs::FileStoreTemplate::read::readSize", "{} {} {}", srcData.offset(), srcData.size(), readSize); oxTracef("ox.fs.FileStoreTemplate.read.readSize", "{} {} {}", srcData.offset(), srcData.size(), readSize);
// error check // error check
if (!(srcData.valid() && srcData.size() - readStart <= readSize)) { if (!(srcData.valid() && srcData.size() - readStart <= readSize)) {
oxTracef("ox::fs::FileStoreTemplate::read::fail", "Could not read data section of item: {}", id); oxTracef("ox.fs.FileStoreTemplate.read.fail", "Could not read data section of item: {}", id);
oxTracef("ox::fs::FileStoreTemplate::read::fail", oxTracef("ox.fs.FileStoreTemplate.read.fail",
"Item data section size: {}, Expected size: {}", srcData.size(), readSize); "Item data section size: {}, Expected size: {}", srcData.size(), readSize);
return OxError(1); return OxError(1);
} }
ox_memcpy(out, srcData.get() + readStart, readSize); ox::memcpy(out, srcData.get() + readStart, readSize);
if (size) { if (size) {
*size = src.size(); *size = src.size();
} }
@ -422,9 +422,9 @@ template<typename size_t>
Error FileStoreTemplate<size_t>::resize() { Error FileStoreTemplate<size_t>::resize() {
oxReturnError(compact()); oxReturnError(compact());
const auto newSize = static_cast<std::size_t>(size() - available()); const auto newSize = static_cast<std::size_t>(size() - available());
oxTracef("ox::fs::FileStoreTemplate::resize", "resize to: {}", newSize); oxTracef("ox.fs.FileStoreTemplate.resize", "resize to: {}", newSize);
oxReturnError(m_buffer->setSize(newSize)); oxReturnError(m_buffer->setSize(newSize));
oxTracef("ox::fs::FileStoreTemplate::resize", "resized to: {}", m_buffer->size()); oxTracef("ox.fs.FileStoreTemplate.resize", "resized to: {}", m_buffer->size());
return OxError(0); return OxError(0);
} }
@ -506,7 +506,7 @@ Error FileStoreTemplate<size_t>::compact() {
if (!item.valid()) { if (!item.valid()) {
return OxError(1); return OxError(1);
} }
oxTracef("ox::fs::FileStoreTemplate::compact::moveItem", "Moving Item: {} from {} to {}", item->id.get(), oldAddr, item.offset()); oxTracef("ox.fs.FileStoreTemplate.compact.moveItem", "Moving Item: {} from {} to {}", item->id.get(), oldAddr, item.offset());
// update rootInode if this is it // update rootInode if this is it
auto fsData = fileStoreData(); auto fsData = fileStoreData();
if (fsData && oldAddr == fsData->rootNode) { if (fsData && oldAddr == fsData->rootNode) {
@ -549,7 +549,7 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr item) {
fsData->rootNode = item; fsData->rootNode = item;
item->left = root->left; item->left = root->left;
item->right = root->right; item->right = root->right;
oxTracef("ox::fs::FileStoreTemplate::placeItem", "Overwrote Root Item: {}", item->id.get()); oxTracef("ox.fs.FileStoreTemplate.placeItem", "Overwrote Root Item: {}", item->id.get());
return OxError(0); return OxError(0);
} else { } else {
return placeItem(root, item); return placeItem(root, item);
@ -559,7 +559,7 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr item) {
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::placeItem(ItemPtr root, ItemPtr item, int depth) { Error FileStoreTemplate<size_t>::placeItem(ItemPtr root, ItemPtr item, int depth) {
if (depth > 5000) { if (depth > 5000) {
oxTrace("ox::fs::FileStoreTemplate::placeItem::fail", "Excessive recursion depth, stopping before stack overflow."); oxTrace("ox.fs.FileStoreTemplate.placeItem.fail", "Excessive recursion depth, stopping before stack overflow.");
return OxError(2); return OxError(2);
} }
if (item->id > root->id) { if (item->id > root->id) {
@ -570,7 +570,7 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr root, ItemPtr item, int depth
item->left = right->left; item->left = right->left;
item->right = right->right; item->right = right->right;
} }
oxTracef("ox::fs::FileStoreTemplate::placeItem", "Placed Item: {}", item->id.get()); oxTracef("ox.fs.FileStoreTemplate.placeItem", "Placed Item: {}", item->id.get());
return OxError(0); return OxError(0);
} else { } else {
return placeItem(right, item, depth + 1); return placeItem(right, item, depth + 1);
@ -583,13 +583,13 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr root, ItemPtr item, int depth
item->left = left->left; item->left = left->left;
item->right = left->right; item->right = left->right;
} }
oxTracef("ox::fs::FileStoreTemplate::placeItem", "Placed Item: {}", item->id.get()); oxTracef("ox.fs.FileStoreTemplate.placeItem", "Placed Item: {}", item->id.get());
return OxError(0); return OxError(0);
} else { } else {
return placeItem(left, item, depth + 1); return placeItem(left, item, depth + 1);
} }
} else { } else {
oxTrace("ox::fs::FileStoreTemplate::placeItem::fail", "Cannot insert an item on itself."); oxTrace("ox.fs.FileStoreTemplate.placeItem.fail", "Cannot insert an item on itself.");
return OxError(1, "Cannot insert an item on itself."); return OxError(1, "Cannot insert an item on itself.");
} }
} }
@ -631,14 +631,14 @@ Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr item) {
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr root, ItemPtr item, int depth) { Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr root, ItemPtr item, int depth) {
if (depth >= 5000) { if (depth >= 5000) {
oxTrace("ox::fs::FileStoreTemplate::unplaceItem::fail", "Excessive recursion depth, stopping before stack overflow."); oxTrace("ox.fs.FileStoreTemplate.unplaceItem.fail", "Excessive recursion depth, stopping before stack overflow.");
return OxError(1, "Excessive recursion depth, stopping before stack overflow."); return OxError(1, "Excessive recursion depth, stopping before stack overflow.");
} }
if (item->id > root->id) { if (item->id > root->id) {
auto right = m_buffer->ptr(root->right); auto right = m_buffer->ptr(root->right);
if (right->id == item->id) { if (right->id == item->id) {
root->right = 0; root->right = 0;
oxTracef("ox::fs::FileStoreTemplate::unplaceItem", "Unplaced Item: {}", item->id.get()); oxTracef("ox.fs.FileStoreTemplate.unplaceItem", "Unplaced Item: {}", item->id.get());
} else { } else {
return unplaceItem(right, item, depth + 1); return unplaceItem(right, item, depth + 1);
} }
@ -646,7 +646,7 @@ Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr root, ItemPtr item, int dep
auto left = m_buffer->ptr(root->left); auto left = m_buffer->ptr(root->left);
if (left->id == item->id) { if (left->id == item->id) {
root->left = 0; root->left = 0;
oxTracef("ox::fs::FileStoreTemplate::unplaceItem", "Unplaced Item: {}", item->id.get()); oxTracef("ox.fs.FileStoreTemplate.unplaceItem", "Unplaced Item: {}", item->id.get());
} else { } else {
return unplaceItem(left, item, depth + 1); return unplaceItem(left, item, depth + 1);
} }
@ -701,22 +701,22 @@ typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::findParen
template<typename size_t> template<typename size_t>
typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::find(ItemPtr item, InodeId_t id, int depth) const { typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::find(ItemPtr item, InodeId_t id, int depth) const {
if (depth > 5000) { if (depth > 5000) {
oxTracef("ox::fs::FileStoreTemplate::find::fail", "Excessive recursion depth, stopping before stack overflow. Search for: {}", id); oxTracef("ox.fs.FileStoreTemplate.find.fail", "Excessive recursion depth, stopping before stack overflow. Search for: {}", id);
return nullptr; return nullptr;
} }
if (!item.valid()) { if (!item.valid()) {
oxTrace("ox::fs::FileStoreTemplate::find::fail", "item invalid"); oxTrace("ox.fs.FileStoreTemplate.find.fail", "item invalid");
return nullptr; return nullptr;
} }
// do search // do search
if (id > item->id) { if (id > item->id) {
oxTracef("ox::fs::FileStoreTemplate::find", "Not a match, searching on {}", item->right.get()); oxTracef("ox.fs.FileStoreTemplate.find", "Not a match, searching on {}", item->right.get());
return find(m_buffer->ptr(item->right), id, depth + 1); return find(m_buffer->ptr(item->right), id, depth + 1);
} else if (id < item->id) { } else if (id < item->id) {
oxTracef("ox::fs::FileStoreTemplate::find", "Not a match, searching on {}", item->left.get()); oxTracef("ox.fs.FileStoreTemplate.find", "Not a match, searching on {}", item->left.get());
return find(m_buffer->ptr(item->left), id, depth + 1); return find(m_buffer->ptr(item->left), id, depth + 1);
} else if (id == item->id) { } else if (id == item->id) {
oxTracef("ox::fs::FileStoreTemplate::find", "Found {} at {}", id, item.offset()); oxTracef("ox.fs.FileStoreTemplate.find", "Found {} at {}", id, item.offset());
return item; return item;
} }
return nullptr; return nullptr;
@ -724,7 +724,7 @@ typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::find(Item
template<typename size_t> template<typename size_t>
typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::find(InodeId_t id) const { typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::find(InodeId_t id) const {
oxTracef("ox::fs::FileStoreTemplate::find", "Searching for inode: {}", id); oxTracef("ox.fs.FileStoreTemplate.find", "Searching for inode: {}", id);
auto fsData = fileStoreData(); auto fsData = fileStoreData();
if (fsData) { if (fsData) {
auto root = m_buffer->ptr(fsData->rootNode); auto root = m_buffer->ptr(fsData->rootNode);
@ -732,10 +732,10 @@ typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::find(Inod
auto item = find(root, id); auto item = find(root, id);
return item; return item;
} else { } else {
oxTrace("ox::fs::FileStoreTemplate::find::fail", "No root node"); oxTrace("ox.fs.FileStoreTemplate.find.fail", "No root node");
} }
} else { } else {
oxTrace("ox::fs::FileStoreTemplate::find::fail", "No FileStore Data"); oxTrace("ox.fs.FileStoreTemplate.find.fail", "No FileStore Data");
} }
return nullptr; return nullptr;
} }

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include "directory.hpp" #include "directory.hpp"

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -48,14 +48,14 @@ struct OX_PACKED DirectoryEntry {
auto d = data(); auto d = data();
if (d.valid()) { if (d.valid()) {
d->inode = inode; d->inode = inode;
ox_strncpy(d->name, name, ox::min(bufferSize, static_cast<InodeId_t>(MaxFileNameLength))); ox::strncpy(d->name, name, ox::min(bufferSize, static_cast<InodeId_t>(MaxFileNameLength)));
return OxError(0); return OxError(0);
} }
return OxError(1); return OxError(1);
} }
ptrarith::Ptr<DirectoryEntryData, InodeId_t> data() noexcept { ptrarith::Ptr<DirectoryEntryData, InodeId_t> data() noexcept {
oxTracef("ox::fs::DirectoryEntry::data", "{} {} {}", this->fullSize(), sizeof(*this), this->size()); oxTracef("ox.fs.DirectoryEntry.data", "{} {} {}", this->fullSize(), sizeof(*this), this->size());
return ptrarith::Ptr<DirectoryEntryData, InodeId_t>(this, this->fullSize(), sizeof(*this), this->size(), this->size()); return ptrarith::Ptr<DirectoryEntryData, InodeId_t>(this, this->fullSize(), sizeof(*this), this->size(), this->size());
} }
@ -136,7 +136,7 @@ Directory<FileStore, InodeId_t>::Directory(FileStore fs, uint64_t inodeId) noexc
template<typename FileStore, typename InodeId_t> template<typename FileStore, typename InodeId_t>
Error Directory<FileStore, InodeId_t>::init() noexcept { Error Directory<FileStore, InodeId_t>::init() noexcept {
constexpr auto Size = sizeof(Buffer); constexpr auto Size = sizeof(Buffer);
oxTracef("ox::fs::Directory::init", "Initializing Directory with Inode ID: {}", m_inodeId); oxTracef("ox.fs.Directory.init", "Initializing Directory with Inode ID: {}", m_inodeId);
oxReturnError(m_fs.write(m_inodeId, nullptr, Size, static_cast<uint8_t>(FileType::Directory))); oxReturnError(m_fs.write(m_inodeId, nullptr, Size, static_cast<uint8_t>(FileType::Directory)));
auto buff = m_fs.read(m_inodeId).template to<Buffer>(); auto buff = m_fs.read(m_inodeId).template to<Buffer>();
if (!buff.valid()) { if (!buff.valid()) {
@ -151,7 +151,7 @@ Error Directory<FileStore, InodeId_t>::init() noexcept {
template<typename FileStore, typename InodeId_t> template<typename FileStore, typename InodeId_t>
Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, FileName *nameBuff) { Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, FileName *nameBuff) {
if (path.valid()) { if (path.valid()) {
oxTrace("ox::fs::Directory::mkdir", path.fullPath()); oxTrace("ox.fs.Directory.mkdir", path.fullPath());
// reuse nameBuff if it has already been allocated, as it is a rather large variable // reuse nameBuff if it has already been allocated, as it is a rather large variable
if (nameBuff == nullptr) { if (nameBuff == nullptr) {
nameBuff = new (ox_alloca(sizeof(FileName))) FileName; nameBuff = new (ox_alloca(sizeof(FileName))) FileName;
@ -159,7 +159,7 @@ Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, Fi
// determine if already exists // determine if already exists
auto name = nameBuff; auto name = nameBuff;
oxReturnError(path.get(name)); oxReturnError(path.get(*name));
auto childInode = find(PathIterator(*name)); auto childInode = find(PathIterator(*name));
if (!childInode.ok()) { if (!childInode.ok()) {
// if this is not the last item in the path and parents is disabled, // if this is not the last item in the path and parents is disabled,
@ -168,7 +168,7 @@ Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, Fi
return OxError(1); return OxError(1);
} }
childInode = m_fs.generateInodeId(); childInode = m_fs.generateInodeId();
oxTracef("ox::fs::Directory::mkdir", "Generated Inode ID: {}", childInode.value); oxTracef("ox.fs.Directory.mkdir", "Generated Inode ID: {}", childInode.value);
oxLogError(childInode.error); oxLogError(childInode.error);
oxReturnError(childInode.error); oxReturnError(childInode.error);
@ -203,34 +203,34 @@ Error Directory<FileStore, InodeId_t>::write(PathIterator path, uint64_t inode64
auto name = nameBuff; auto name = nameBuff;
if (path.next().hasNext()) { // not yet at target directory, recurse to next one if (path.next().hasNext()) { // not yet at target directory, recurse to next one
oxReturnError(path.get(name)); oxReturnError(path.get(*name));
oxTracef("ox::fs::Directory::write", "Attempting to write to next sub-Directory: {} of {}", oxTracef("ox.fs.Directory.write", "Attempting to write to next sub-Directory: {} of {}",
*name, path.fullPath()); *name, path.fullPath());
oxRequire(nextChild, findEntry(*name)); oxRequire(nextChild, findEntry(*name));
oxTracef("ox::fs::Directory::write", "{}: {}", *name, nextChild); oxTracef("ox.fs.Directory.write", "{}: {}", *name, nextChild);
if (nextChild) { if (nextChild) {
// reuse name because it is a rather large variable and will not be used again // reuse name because it is a rather large variable and will not be used again
// be attentive that this remains true // be attentive that this remains true
name = nullptr; name = nullptr;
return Directory(m_fs, nextChild).write(path.next(), inode, nameBuff); return Directory(m_fs, nextChild).write(path.next(), inode, nameBuff);
} else { } else {
oxTracef("ox::fs::Directory::write", "{} not found and not allowed to create it.", *name); oxTracef("ox.fs.Directory.write", "{} not found and not allowed to create it.", *name);
return OxError(1, "File not found and not allowed to create it."); return OxError(1, "File not found and not allowed to create it.");
} }
} else { } else {
oxTrace("ox::fs::Directory::write", path.fullPath()); oxTrace("ox.fs.Directory.write", path.fullPath());
// insert the new entry on this directory // insert the new entry on this directory
// get the name // get the name
oxReturnError(path.next(name)); oxReturnError(path.next(*name));
// find existing version of directory // find existing version of directory
oxTracef("ox::fs::Directory::write", "Searching for directory inode {}", m_inodeId); oxTracef("ox.fs.Directory.write", "Searching for directory inode {}", m_inodeId);
oxRequire(oldStat, m_fs.stat(m_inodeId)); oxRequire(oldStat, m_fs.stat(m_inodeId));
oxTracef("ox::fs::Directory::write", "Found existing directory of size {}", oldStat.size); oxTracef("ox.fs.Directory.write", "Found existing directory of size {}", oldStat.size);
auto old = m_fs.read(m_inodeId).template to<Buffer>(); auto old = m_fs.read(m_inodeId).template to<Buffer>();
if (!old.valid()) { if (!old.valid()) {
oxTrace("ox::fs::Directory::write::fail", "Could not read existing version of Directory"); oxTrace("ox.fs.Directory.write.fail", "Could not read existing version of Directory");
return OxError(1, "Could not read existing version of Directory"); return OxError(1, "Could not read existing version of Directory");
} }
@ -239,20 +239,20 @@ Error Directory<FileStore, InodeId_t>::write(PathIterator path, uint64_t inode64
const auto newSize = oldStat.size + Buffer::spaceNeeded(entryDataSize); const auto newSize = oldStat.size + Buffer::spaceNeeded(entryDataSize);
auto cpy = ox_malloca(newSize, Buffer, *old, oldStat.size); auto cpy = ox_malloca(newSize, Buffer, *old, oldStat.size);
if (cpy == nullptr) { if (cpy == nullptr) {
oxTrace("ox::fs::Directory::write::fail", "Could not allocate memory for copy of Directory"); oxTrace("ox.fs.Directory.write.fail", "Could not allocate memory for copy of Directory");
return OxError(1, "Could not allocate memory for copy of Directory"); return OxError(1, "Could not allocate memory for copy of Directory");
} }
oxReturnError(cpy->setSize(newSize)); oxReturnError(cpy->setSize(newSize));
auto val = cpy->malloc(entryDataSize).value; auto val = cpy->malloc(entryDataSize).value;
if (!val.valid()) { if (!val.valid()) {
oxTrace("ox::fs::Directory::write::fail", "Could not allocate memory for new directory entry"); oxTrace("ox.fs.Directory.write.fail", "Could not allocate memory for new directory entry");
return OxError(1, "Could not allocate memory for new directory entry"); return OxError(1, "Could not allocate memory for new directory entry");
} }
oxTracef("ox::fs::Directory::write", "Attempting to write Directory entry: {}", name->data()); oxTracef("ox.fs.Directory.write", "Attempting to write Directory entry: {}", name->data());
oxReturnError(val->init(inode, name->data(), val.size())); oxReturnError(val->init(inode, name->data(), val.size()));
return m_fs.write(m_inodeId, cpy, cpy->size(), static_cast<uint8_t>(FileType::Directory)); return m_fs.write(m_inodeId, cpy.get(), cpy->size(), static_cast<uint8_t>(FileType::Directory));
} }
} }
@ -263,12 +263,12 @@ Error Directory<FileStore, InodeId_t>::remove(PathIterator path, FileName *nameB
nameBuff = new (ox_alloca(sizeof(FileName))) FileName; nameBuff = new (ox_alloca(sizeof(FileName))) FileName;
} }
auto &name = *nameBuff; auto &name = *nameBuff;
oxReturnError(path.get(&name)); oxReturnError(path.get(name));
oxTrace("ox::fs::Directory::remove", name); oxTrace("ox.fs.Directory.remove", name);
auto buff = m_fs.read(m_inodeId).template to<Buffer>(); auto buff = m_fs.read(m_inodeId).template to<Buffer>();
if (buff.valid()) { if (buff.valid()) {
oxTrace("ox::fs::Directory::remove", "Found directory buffer."); oxTrace("ox.fs.Directory.remove", "Found directory buffer.");
for (auto i = buff->iterator(); i.valid(); i.next()) { for (auto i = buff->iterator(); i.valid(); i.next()) {
auto data = i->data(); auto data = i->data();
if (data.valid()) { if (data.valid()) {
@ -276,11 +276,11 @@ Error Directory<FileStore, InodeId_t>::remove(PathIterator path, FileName *nameB
oxReturnError(buff->free(i)); oxReturnError(buff->free(i));
} }
} else { } else {
oxTrace("ox::fs::Directory::remove", "INVALID DIRECTORY ENTRY"); oxTrace("ox.fs.Directory.remove", "INVALID DIRECTORY ENTRY");
} }
} }
} else { } else {
oxTrace("ox::fs::Directory::remove::fail", "Could not find directory buffer"); oxTrace("ox.fs.Directory.remove.fail", "Could not find directory buffer");
return OxError(1, "Could not find directory buffer"); return OxError(1, "Could not find directory buffer");
} }
return OxError(0); return OxError(0);
@ -289,20 +289,20 @@ Error Directory<FileStore, InodeId_t>::remove(PathIterator path, FileName *nameB
template<typename FileStore, typename InodeId_t> template<typename FileStore, typename InodeId_t>
template<typename F> template<typename F>
Error Directory<FileStore, InodeId_t>::ls(F cb) noexcept { Error Directory<FileStore, InodeId_t>::ls(F cb) noexcept {
oxTrace("ox::fs::Directory::ls"); oxTrace("ox.fs.Directory.ls");
auto buff = m_fs.read(m_inodeId).template to<Buffer>(); auto buff = m_fs.read(m_inodeId).template to<Buffer>();
if (!buff.valid()) { if (!buff.valid()) {
oxTrace("ox::fs::Directory::ls::fail", "Could not directory buffer"); oxTrace("ox.fs.Directory.ls.fail", "Could not directory buffer");
return OxError(1, "Could not directory buffer"); return OxError(1, "Could not directory buffer");
} }
oxTrace("ox::fs::Directory::ls", "Found directory buffer."); oxTrace("ox.fs.Directory.ls", "Found directory buffer.");
for (auto i = buff->iterator(); i.valid(); i.next()) { for (auto i = buff->iterator(); i.valid(); i.next()) {
auto data = i->data(); auto data = i->data();
if (data.valid()) { if (data.valid()) {
oxReturnError(cb(data->name, data->inode)); oxReturnError(cb(data->name, data->inode));
} else { } else {
oxTrace("ox::fs::Directory::ls", "INVALID DIRECTORY ENTRY"); oxTrace("ox.fs.Directory.ls", "INVALID DIRECTORY ENTRY");
} }
} }
@ -311,26 +311,26 @@ Error Directory<FileStore, InodeId_t>::ls(F cb) noexcept {
template<typename FileStore, typename InodeId_t> template<typename FileStore, typename InodeId_t>
Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::findEntry(const FileName &name) const noexcept { Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::findEntry(const FileName &name) const noexcept {
oxTrace("ox::fs::Directory::findEntry", name); oxTrace("ox.fs.Directory.findEntry", name);
auto buff = m_fs.read(m_inodeId).template to<Buffer>(); auto buff = m_fs.read(m_inodeId).template to<Buffer>();
if (!buff.valid()) { if (!buff.valid()) {
oxTrace("ox::fs::Directory::findEntry::fail", "Could not findEntry directory buffer"); oxTrace("ox.fs.Directory.findEntry.fail", "Could not findEntry directory buffer");
return OxError(2, "Could not findEntry directory buffer"); return OxError(2, "Could not findEntry directory buffer");
} }
oxTracef("ox::fs::Directory::findEntry", "Found directory buffer, size: {}", buff.size()); oxTracef("ox.fs.Directory.findEntry", "Found directory buffer, size: {}", buff.size());
for (auto i = buff->iterator(); i.valid(); i.next()) { for (auto i = buff->iterator(); i.valid(); i.next()) {
auto data = i->data(); auto data = i->data();
if (data.valid()) { if (data.valid()) {
oxTracef("ox::fs::Directory::findEntry", "Comparing \"{}\" to \"{}\"", name, data->name); oxTracef("ox.fs.Directory.findEntry", "Comparing \"{}\" to \"{}\"", name, data->name);
if (name == data->name) { if (name == data->name) {
oxTracef("ox::fs::Directory::findEntry", "\"{}\" match found.", name); oxTracef("ox.fs.Directory.findEntry", "\"{}\" match found.", name);
return static_cast<InodeId_t>(data->inode); return static_cast<InodeId_t>(data->inode);
} }
} else { } else {
oxTrace("ox::fs::Directory::findEntry") << "INVALID DIRECTORY ENTRY"; oxTrace("ox.fs.Directory.findEntry") << "INVALID DIRECTORY ENTRY";
} }
} }
oxTrace("ox::fs::Directory::findEntry::fail", "Entry not present"); oxTrace("ox.fs.Directory.findEntry.fail", "Entry not present");
return OxError(1, "Entry not present"); return OxError(1, "Entry not present");
} }
@ -343,7 +343,7 @@ Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::find(Path
// determine if already exists // determine if already exists
auto name = nameBuff; auto name = nameBuff;
oxReturnError(path.get(name)); oxReturnError(path.get(*name));
oxRequire(v, findEntry(*name)); oxRequire(v, findEntry(*name));
// recurse if not at end of path // recurse if not at end of path

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include <ox/model/modelops.hpp> #include <ox/model/modelops.hpp>
@ -36,13 +36,6 @@ FileAddress::FileAddress(ox::CRStringView path) noexcept {
m_type = FileAddressType::Path; m_type = FileAddressType::Path;
} }
FileAddress::FileAddress(char *path) noexcept {
auto pathSize = ox_strlen(path) + 1;
m_data.path = new char[pathSize];
memcpy(m_data.path, path, pathSize);
m_type = FileAddressType::Path;
}
FileAddress &FileAddress::operator=(const FileAddress &other) noexcept { FileAddress &FileAddress::operator=(const FileAddress &other) noexcept {
if (this == &other) { if (this == &other) {
return *this; return *this;
@ -52,9 +45,14 @@ FileAddress &FileAddress::operator=(const FileAddress &other) noexcept {
switch (m_type) { switch (m_type) {
case FileAddressType::Path: case FileAddressType::Path:
{ {
auto strSize = ox_strlen(other.m_data.path) + 1; if (other.m_data.path) {
auto strSize = ox::strlen(other.m_data.path) + 1;
m_data.path = new char[strSize]; m_data.path = new char[strSize];
ox_memcpy(m_data.path, other.m_data.path, strSize); ox::memcpy(m_data.path, other.m_data.path, strSize);
} else {
m_data.constPath = "";
m_type = FileAddressType::ConstPath;
}
break; break;
} }
case FileAddressType::ConstPath: case FileAddressType::ConstPath:
@ -90,6 +88,32 @@ FileAddress &FileAddress::operator=(FileAddress &&other) noexcept {
return *this; return *this;
} }
bool FileAddress::operator==(FileAddress const&other) const noexcept {
if (m_type != other.m_type) {
auto const aIsPath =
m_type == FileAddressType::Path || m_type == FileAddressType::ConstPath;
auto const bIsPath =
other.m_type == FileAddressType::Path || other.m_type == FileAddressType::ConstPath;
if (!(aIsPath && bIsPath)) {
return false;
}
}
switch (m_type) {
case FileAddressType::ConstPath:
case FileAddressType::Path: {
auto const a = getPath();
auto const b = other.getPath();
return (other.m_type == FileAddressType::ConstPath || other.m_type == FileAddressType::Path)
&& (a.value == b.value);
}
case FileAddressType::Inode:
return m_data.inode == other.m_data.inode;
case FileAddressType::None:
return true;
}
return true;
}
bool FileAddress::operator==(CRStringView path) const noexcept { bool FileAddress::operator==(CRStringView path) const noexcept {
auto [p, err] = getPath(); auto [p, err] = getPath();
if (err) { if (err) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -22,10 +22,13 @@ enum class FileAddressType: int8_t {
Inode, Inode,
}; };
template<typename T>
constexpr Error model(T *h, CommonPtrWith<class FileAddress> auto *fa) noexcept;
class FileAddress { class FileAddress {
template<typename T> template<typename T>
friend constexpr Error model(T*, CommonPtrWith<FileAddress> auto*) noexcept; friend constexpr Error model(T *h, CommonPtrWith<FileAddress> auto *fa) noexcept;
public: public:
static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress"; static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress";
@ -41,13 +44,10 @@ class FileAddress {
protected: protected:
FileAddressType m_type = FileAddressType::None; FileAddressType m_type = FileAddressType::None;
Data m_data; Data m_data{};
public: public:
constexpr FileAddress() noexcept { constexpr FileAddress() noexcept = default;
m_data.inode = 0;
m_type = FileAddressType::None;
}
FileAddress(const FileAddress &other) noexcept; FileAddress(const FileAddress &other) noexcept;
@ -59,13 +59,7 @@ class FileAddress {
explicit FileAddress(CRStringView path) noexcept; explicit FileAddress(CRStringView path) noexcept;
template<std::size_t SmallStrSz> constexpr FileAddress(ox::StringLiteral path) noexcept;
explicit FileAddress(const ox::BasicString<SmallStrSz> &path) noexcept: FileAddress(StringView(path)) {
}
explicit FileAddress(char *path) noexcept;
explicit constexpr FileAddress(const char *path) noexcept;
constexpr ~FileAddress() noexcept; constexpr ~FileAddress() noexcept;
@ -73,6 +67,8 @@ class FileAddress {
FileAddress &operator=(FileAddress &&other) noexcept; FileAddress &operator=(FileAddress &&other) noexcept;
bool operator==(const FileAddress &other) const noexcept;
bool operator==(CRStringView path) const noexcept; bool operator==(CRStringView path) const noexcept;
[[nodiscard]] [[nodiscard]]
@ -86,7 +82,6 @@ class FileAddress {
} }
} }
[[nodiscard]]
constexpr Result<uint64_t> getInode() const noexcept { constexpr Result<uint64_t> getInode() const noexcept {
switch (m_type) { switch (m_type) {
case FileAddressType::Inode: case FileAddressType::Inode:
@ -96,12 +91,12 @@ class FileAddress {
} }
} }
constexpr Result<const char*> getPath() const noexcept { constexpr Result<ox::CStringView> getPath() const noexcept {
switch (m_type) { switch (m_type) {
case FileAddressType::Path: case FileAddressType::Path:
return m_data.path; return ox::CStringView(m_data.path);
case FileAddressType::ConstPath: case FileAddressType::ConstPath:
return m_data.constPath; return ox::CStringView(m_data.constPath);
default: default:
return OxError(1); return OxError(1);
} }
@ -124,8 +119,8 @@ class FileAddress {
}; };
constexpr FileAddress::FileAddress(const char *path) noexcept { constexpr FileAddress::FileAddress(ox::StringLiteral path) noexcept {
m_data.constPath = path; m_data.constPath = path.c_str();
m_type = FileAddressType::ConstPath; m_type = FileAddressType::ConstPath;
} }
@ -133,45 +128,6 @@ constexpr FileAddress::~FileAddress() noexcept {
cleanup(); cleanup();
} }
template<>
constexpr const char *getModelTypeName<FileAddress::Data>() noexcept {
return FileAddress::Data::TypeName;
}
template<>
constexpr const char *getModelTypeName<FileAddress>() noexcept {
return FileAddress::TypeName;
}
template<typename T>
constexpr Error model(T *io, CommonPtrWith<FileAddress::Data> auto *obj) noexcept {
oxReturnError(io->template setTypeInfo<FileAddress::Data>());
oxReturnError(io->fieldCString("path", &obj->path));
oxReturnError(io->fieldCString("constPath", &obj->path));
oxReturnError(io->field("inode", &obj->inode));
return OxError(0);
}
template<typename T>
constexpr Error model(T *io, CommonPtrWith<FileAddress> auto *fa) noexcept {
oxReturnError(io->template setTypeInfo<FileAddress>());
if constexpr(T::opType() == OpType::Reflect) {
int8_t type = 0;
oxReturnError(io->field("type", &type));
oxReturnError(io->field("data", UnionView(&fa->m_data, 0)));
} else if constexpr(T::opType() == OpType::Read) {
auto type = static_cast<int8_t>(fa->m_type);
oxReturnError(io->field("type", &type));
fa->m_type = static_cast<FileAddressType>(type);
oxReturnError(io->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
} else if constexpr(T::opType() == OpType::Write) {
auto type = static_cast<int8_t>(fa->m_type);
oxReturnError(io->field("type", &type));
oxReturnError(io->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
}
return OxError(0);
}
constexpr void FileAddress::cleanup() noexcept { constexpr void FileAddress::cleanup() noexcept {
if (m_type == FileAddressType::Path) { if (m_type == FileAddressType::Path) {
safeDeleteArray(m_data.path); safeDeleteArray(m_data.path);
@ -184,4 +140,43 @@ constexpr void FileAddress::clear() noexcept {
m_type = FileAddressType::None; m_type = FileAddressType::None;
} }
template<>
constexpr const char *getModelTypeName<FileAddress::Data>() noexcept {
return FileAddress::Data::TypeName;
}
template<>
constexpr const char *getModelTypeName<FileAddress>() noexcept {
return FileAddress::TypeName;
}
template<typename T>
constexpr Error model(T *h, CommonPtrWith<FileAddress::Data> auto *obj) noexcept {
oxReturnError(h->template setTypeInfo<FileAddress::Data>());
oxReturnError(h->fieldCString("path", &obj->path));
oxReturnError(h->fieldCString("constPath", &obj->path));
oxReturnError(h->field("inode", &obj->inode));
return {};
}
template<typename T>
constexpr Error model(T *h, CommonPtrWith<FileAddress> auto *fa) noexcept {
oxReturnError(h->template setTypeInfo<FileAddress>());
if constexpr(T::opType() == OpType::Reflect) {
int8_t type = -1;
oxReturnError(h->field("type", &type));
oxReturnError(h->field("data", UnionView(&fa->m_data, type)));
} else if constexpr(T::opType() == OpType::Read) {
auto type = static_cast<int8_t>(fa->m_type);
oxReturnError(h->field("type", &type));
fa->m_type = static_cast<FileAddressType>(type);
oxReturnError(h->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
} else if constexpr(T::opType() == OpType::Write) {
auto const type = static_cast<int8_t>(fa->m_type);
oxReturnError(h->field("type", &type));
oxReturnError(h->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
}
return {};
}
} }

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include <ox/std/error.hpp> #include <ox/std/error.hpp>

View File

@ -1,14 +1,15 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
#include <ox/std/buffer.hpp> #include <ox/std/buffer.hpp>
#include <ox/std/span.hpp>
#include <ox/fs/filestore/filestoretemplate.hpp> #include <ox/fs/filestore/filestoretemplate.hpp>
#include <ox/fs/filesystem/filelocation.hpp> #include <ox/fs/filesystem/filelocation.hpp>
@ -66,10 +67,18 @@ class FileSystem {
return writeFilePath(path, buffer, size, FileType::NormalFile); return writeFilePath(path, buffer, size, FileType::NormalFile);
} }
Error write(CRStringView path, ox::Span<char> const&buff) noexcept {
return write(path, buff.data(), buff.size(), FileType::NormalFile);
}
Error write(uint64_t inode, const void *buffer, uint64_t size) noexcept { Error write(uint64_t inode, const void *buffer, uint64_t size) noexcept {
return write(inode, buffer, size, FileType::NormalFile); return write(inode, buffer, size, FileType::NormalFile);
} }
Error write(uint64_t inode, ox::Span<char> const&buff) noexcept {
return write(inode, buff.data(), buff.size(), FileType::NormalFile);
}
Error write(const FileAddress &addr, const void *buffer, uint64_t size, FileType fileType = FileType::NormalFile) noexcept; Error write(const FileAddress &addr, const void *buffer, uint64_t size, FileType fileType = FileType::NormalFile) noexcept;
inline Error write(CRStringView path, const void *buffer, uint64_t size, FileType fileType) noexcept { inline Error write(CRStringView path, const void *buffer, uint64_t size, FileType fileType) noexcept {
@ -165,6 +174,8 @@ class FileSystemTemplate: public MemFS {
FileSystemTemplate(void *buffer, uint64_t bufferSize, void(*freeBuffer)(char*) = detail::fsBuffFree) noexcept; FileSystemTemplate(void *buffer, uint64_t bufferSize, void(*freeBuffer)(char*) = detail::fsBuffFree) noexcept;
explicit FileSystemTemplate(ox::Buffer &buffer) noexcept;
explicit FileSystemTemplate(FileStore fs) noexcept; explicit FileSystemTemplate(FileStore fs) noexcept;
~FileSystemTemplate() noexcept override; ~FileSystemTemplate() noexcept override;
@ -238,6 +249,11 @@ FileSystemTemplate<FileStore, Directory>::FileSystemTemplate(FileStore fs) noexc
m_fs = fs; m_fs = fs;
} }
template<typename FileStore, typename Directory>
FileSystemTemplate<FileStore, Directory>::FileSystemTemplate(ox::Buffer &buffer) noexcept:
m_fs(buffer.data(), static_cast<std::size_t>(buffer.size())) {
}
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
FileSystemTemplate<FileStore, Directory>::FileSystemTemplate(void *buffer, uint64_t bufferSize, void(*freeBuffer)(char*)) noexcept: FileSystemTemplate<FileStore, Directory>::FileSystemTemplate(void *buffer, uint64_t bufferSize, void(*freeBuffer)(char*)) noexcept:
m_fs(buffer, static_cast<std::size_t>(bufferSize)), m_fs(buffer, static_cast<std::size_t>(bufferSize)),
@ -262,11 +278,11 @@ Error FileSystemTemplate<FileStore, Directory>::format(void *buff, uint64_t buff
FileSystemData fd; FileSystemData fd;
fd.rootDirInode = rootDirInode; fd.rootDirInode = rootDirInode;
oxTracef("ox::fs::FileSystemTemplate::format", "rootDirInode: {}", fd.rootDirInode.get()); oxTracef("ox.fs.FileSystemTemplate.format", "rootDirInode: {}", fd.rootDirInode.get());
oxReturnError(fs.write(InodeFsData, &fd, sizeof(fd))); oxReturnError(fs.write(InodeFsData, &fd, sizeof(fd)));
if (!fs.read(fd.rootDirInode).valid()) { if (!fs.read(fd.rootDirInode).valid()) {
oxTrace("ox::fs::FileSystemTemplate::format::error", "FileSystemTemplate::format did not correctly create root directory"); oxTrace("ox.fs.FileSystemTemplate.format.error", "FileSystemTemplate::format did not correctly create root directory");
return OxError(1); return OxError(1);
} }
@ -275,7 +291,7 @@ Error FileSystemTemplate<FileStore, Directory>::format(void *buff, uint64_t buff
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::mkdir(CRStringView path, bool recursive) noexcept { Error FileSystemTemplate<FileStore, Directory>::mkdir(CRStringView path, bool recursive) noexcept {
oxTracef("ox::fs::FileSystemTemplate::mkdir", "path: {}, recursive: {}", path, recursive); oxTracef("ox.fs.FileSystemTemplate.mkdir", "path: {}, recursive: {}", path, recursive);
oxRequireM(rootDir, this->rootDir()); oxRequireM(rootDir, this->rootDir());
return rootDir.mkdir(path, recursive); return rootDir.mkdir(path, recursive);
} }
@ -345,7 +361,7 @@ Result<Vector<String>> FileSystemTemplate<FileStore, Directory>::ls(CRStringView
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
template<typename F> template<typename F>
Error FileSystemTemplate<FileStore, Directory>::ls(CRStringView path, F cb) const { Error FileSystemTemplate<FileStore, Directory>::ls(CRStringView path, F cb) const {
oxTracef("ox::fs::FileSystemTemplate::ls", "path: {}", path); oxTracef("ox.fs.FileSystemTemplate.ls", "path: {}", path);
oxRequire(s, stat(path)); oxRequire(s, stat(path));
Directory dir(m_fs, s.inode); Directory dir(m_fs, s.inode);
return dir.ls(cb); return dir.ls(cb);
@ -364,7 +380,7 @@ Error FileSystemTemplate<FileStore, Directory>::remove(CRStringView path, bool r
return err; return err;
} }
} else { } else {
oxTrace("FileSystemTemplate::remove::fail", "Tried to remove directory without recursive setting."); oxTrace("FileSystemTemplate.remove.fail", "Tried to remove directory without recursive setting.");
return OxError(1); return OxError(1);
} }
return OxError(0); return OxError(0);

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include <ox/std/error.hpp> #include <ox/std/error.hpp>
@ -24,14 +24,14 @@ PassThroughFS::PassThroughFS(CRStringView dirPath) {
PassThroughFS::~PassThroughFS() noexcept = default; PassThroughFS::~PassThroughFS() noexcept = default;
String PassThroughFS::basePath() const noexcept { String PassThroughFS::basePath() const noexcept {
return m_path.string().c_str(); return ox::String(m_path.string().c_str());
} }
Error PassThroughFS::mkdir(CRStringView path, bool recursive) noexcept { Error PassThroughFS::mkdir(CRStringView path, bool recursive) noexcept {
bool success = false; bool success = false;
const auto p = m_path / stripSlash(path); const auto p = m_path / stripSlash(path);
const auto u8p = p.u8string(); const auto u8p = p.u8string();
oxTrace("ox::fs::PassThroughFS::mkdir", std::bit_cast<const char*>(u8p.c_str())); oxTrace("ox.fs.PassThroughFS.mkdir", std::bit_cast<const char*>(u8p.c_str()));
if (recursive) { if (recursive) {
std::error_code ec; std::error_code ec;
const auto isDir = std::filesystem::is_directory(p, ec); const auto isDir = std::filesystem::is_directory(p, ec);
@ -98,10 +98,10 @@ Result<FileStat> PassThroughFS::statPath(CRStringView path) const noexcept {
const auto p = m_path / stripSlash(path); const auto p = m_path / stripSlash(path);
const FileType type = std::filesystem::is_directory(p, ec) ? const FileType type = std::filesystem::is_directory(p, ec) ?
FileType::Directory : FileType::NormalFile; FileType::Directory : FileType::NormalFile;
oxTracef("ox::fs::PassThroughFS::statInode", "{} {}", ec.message(), path); oxTracef("ox.fs.PassThroughFS.statInode", "{} {}", ec.message(), path);
const uint64_t size = type == FileType::Directory ? 0 : std::filesystem::file_size(p, ec); const uint64_t size = type == FileType::Directory ? 0 : std::filesystem::file_size(p, ec);
oxTracef("ox::fs::PassThroughFS::statInode", "{} {}", ec.message(), path); oxTracef("ox.fs.PassThroughFS.statInode", "{} {}", ec.message(), path);
oxTracef("ox::fs::PassThroughFS::statInode::size", "{} {}", path, size); oxTracef("ox.fs.PassThroughFS.statInode.size", "{} {}", path, size);
oxReturnError(OxError(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: stat failed")); oxReturnError(OxError(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: stat failed"));
return FileStat{0, 0, size, type}; return FileStat{0, 0, size, type};
} }
@ -147,12 +147,12 @@ Error PassThroughFS::readFilePath(CRStringView path, void *buffer, std::size_t b
const std::size_t size = static_cast<std::size_t>(file.tellg()); const std::size_t size = static_cast<std::size_t>(file.tellg());
file.seekg(0, std::ios::beg); file.seekg(0, std::ios::beg);
if (size > buffSize) { if (size > buffSize) {
oxTracef("ox::fs::PassThroughFS::read::error", "Read failed: Buffer too small: {}", path); oxTracef("ox.fs.PassThroughFS.read.error", "Read failed: Buffer too small: {}", path);
return OxError(1); return OxError(1);
} }
file.read(static_cast<char*>(buffer), static_cast<std::streamsize>(buffSize)); file.read(static_cast<char*>(buffer), static_cast<std::streamsize>(buffSize));
} catch (const std::fstream::failure &f) { } catch (const std::fstream::failure &f) {
oxTracef("ox::fs::PassThroughFS::read::error", "Read of {} failed: {}", path, f.what()); oxTracef("ox.fs.PassThroughFS.read.error", "Read of {} failed: {}", path, f.what());
return OxError(2); return OxError(2);
} }
return OxError(0); return OxError(0);
@ -174,7 +174,7 @@ Error PassThroughFS::writeFilePath(CRStringView path, const void *buffer, uint64
std::ofstream f(p, std::ios::binary); std::ofstream f(p, std::ios::binary);
f.write(static_cast<const char*>(buffer), static_cast<std::streamsize>(size)); f.write(static_cast<const char*>(buffer), static_cast<std::streamsize>(size));
} catch (const std::fstream::failure &f) { } catch (const std::fstream::failure &f) {
oxTracef("ox::fs::PassThroughFS::read::error", "Write of {} failed: {}", path, f.what()); oxTracef("ox.fs.PassThroughFS.read.error", "Write of {} failed: {}", path, f.what());
return OxError(1); return OxError(1);
} }
return OxError(0); return OxError(0);
@ -186,9 +186,9 @@ Error PassThroughFS::writeFileInode(uint64_t, const void*, uint64_t, FileType) n
} }
std::string_view PassThroughFS::stripSlash(StringView path) noexcept { std::string_view PassThroughFS::stripSlash(StringView path) noexcept {
const auto pathLen = ox_strlen(path); const auto pathLen = ox::strlen(path);
for (auto i = 0u; i < pathLen && path[0] == '/'; i++) { for (auto i = 0u; i < pathLen && path[0] == '/'; i++) {
path = path.substr(1); path = substr(path, 1);
} }
return {path.data(), path.bytes()}; return {path.data(), path.bytes()};
} }

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include <ox/std/memops.hpp> #include <ox/std/memops.hpp>
@ -19,7 +19,7 @@ PathIterator::PathIterator(const char *path, std::size_t maxSize, std::size_t it
m_iterator = iterator; m_iterator = iterator;
} }
PathIterator::PathIterator(const char *path): PathIterator(path, ox_strlen(path)) { PathIterator::PathIterator(const char *path): PathIterator(path, ox::strlen(path)) {
} }
PathIterator::PathIterator(CRStringView path): PathIterator(path.data(), path.bytes()) { PathIterator::PathIterator(CRStringView path): PathIterator(path.data(), path.bytes()) {
@ -29,10 +29,10 @@ PathIterator::PathIterator(CRStringView path): PathIterator(path.data(), path.by
* @return 0 if no error * @return 0 if no error
*/ */
Error PathIterator::dirPath(char *out, std::size_t outSize) { Error PathIterator::dirPath(char *out, std::size_t outSize) {
const auto idx = ox_lastIndexOf(m_path, '/', m_maxSize); const auto idx = ox::lastIndexOf(m_path, '/', m_maxSize);
const auto size = static_cast<std::size_t>(idx + 1); const auto size = static_cast<std::size_t>(idx + 1);
if (idx >= 0 && size < outSize) { if (idx >= 0 && size < outSize) {
ox_memcpy(out, m_path, size); ox::memcpy(out, m_path, size);
out[size] = 0; out[size] = 0;
return OxError(0); return OxError(0);
} else { } else {
@ -44,12 +44,12 @@ Error PathIterator::dirPath(char *out, std::size_t outSize) {
* @return 0 if no error * @return 0 if no error
*/ */
Error PathIterator::fileName(char *out, std::size_t outSize) { Error PathIterator::fileName(char *out, std::size_t outSize) {
auto idx = ox_lastIndexOf(m_path, '/', m_maxSize); auto idx = ox::lastIndexOf(m_path, '/', m_maxSize);
if (idx >= 0) { if (idx >= 0) {
idx++; // pass up the preceding / idx++; // pass up the preceding /
std::size_t fileNameSize = static_cast<size_t>(ox_strlen(&m_path[idx])); std::size_t fileNameSize = static_cast<size_t>(ox::strlen(&m_path[idx]));
if (fileNameSize < outSize) { if (fileNameSize < outSize) {
ox_memcpy(out, &m_path[idx], fileNameSize); ox::memcpy(out, &m_path[idx], fileNameSize);
out[fileNameSize] = 0; out[fileNameSize] = 0;
return OxError(0); return OxError(0);
} else { } else {
@ -61,14 +61,15 @@ Error PathIterator::fileName(char *out, std::size_t outSize) {
} }
// Gets the get item in the path // Gets the get item in the path
Error PathIterator::get(char *pathOut, std::size_t pathOutSize) { Error PathIterator::get(IString<MaxFileNameLength> &fileName) {
std::size_t size = 0; std::size_t size = 0;
std::ignore = fileName.resize(MaxFileNameLength);
if (m_iterator >= m_maxSize) { if (m_iterator >= m_maxSize) {
oxTracef("ox::fs::PathIterator::get", "m_iterator ({}) >= m_maxSize ({})", m_iterator, m_maxSize); oxTracef("ox.fs.PathIterator.get", "m_iterator ({}) >= m_maxSize ({})", m_iterator, m_maxSize);
return OxError(1); return OxError(1);
} }
if (!ox_strlen(&m_path[m_iterator])) { if (!ox::strlen(&m_path[m_iterator])) {
oxTrace("ox::fs::PathIterator::get", "!ox_strlen(&m_path[m_iterator])"); oxTrace("ox.fs.PathIterator.get", "!ox::strlen(&m_path[m_iterator])");
return OxError(1); return OxError(1);
} }
auto start = m_iterator; auto start = m_iterator;
@ -76,88 +77,78 @@ Error PathIterator::get(char *pathOut, std::size_t pathOutSize) {
start++; start++;
} }
// end is at the next / // end is at the next /
const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start); const char *substr = ox::strchr(&m_path[start], '/', m_maxSize - start);
// correct end if it is invalid, which happens if there is no next / // correct end if it is invalid, which happens if there is no next /
if (!substr) { if (!substr) {
substr = ox_strchr(&m_path[start], 0, m_maxSize - start); substr = ox::strchr(&m_path[start], 0, m_maxSize - start);
} }
const auto end = static_cast<size_t>(substr - m_path); const auto end = static_cast<size_t>(substr - m_path);
size = end - start; size = end - start;
// cannot fit the output in the output parameter // cannot fit the output in the output parameter
if (size >= pathOutSize || size == 0) { if (size >= MaxFileNameLength || size == 0) {
return OxError(1); return OxError(1);
} }
ox_memcpy(pathOut, &m_path[start], size); ox::memcpy(fileName.data(), &m_path[start], size);
// truncate trailing / // truncate trailing /
if (size && pathOut[size - 1] == '/') { if (size && fileName[size - 1] == '/') {
size--; size--;
} }
pathOut[size] = 0; // end with null terminator oxReturnError(fileName.resize(size));
return OxError(0); return {};
} }
// Gets the get item in the path /**
Error PathIterator::next(char *pathOut, std::size_t pathOutSize) { * @return 0 if no error
*/
Error PathIterator::next(IString<MaxFileNameLength> &fileName) {
std::size_t size = 0; std::size_t size = 0;
auto retval = OxError(1); auto retval = OxError(1);
if (m_iterator < m_maxSize && ox_strlen(&m_path[m_iterator])) { std::ignore = fileName.resize(MaxFileNameLength);
if (m_iterator < m_maxSize && ox::strlen(&m_path[m_iterator])) {
retval = OxError(0); retval = OxError(0);
if (m_path[m_iterator] == '/') { if (m_path[m_iterator] == '/') {
m_iterator++; m_iterator++;
} }
const auto start = m_iterator; const auto start = m_iterator;
// end is at the next / // end is at the next /
const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start); const char *substr = ox::strchr(&m_path[start], '/', m_maxSize - start);
// correct end if it is invalid, which happens if there is no next / // correct end if it is invalid, which happens if there is no next /
if (!substr) { if (!substr) {
substr = ox_strchr(&m_path[start], 0, m_maxSize - start); substr = ox::strchr(&m_path[start], 0, m_maxSize - start);
} }
const auto end = static_cast<size_t>(substr - m_path); const auto end = static_cast<size_t>(substr - m_path);
size = end - start; size = end - start;
// cannot fit the output in the output parameter // cannot fit the output in the output parameter
if (size >= pathOutSize) { if (size >= MaxFileNameLength) {
return OxError(1); return OxError(1);
} }
ox_memcpy(pathOut, &m_path[start], size); ox::memcpy(fileName.data(), &m_path[start], size);
} }
// truncate trailing / // truncate trailing /
if (size && pathOut[size - 1] == '/') { if (size && fileName[size - 1] == '/') {
size--; size--;
} }
pathOut[size] = 0; // end with null terminator fileName[size] = 0; // end with null terminator
oxReturnError(fileName.resize(size));
m_iterator += size; m_iterator += size;
return retval; return retval;
} }
/**
* @return 0 if no error
*/
Error PathIterator::get(BString<MaxFileNameLength> *fileName) {
return get(fileName->data(), fileName->cap());
}
/**
* @return 0 if no error
*/
Error PathIterator::next(BString<MaxFileNameLength> *fileName) {
return next(fileName->data(), fileName->cap());
}
Result<std::size_t> PathIterator::nextSize() const { Result<std::size_t> PathIterator::nextSize() const {
std::size_t size = 0; std::size_t size = 0;
auto retval = OxError(1); auto retval = OxError(1);
auto it = m_iterator; auto it = m_iterator;
if (it < m_maxSize && ox_strlen(&m_path[it])) { if (it < m_maxSize && ox::strlen(&m_path[it])) {
retval = OxError(0); retval = OxError(0);
if (m_path[it] == '/') { if (m_path[it] == '/') {
it++; it++;
} }
const auto start = it; const auto start = it;
// end is at the next / // end is at the next /
const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start); const char *substr = ox::strchr(&m_path[start], '/', m_maxSize - start);
// correct end if it is invalid, which happens if there is no next / // correct end if it is invalid, which happens if there is no next /
if (!substr) { if (!substr) {
substr = ox_strchr(&m_path[start], 0, m_maxSize - start); substr = ox::strchr(&m_path[start], 0, m_maxSize - start);
} }
const auto end = static_cast<std::size_t>(substr - m_path); const auto end = static_cast<std::size_t>(substr - m_path);
size = end - start; size = end - start;
@ -168,16 +159,16 @@ Result<std::size_t> PathIterator::nextSize() const {
bool PathIterator::hasNext() const { bool PathIterator::hasNext() const {
std::size_t size = 0; std::size_t size = 0;
if (m_iterator < m_maxSize && ox_strlen(&m_path[m_iterator])) { if (m_iterator < m_maxSize && ox::strlen(&m_path[m_iterator])) {
std::size_t start = m_iterator; std::size_t start = m_iterator;
if (m_path[start] == '/') { if (m_path[start] == '/') {
start++; start++;
} }
// end is at the next / // end is at the next /
const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start); const char *substr = ox::strchr(&m_path[start], '/', m_maxSize - start);
// correct end if it is invalid, which happens if there is no next / // correct end if it is invalid, which happens if there is no next /
if (!substr) { if (!substr) {
substr = ox_strchr(&m_path[start], 0, m_maxSize - start); substr = ox::strchr(&m_path[start], 0, m_maxSize - start);
} }
const auto end = static_cast<std::size_t>(substr - m_path); const auto end = static_cast<std::size_t>(substr - m_path);
size = end - start; size = end - start;
@ -192,16 +183,16 @@ bool PathIterator::valid() const {
PathIterator PathIterator::next() const { PathIterator PathIterator::next() const {
std::size_t size = 0; std::size_t size = 0;
auto iterator = m_iterator; auto iterator = m_iterator;
if (iterator < m_maxSize && ox_strlen(&m_path[iterator])) { if (iterator < m_maxSize && ox::strlen(&m_path[iterator])) {
if (m_path[iterator] == '/') { if (m_path[iterator] == '/') {
iterator++; iterator++;
} }
const auto start = iterator; const auto start = iterator;
// end is at the next / // end is at the next /
const char *substr = ox_strchr(&m_path[start], '/', m_maxSize - start); const char *substr = ox::strchr(&m_path[start], '/', m_maxSize - start);
// correct end if it is invalid, which happens if there is no next / // correct end if it is invalid, which happens if there is no next /
if (!substr) { if (!substr) {
substr = ox_strchr(&m_path[start], 0, m_maxSize - start); substr = ox::strchr(&m_path[start], 0, m_maxSize - start);
} }
const auto end = static_cast<std::size_t>(substr - m_path); const auto end = static_cast<std::size_t>(substr - m_path);
size = end - start; size = end - start;

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -13,7 +13,7 @@
namespace ox { namespace ox {
constexpr std::size_t MaxFileNameLength = 255; constexpr std::size_t MaxFileNameLength = 255;
using FileName = BString<MaxFileNameLength>; using FileName = IString<MaxFileNameLength>;
class PathIterator { class PathIterator {
private: private:
@ -41,22 +41,12 @@ class PathIterator {
/** /**
* @return 0 if no error * @return 0 if no error
*/ */
Error next(char *pathOut, std::size_t pathOutSize); Error next(FileName &fileName);
/** /**
* @return 0 if no error * @return 0 if no error
*/ */
Error get(char *pathOut, std::size_t pathOutSize); Error get(FileName &fileName);
/**
* @return 0 if no error
*/
Error next(FileName *fileName);
/**
* @return 0 if no error
*/
Error get(FileName *fileName);
/** /**
* @return 0 if no error * @return 0 if no error

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -37,7 +37,7 @@ class OX_PACKED NodeBuffer {
Iterator(NodeBuffer *buffer, ItemPtr current) noexcept { Iterator(NodeBuffer *buffer, ItemPtr current) noexcept {
m_buffer = buffer; m_buffer = buffer;
m_current = current; m_current = current;
oxTrace("ox::ptrarith::Iterator::start") << current.offset(); oxTrace("ox.ptrarith.Iterator.start") << current.offset();
} }
operator const Item*() const noexcept { operator const Item*() const noexcept {
@ -77,7 +77,7 @@ class OX_PACKED NodeBuffer {
[[nodiscard]] [[nodiscard]]
bool hasNext() noexcept { bool hasNext() noexcept {
if (m_current.valid()) { if (m_current.valid()) {
oxTrace("ox::ptrarith::NodeBuffer::Iterator::hasNext::current") << m_current.offset(); oxTrace("ox.ptrarith.NodeBuffer.Iterator.hasNext.current") << m_current.offset();
auto next = m_buffer->next(m_current); auto next = m_buffer->next(m_current);
return next.valid() && m_buffer->firstItem() != next; return next.valid() && m_buffer->firstItem() != next;
} }
@ -85,7 +85,7 @@ class OX_PACKED NodeBuffer {
} }
void next() noexcept { void next() noexcept {
oxTrace("ox::ptrarith::NodeBuffer::Iterator::next") << m_it++; oxTrace("ox.ptrarith.NodeBuffer.Iterator.next") << m_it++;
if (hasNext()) { if (hasNext()) {
m_current = m_buffer->next(m_current); m_current = m_buffer->next(m_current);
} else { } else {
@ -173,15 +173,15 @@ class OX_PACKED NodeBuffer {
template<typename size_t, typename Item> template<typename size_t, typename Item>
NodeBuffer<size_t, Item>::NodeBuffer(std::size_t size) noexcept { NodeBuffer<size_t, Item>::NodeBuffer(std::size_t size) noexcept {
m_header.size = static_cast<size_t>(size); m_header.size = static_cast<size_t>(size);
ox_memset(this + 1, 0, size - sizeof(*this)); ox::memset(this + 1, 0, size - sizeof(*this));
oxTracef("ox::NodeBuffer::constructor", "{}", m_header.firstItem.get()); oxTracef("ox.NodeBuffer.constructor", "{}", m_header.firstItem.get());
} }
template<typename size_t, typename Item> template<typename size_t, typename Item>
NodeBuffer<size_t, Item>::NodeBuffer(const NodeBuffer &other, std::size_t size) noexcept { NodeBuffer<size_t, Item>::NodeBuffer(const NodeBuffer &other, std::size_t size) noexcept {
oxTracef("ox::ptrarith::NodeBuffer::copy", "other.m_header.firstItem: {}", other.m_header.firstItem.get()); oxTracef("ox.ptrarith.NodeBuffer.copy", "other.m_header.firstItem: {}", other.m_header.firstItem.get());
ox_memset(this + 1, 0, size - sizeof(*this)); ox::memset(this + 1, 0, size - sizeof(*this));
ox_memcpy(this, &other, size); ox::memcpy(this, &other, size);
} }
template<typename size_t, typename Item> template<typename size_t, typename Item>
@ -191,7 +191,7 @@ const typename NodeBuffer<size_t, Item>::Iterator NodeBuffer<size_t, Item>::iter
template<typename size_t, typename Item> template<typename size_t, typename Item>
typename NodeBuffer<size_t, Item>::Iterator NodeBuffer<size_t, Item>::iterator() noexcept { typename NodeBuffer<size_t, Item>::Iterator NodeBuffer<size_t, Item>::iterator() noexcept {
oxTracef("ox::ptrarith::NodeBuffer::iterator::size", "{}", m_header.size.get()); oxTracef("ox.ptrarith.NodeBuffer.iterator.size", "{}", m_header.size.get());
return Iterator(this, firstItem()); return Iterator(this, firstItem());
} }
@ -267,7 +267,7 @@ typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::ptr(size_t
template<typename size_t, typename Item> template<typename size_t, typename Item>
Result<typename NodeBuffer<size_t, Item>::ItemPtr> NodeBuffer<size_t, Item>::malloc(std::size_t size) noexcept { Result<typename NodeBuffer<size_t, Item>::ItemPtr> NodeBuffer<size_t, Item>::malloc(std::size_t size) noexcept {
const auto sz = static_cast<std::size_t>(size); const auto sz = static_cast<std::size_t>(size);
oxTracef("ox::ptrarith::NodeBuffer::malloc", "Size: {}", sz); oxTracef("ox.ptrarith.NodeBuffer.malloc", "Size: {}", sz);
size_t fullSize = static_cast<size_t>(sz + sizeof(Item)); size_t fullSize = static_cast<size_t>(sz + sizeof(Item));
if (m_header.size - m_header.bytesUsed >= fullSize) { if (m_header.size - m_header.bytesUsed >= fullSize) {
auto last = lastItem(); auto last = lastItem();
@ -277,21 +277,21 @@ Result<typename NodeBuffer<size_t, Item>::ItemPtr> NodeBuffer<size_t, Item>::mal
} else { } else {
// there is no first item, so this must be the first item // there is no first item, so this must be the first item
if (!m_header.firstItem) { if (!m_header.firstItem) {
oxTrace("ox::ptrarith::NodeBuffer::malloc", "No first item, initializing."); oxTrace("ox.ptrarith.NodeBuffer.malloc", "No first item, initializing.");
m_header.firstItem = static_cast<size_t>(sizeof(m_header)); m_header.firstItem = static_cast<size_t>(sizeof(m_header));
addr = m_header.firstItem; addr = m_header.firstItem;
} else { } else {
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail", "NodeBuffer is in invalid state."); oxTrace("ox.ptrarith.NodeBuffer.malloc.fail", "NodeBuffer is in invalid state.");
return OxError(1, "NodeBuffer is in invalid state."); return OxError(1, "NodeBuffer is in invalid state.");
} }
} }
oxTracef("ox::ptrarith::NodeBuffer::malloc", "buffer size: {}; addr: {}; fullSize: {}", m_header.size.get(), addr, fullSize); oxTracef("ox.ptrarith.NodeBuffer.malloc", "buffer size: {}; addr: {}; fullSize: {}", m_header.size.get(), addr, fullSize);
auto out = ItemPtr(this, m_header.size, addr, fullSize); auto out = ItemPtr(this, m_header.size, addr, fullSize);
if (!out.valid()) { if (!out.valid()) {
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail", "Unknown"); oxTrace("ox.ptrarith.NodeBuffer.malloc.fail", "Unknown");
return OxError(1, "NodeBuffer::malloc: unknown failure"); return OxError(1, "NodeBuffer::malloc: unknown failure");
} }
ox_memset(out, 0, fullSize); ox::memset(out, 0, fullSize);
new (out) Item; new (out) Item;
out->setSize(sz); out->setSize(sz);
@ -301,7 +301,7 @@ Result<typename NodeBuffer<size_t, Item>::ItemPtr> NodeBuffer<size_t, Item>::mal
if (first.valid()) { if (first.valid()) {
first->prev = out.offset(); first->prev = out.offset();
} else { } else {
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail", "NodeBuffer malloc failed due to invalid first element pointer."); oxTrace("ox.ptrarith.NodeBuffer.malloc.fail", "NodeBuffer malloc failed due to invalid first element pointer.");
return OxError(1, "NodeBuffer malloc failed due to invalid first element pointer."); return OxError(1, "NodeBuffer malloc failed due to invalid first element pointer.");
} }
@ -311,22 +311,22 @@ Result<typename NodeBuffer<size_t, Item>::ItemPtr> NodeBuffer<size_t, Item>::mal
} else { // check to see if this is the first allocation } else { // check to see if this is the first allocation
if (out.offset() != first.offset()) { if (out.offset() != first.offset()) {
// if this is not the first allocation, there should be an oldLast // if this is not the first allocation, there should be an oldLast
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail", "NodeBuffer malloc failed due to invalid last element pointer."); oxTrace("ox.ptrarith.NodeBuffer.malloc.fail", "NodeBuffer malloc failed due to invalid last element pointer.");
return OxError(1, "NodeBuffer malloc failed due to invalid last element pointer."); return OxError(1, "NodeBuffer malloc failed due to invalid last element pointer.");
} }
out->prev = out.offset(); out->prev = out.offset();
} }
m_header.bytesUsed += out.size(); m_header.bytesUsed += out.size();
oxTracef("ox::ptrarith::NodeBuffer::malloc", "Offset: {}", out.offset()); oxTracef("ox.ptrarith.NodeBuffer.malloc", "Offset: {}", out.offset());
return out; return out;
} }
oxTracef("ox::ptrarith::NodeBuffer::malloc::fail", "Insufficient space: {} needed, {} available", fullSize, available()); oxTracef("ox.ptrarith.NodeBuffer.malloc.fail", "Insufficient space: {} needed, {} available", fullSize, available());
return OxError(1); return OxError(1);
} }
template<typename size_t, typename Item> template<typename size_t, typename Item>
Error NodeBuffer<size_t, Item>::free(ItemPtr item) noexcept { Error NodeBuffer<size_t, Item>::free(ItemPtr item) noexcept {
oxTracef("ox::ptrarith::NodeBuffer::free", "offset: {}", item.offset()); oxTracef("ox.ptrarith.NodeBuffer.free", "offset: {}", item.offset());
auto prev = this->prev(item); auto prev = this->prev(item);
auto next = this->next(item); auto next = this->next(item);
if (prev.valid() && next.valid()) { if (prev.valid() && next.valid()) {
@ -338,16 +338,16 @@ Error NodeBuffer<size_t, Item>::free(ItemPtr item) noexcept {
} }
} else { } else {
// only one item, null out first // only one item, null out first
oxTrace("ox::ptrarith::NodeBuffer::free", "Nulling out firstItem."); oxTrace("ox.ptrarith.NodeBuffer.free", "Nulling out firstItem.");
m_header.firstItem = 0; m_header.firstItem = 0;
} }
} else { } else {
if (!prev.valid()) { if (!prev.valid()) {
oxTracef("ox::ptrarith::NodeBuffer::free::fail", "NodeBuffer free failed due to invalid prev element pointer: {}", prev.offset()); oxTracef("ox.ptrarith.NodeBuffer.free.fail", "NodeBuffer free failed due to invalid prev element pointer: {}", prev.offset());
return OxError(1); return OxError(1);
} }
if (!next.valid()) { if (!next.valid()) {
oxTracef("ox::ptrarith::NodeBuffer::free::fail", "NodeBuffer free failed due to invalid next element pointer: {}", next.offset()); oxTracef("ox.ptrarith.NodeBuffer.free.fail", "NodeBuffer free failed due to invalid next element pointer: {}", next.offset());
return OxError(1); return OxError(1);
} }
} }
@ -357,17 +357,17 @@ Error NodeBuffer<size_t, Item>::free(ItemPtr item) noexcept {
template<typename size_t, typename Item> template<typename size_t, typename Item>
Error NodeBuffer<size_t, Item>::setSize(std::size_t size) noexcept { Error NodeBuffer<size_t, Item>::setSize(std::size_t size) noexcept {
oxTracef("ox::ptrarith::NodeBuffer::setSize", "{} to {}", m_header.size.get(), size); oxTracef("ox.ptrarith.NodeBuffer.setSize", "{} to {}", m_header.size.get(), size);
auto last = lastItem(); auto last = lastItem();
auto end = last.valid() ? last.end() : sizeof(m_header); auto end = last.valid() ? last.end() : sizeof(m_header);
oxTracef("ox::ptrarith::NodeBuffer::setSize", "end: {}", end); oxTracef("ox.ptrarith.NodeBuffer.setSize", "end: {}", end);
if (end > size) { if (end > size) {
// resizing to less than buffer size // resizing to less than buffer size
return OxError(1); return OxError(1);
} else { } else {
m_header.size = static_cast<size_t>(size); m_header.size = static_cast<size_t>(size);
auto data = reinterpret_cast<uint8_t*>(this) + end; auto data = reinterpret_cast<uint8_t*>(this) + end;
ox_memset(data, 0, size - end); ox::memset(data, 0, size - end);
return OxError(0); return OxError(0);
} }
} }
@ -405,7 +405,7 @@ Error NodeBuffer<size_t, Item>::compact(F cb) noexcept {
return OxError(2); return OxError(2);
} }
// move node // move node
ox_memcpy(dest, src, src->fullSize()); ox::memcpy(dest, src, src->fullSize());
oxReturnError(cb(src, dest)); oxReturnError(cb(src, dest));
// update surrounding nodes // update surrounding nodes
auto prev = ptr(dest->prev); auto prev = ptr(dest->prev);

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -224,7 +224,7 @@ constexpr const Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(s
template<typename T, typename size_t, size_t minOffset> template<typename T, typename size_t, size_t minOffset>
template<typename SubT> template<typename SubT>
constexpr const Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset) const noexcept { constexpr const Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset) const noexcept {
oxTracef("ox::fs::Ptr::subPtr", "{} {} {} {} {}", m_itemOffset, this->size(), offset, m_itemSize, (m_itemSize - offset)); oxTracef("ox.fs.Ptr.subPtr", "{} {} {} {} {}", m_itemOffset, this->size(), offset, m_itemSize, (m_itemSize - offset));
return subPtr<SubT>(offset, m_itemSize - offset); return subPtr<SubT>(offset, m_itemSize - offset);
} }
@ -237,7 +237,7 @@ constexpr Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t
template<typename T, typename size_t, size_t minOffset> template<typename T, typename size_t, size_t minOffset>
template<typename SubT> template<typename SubT>
constexpr Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset) noexcept { constexpr Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t offset) noexcept {
oxTracef("ox::fs::Ptr::subPtr", "{} {} {} {} {}", m_itemOffset, this->size(), offset, m_itemSize, (m_itemSize - offset)); oxTracef("ox.fs.Ptr.subPtr", "{} {} {} {} {}", m_itemOffset, this->size(), offset, m_itemSize, (m_itemSize - offset));
return subPtr<SubT>(offset, m_itemSize - offset); return subPtr<SubT>(offset, m_itemSize - offset);
} }

View File

@ -6,24 +6,23 @@ add_executable(
target_link_libraries( target_link_libraries(
FSTests FSTests
OxFS OxFS
OxStd
OxMetalClaw OxMetalClaw
) )
add_test("[ox/fs] PtrArith::setSize" FSTests PtrArith::setSize) add_test("[ox/fs] PtrArith::setSize" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PtrArith::setSize)
add_test("[ox/fs] PathIterator::next1" FSTests PathIterator::next1) add_test("[ox/fs] PathIterator::next1" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::next1)
add_test("[ox/fs] PathIterator::next2" FSTests PathIterator::next2) add_test("[ox/fs] PathIterator::next2" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::next2)
add_test("[ox/fs] PathIterator::next3" FSTests PathIterator::next3) add_test("[ox/fs] PathIterator::next3" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::next3)
add_test("[ox/fs] PathIterator::next4" FSTests PathIterator::next4) add_test("[ox/fs] PathIterator::next4" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::next4)
add_test("[ox/fs] PathIterator::next5" FSTests PathIterator::next5) add_test("[ox/fs] PathIterator::next5" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::next5)
add_test("[ox/fs] PathIterator::hasNext" FSTests PathIterator::hasNext) add_test("[ox/fs] PathIterator::hasNext" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::hasNext)
add_test("[ox/fs] PathIterator::dirPath" FSTests PathIterator::dirPath) add_test("[ox/fs] PathIterator::dirPath" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::dirPath)
add_test("[ox/fs] PathIterator::fileName" FSTests PathIterator::fileName) add_test("[ox/fs] PathIterator::fileName" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::fileName)
add_test("[ox/fs] NodeBuffer::insert" FSTests "NodeBuffer::insert") add_test("[ox/fs] NodeBuffer::insert" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests "NodeBuffer::insert")
add_test("[ox/fs] FileStore::readWrite" FSTests "FileStore::readWrite") add_test("[ox/fs] FileStore::readWrite" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests "FileStore::readWrite")
add_test("[ox/fs] Directory" FSTests "Directory") add_test("[ox/fs] Directory" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests "Directory")
add_test("[ox/fs] FileSystem" FSTests "FileSystem") add_test("[ox/fs] FileSystem" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests "FileSystem")

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
// make sure asserts are enabled for the test file // make sure asserts are enabled for the test file
@ -26,15 +26,15 @@ struct OX_PACKED NodeType: public ox::ptrarith::Item<T> {
} }
}; };
const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tests = { const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests = {
{ {
{ {
"PtrArith::setSize", "PtrArith::setSize",
[](std::string_view) { [](ox::StringView) {
using BuffPtr_t = uint32_t; using BuffPtr_t = uint32_t;
ox::Vector<char> buff(5 * ox::units::MB); ox::Vector<char> buff(5 * ox::units::MB);
auto buffer = new (buff.data()) ox::ptrarith::NodeBuffer<BuffPtr_t, NodeType<BuffPtr_t>>(buff.size()); auto buffer = new (buff.data()) ox::ptrarith::NodeBuffer<BuffPtr_t, NodeType<BuffPtr_t>>(buff.size());
using String = ox::BString<6>; using String = ox::IString<6>;
auto a1 = buffer->malloc(sizeof(String)).value; auto a1 = buffer->malloc(sizeof(String)).value;
auto a2 = buffer->malloc(sizeof(String)).value; auto a2 = buffer->malloc(sizeof(String)).value;
oxAssert(a1.valid(), "Allocation 1 failed."); oxAssert(a1.valid(), "Allocation 1 failed.");
@ -57,85 +57,85 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"PathIterator::next1", "PathIterator::next1",
[](std::string_view) { [](ox::StringView) {
ox::String path = "/usr/share/charset.gbag"; auto const path = ox::String("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1)); ox::FileName buff;
oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "share") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "charset.gbag") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && buff == "charset.gbag", "PathIterator shows wrong next");
return OxError(0); return OxError(0);
} }
}, },
{ {
"PathIterator::next2", "PathIterator::next2",
[](std::string_view) { [](ox::StringView) {
ox::String path = "/usr/share/"; auto const path = ox::String("/usr/share/");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1)); ox::FileName buff;
oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "share") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next");
return OxError(0); return OxError(0);
} }
}, },
{ {
"PathIterator::next3", "PathIterator::next3",
[](std::string_view) { [](ox::StringView) {
ox::String path = "/"; auto const path = ox::String("/");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1)); ox::FileName buff;
oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "\0") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "\0") == 0, "PathIterator shows wrong next");
return OxError(0); return OxError(0);
} }
}, },
{ {
"PathIterator::next4", "PathIterator::next4",
[](std::string_view) { [](ox::StringView) {
ox::String path = "usr/share/charset.gbag"; auto const path = ox::String("usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1)); ox::FileName buff;
oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "share") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next");
oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "charset.gbag") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "charset.gbag") == 0, "PathIterator shows wrong next");
return OxError(0); return OxError(0);
} }
}, },
{ {
"PathIterator::next5", "PathIterator::next5",
[](std::string_view) { [](ox::StringView) {
ox::String path = "usr/share/"; auto const path = ox::String("usr/share/");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1)); ox::FileName buff;
oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "usr") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "share") == 0, "PathIterator shows wrong next"); oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next");
return OxError(0); return OxError(0);
} }
}, },
{ {
"PathIterator::dirPath", "PathIterator::dirPath",
[] (std::string_view) { [] (ox::StringView) {
ox::String path = "/usr/share/charset.gbag"; auto const path = ox::String("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1)); auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.dirPath(buff, path.len()) == 0 && ox_strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path"); oxAssert(it.dirPath(buff, path.len()) == 0 && ox::strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path");
return OxError(0); return OxError(0);
} }
}, },
{ {
"PathIterator::fileName", "PathIterator::fileName",
[](std::string_view) { [](ox::StringView) {
ox::String path = "/usr/share/charset.gbag"; auto const path = ox::String("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len()); ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1)); auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.fileName(buff, path.len()) == 0 && ox_strcmp(buff, "charset.gbag") == 0, "PathIterator shows incorrect file name"); oxAssert(it.fileName(buff, path.len()) == 0 && ox::strcmp(buff, "charset.gbag") == 0, "PathIterator shows incorrect file name");
return OxError(0); return OxError(0);
} }
}, },
{ {
"PathIterator::hasNext", "PathIterator::hasNext",
[](std::string_view) { [](ox::StringView) {
const auto path = "/file1"; const auto path = "/file1";
ox::PathIterator it(path, ox_strlen(path)); ox::PathIterator it(path, ox::strlen(path));
oxAssert(it.hasNext(), "PathIterator shows incorrect hasNext"); oxAssert(it.hasNext(), "PathIterator shows incorrect hasNext");
oxAssert(!it.next().hasNext(), "PathIterator shows incorrect hasNext"); oxAssert(!it.next().hasNext(), "PathIterator shows incorrect hasNext");
return OxError(0); return OxError(0);
@ -143,7 +143,7 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"Ptr::subPtr", "Ptr::subPtr",
[](std::string_view) { [](ox::StringView) {
constexpr auto buffLen = 5000; constexpr auto buffLen = 5000;
ox::ptrarith::Ptr<uint8_t, uint32_t> p(ox_alloca(buffLen), buffLen, 500, 500); ox::ptrarith::Ptr<uint8_t, uint32_t> p(ox_alloca(buffLen), buffLen, 500, 500);
oxAssert(p.valid(), "Ptr::subPtr: Ptr p is invalid."); oxAssert(p.valid(), "Ptr::subPtr: Ptr p is invalid.");
@ -155,7 +155,7 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"NodeBuffer::insert", "NodeBuffer::insert",
[](std::string_view) { [](ox::StringView) {
constexpr auto buffLen = 5000; constexpr auto buffLen = 5000;
auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen); auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen);
oxAssert(list->malloc(50).value.valid(), "NodeBuffer::insert: malloc 1 failed"); oxAssert(list->malloc(50).value.valid(), "NodeBuffer::insert: malloc 1 failed");
@ -168,12 +168,12 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"FileStore::readWrite", "FileStore::readWrite",
[](std::string_view) { [](ox::StringView) {
constexpr auto buffLen = 5000; constexpr auto buffLen = 5000;
constexpr auto str1 = "Hello, World!"; constexpr auto str1 = "Hello, World!";
constexpr auto str1Len = ox_strlen(str1) + 1; constexpr auto str1Len = ox::strlen(str1) + 1;
constexpr auto str2 = "Hello, Moon!"; constexpr auto str2 = "Hello, Moon!";
constexpr auto str2Len = ox_strlen(str2) + 1; constexpr auto str2Len = ox::strlen(str2) + 1;
auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen); auto list = new (ox_alloca(buffLen)) ox::ptrarith::NodeBuffer<uint32_t, ox::FileStoreItem<uint32_t>>(buffLen);
oxAssert(ox::FileStore32::format(list, buffLen), "FileStore::format failed."); oxAssert(ox::FileStore32::format(list, buffLen), "FileStore::format failed.");
ox::FileStore32 fileStore(list, buffLen); ox::FileStore32 fileStore(list, buffLen);
@ -189,26 +189,26 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"Directory", "Directory",
[](std::string_view) { [](ox::StringView) {
ox::Vector<uint8_t> fsBuff(5000); ox::Vector<uint8_t> fsBuff(5000);
oxAssert(ox::FileStore32::format(fsBuff.data(), fsBuff.size()), "FS format failed"); oxAssert(ox::FileStore32::format(fsBuff.data(), fsBuff.size()), "FS format failed");
ox::FileStore32 fileStore(fsBuff.data(), fsBuff.size()); ox::FileStore32 fileStore(fsBuff.data(), fsBuff.size());
ox::Directory32 dir(fileStore, 105); ox::Directory32 dir(fileStore, 105);
oxTrace("ox::fs::test::Directory") << "Init"; oxTrace("ox.fs.test.Directory") << "Init";
oxAssert(dir.init(), "Init failed"); oxAssert(dir.init(), "Init failed");
oxTrace("ox::fs::test::Directory") << "write 1"; oxTrace("ox.fs.test.Directory") << "write 1";
oxAssert(dir.write("/file1", 1), "Directory write of file1 failed"); oxAssert(dir.write("/file1", 1), "Directory write of file1 failed");
oxTrace("ox::fs::test::Directory") << "find"; oxTrace("ox.fs.test.Directory") << "find";
oxAssert(dir.find("file1").error, "Could not find file1"); oxAssert(dir.find("file1").error, "Could not find file1");
oxAssert(dir.find("file1").value == 1, "Could not find file1"); oxAssert(dir.find("file1").value == 1, "Could not find file1");
oxTrace("ox::fs::test::Directory") << "write 2"; oxTrace("ox.fs.test.Directory") << "write 2";
oxAssert(dir.write("/file3", 3), "Directory write of file3 failed"); oxAssert(dir.write("/file3", 3), "Directory write of file3 failed");
oxTrace("ox::fs::test::Directory") << "write 3"; oxTrace("ox.fs.test.Directory") << "write 3";
oxAssert(dir.write("/file2", 2), "Directory write of file2 failed"); oxAssert(dir.write("/file2", 2), "Directory write of file2 failed");
return OxError(0); return OxError(0);
@ -216,13 +216,13 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}, },
{ {
"FileSystem", "FileSystem",
[](std::string_view) { [](ox::StringView) {
ox::Vector<uint8_t> fsBuff(5000); ox::Vector<uint8_t> fsBuff(5000);
oxTrace("ox::fs::test::FileSystem") << "format"; oxTrace("ox.fs.test.FileSystem") << "format";
oxAssert(ox::FileSystem32::format(fsBuff.data(), fsBuff.size()), "FileSystem format failed"); oxAssert(ox::FileSystem32::format(fsBuff.data(), fsBuff.size()), "FileSystem format failed");
ox::FileSystem32 fs(ox::FileStore32(fsBuff.data(), fsBuff.size())); ox::FileSystem32 fs(ox::FileStore32(fsBuff.data(), fsBuff.size()));
oxTrace("ox::fs::test::FileSystem") << "mkdir"; oxTrace("ox.fs.test.FileSystem") << "mkdir";
oxAssert(fs.mkdir("/dir", true), "mkdir failed"); oxAssert(fs.mkdir("/dir", true), "mkdir failed");
oxAssert(fs.stat("/dir").error, "mkdir failed"); oxAssert(fs.stat("/dir").error, "mkdir failed");
oxAssert(fs.mkdir("/l1d1/l2d1/l3d1", true), "mkdir failed"); oxAssert(fs.mkdir("/l1d1/l2d1/l3d1", true), "mkdir failed");
@ -237,16 +237,16 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
}; };
int main(int argc, const char **args) { int main(int argc, const char **args) {
int retval = -1; if (argc < 2) {
if (argc > 1) { oxError("Must specify test to run");
std::string_view testName = args[1]; return -1;
std::string_view testArg;
if (args[2]) {
testArg = args[2];
} }
if (tests.find(testName) != tests.end()) { ox::StringView const testName = args[1];
retval = static_cast<int>(tests.at(testName)(testArg)); ox::StringView const testArg = args[2] ? args[2] : nullptr;
auto const func = tests.find(testName);
if (func != tests.end()) {
oxAssert(func->second(testArg), "Test returned Error");
return 0;
} }
} return -1;
return retval;
} }

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include <cstdio> #include <cstdio>
@ -67,7 +67,7 @@ static ox::Error run(int argc, const char **argv) noexcept {
return OxError(1); return OxError(1);
} }
const auto fsPath = argv[1]; const auto fsPath = argv[1];
ox::String subCmd = argv[2]; ox::String subCmd(argv[2]);
oxRequire(fs, loadFs(fsPath)); oxRequire(fs, loadFs(fsPath));
if (subCmd == "ls") { if (subCmd == "ls") {
return runLs(fs.get(), argc - 2, argv + 2); return runLs(fs.get(), argc - 2, argv + 2);

View File

@ -20,6 +20,8 @@ target_link_libraries(
OxLogConn PUBLIC OxLogConn PUBLIC
OxStd OxStd
OxMetalClaw OxMetalClaw
$<$<BOOL:${OX_OS_FREEBSD}>:pthread>
$<$<BOOL:${OX_OS_WINDOWS}>:ws2_32>
) )
install( install(

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -47,13 +47,13 @@ class CirculerBuffer {
} }
// write seg 1 // write seg 1
const auto seg1Sz = ox::min(sz, m_buff.size() - m_writePt); const auto seg1Sz = ox::min(sz, m_buff.size() - m_writePt);
ox_memcpy(&m_buff[m_writePt], &buff[0], seg1Sz); ox::listcpy(&m_buff[m_writePt], &buff[0], seg1Sz);
m_writePt += sz; m_writePt += sz;
if (seg1Sz != sz) { if (seg1Sz != sz) {
m_writePt -= m_buff.size(); m_writePt -= m_buff.size();
// write seg 2 // write seg 2
const auto seg2Sz = sz - seg1Sz; const auto seg2Sz = sz - seg1Sz;
ox_memcpy(&m_buff[0], &buff[seg1Sz], seg2Sz); ox::listcpy(&m_buff[0], &buff[seg1Sz], seg2Sz);
oxAssert(m_buff[0] == buff[seg1Sz], "break"); oxAssert(m_buff[0] == buff[seg1Sz], "break");
} }
return {}; return {};
@ -70,7 +70,7 @@ class CirculerBuffer {
return {}; return {};
} }
constexpr ox::Error seekp(int, ios_base::seekdir) { constexpr ox::Error seekp(int, ios_base::seekdir) noexcept {
return OxError(1, "Unimplemented"); return OxError(1, "Unimplemented");
} }
@ -84,13 +84,13 @@ class CirculerBuffer {
const auto bytesRead = ox::min(outSize, m_buff.size() - avail()); const auto bytesRead = ox::min(outSize, m_buff.size() - avail());
// read seg 1 // read seg 1
const auto seg1Sz = ox::min(bytesRead, m_buff.size() - m_readPt); const auto seg1Sz = ox::min(bytesRead, m_buff.size() - m_readPt);
ox_memcpy(&out[0], &m_buff[m_readPt], seg1Sz); ox::listcpy(&out[0], &m_buff[m_readPt], seg1Sz);
m_readPt += bytesRead; m_readPt += bytesRead;
if (seg1Sz != bytesRead) { if (seg1Sz != bytesRead) {
m_readPt -= m_buff.size(); m_readPt -= m_buff.size();
// read seg 2 // read seg 2
const auto seg2Sz = bytesRead - seg1Sz; const auto seg2Sz = bytesRead - seg1Sz;
ox_memcpy(&out[seg1Sz], &m_buff[0], seg2Sz); ox::listcpy(&out[seg1Sz], &m_buff[0], seg2Sz);
} }
return bytesRead; return bytesRead;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -7,21 +7,38 @@
*/ */
#ifdef OX_USE_STDLIB #ifdef OX_USE_STDLIB
#include <cstdio>
#include <sys/types.h>
#ifndef _WIN32
#include <sys/socket.h> #include <sys/socket.h>
#include <arpa/inet.h> #include <arpa/inet.h>
#include <netinet/in.h> #include <netinet/in.h>
#include <sys/types.h>
#include <unistd.h> #include <unistd.h>
#include <cstdio> #else
#include <winsock.h>
#undef interface
#undef min
#undef max
#endif
#include <ox/std/bit.hpp>
#include "logconn.hpp" #include "logconn.hpp"
#include <ox/std/bit.hpp>
namespace ox { namespace ox {
using namespace trace; using namespace trace;
void closeSock(auto s) noexcept {
#ifdef _WIN32
closesocket(s);
#else
close(s);
#endif
}
LoggerConn::LoggerConn() noexcept: m_netThread([this]{this->msgSend();}) { LoggerConn::LoggerConn() noexcept: m_netThread([this]{this->msgSend();}) {
} }
@ -30,7 +47,7 @@ LoggerConn::~LoggerConn() noexcept {
m_waitCond.notify_one(); m_waitCond.notify_one();
m_netThread.join(); m_netThread.join();
if (m_socket) { if (m_socket) {
close(m_socket); closeSock(m_socket);
} }
} }
@ -41,7 +58,7 @@ ox::Error LoggerConn::initConn(ox::CRStringView appName) noexcept {
addr.sin_port = htons(5590); addr.sin_port = htons(5590);
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP); m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
oxReturnError(OxError(static_cast<ox::ErrorCode>(connect(m_socket, reinterpret_cast<sockaddr*>(&addr), sizeof(addr))))); oxReturnError(OxError(static_cast<ox::ErrorCode>(connect(m_socket, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)))));
return sendInit({.appName = appName}); return sendInit({.appName = ox::BasicString<128>(appName)});
} }
ox::Error LoggerConn::send(const char *buff, std::size_t len) const noexcept { ox::Error LoggerConn::send(const char *buff, std::size_t len) const noexcept {
@ -81,7 +98,7 @@ void LoggerConn::msgSend() noexcept {
break; break;
} }
//std::printf("LoggerConn: sending %lu bytes\n", read); //std::printf("LoggerConn: sending %lu bytes\n", read);
oxIgnoreError(send(tmp.data(), read)); std::ignore = send(tmp.data(), read);
} }
} }
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -11,9 +11,9 @@
namespace ox { namespace ox {
enum { enum {
MC_PRESENCEMASKOUTBOUNDS = 1, McPresenceMapOverflow = 1,
MC_BUFFENDED = 2, McBuffEnded = 2,
MC_OUTBUFFENDED = 4 McOutputBuffEnded = 4
}; };
} }

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -14,6 +14,7 @@
#include <ox/std/byteswap.hpp> #include <ox/std/byteswap.hpp>
#include <ox/std/math.hpp> #include <ox/std/math.hpp>
#include <ox/std/memops.hpp> #include <ox/std/memops.hpp>
#include <ox/std/reader.hpp>
namespace ox::mc { namespace ox::mc {
@ -34,7 +35,7 @@ constexpr std::size_t highestBit(I val) noexcept {
if constexpr(is_signed_v<I>) { if constexpr(is_signed_v<I>) {
--shiftStart; --shiftStart;
} }
for (auto i = shiftStart; i < MaxValue<decltype(i)>; --i) { for (auto i = shiftStart; i > 0; --i) {
const auto bitValue = (val >> i) & 1; const auto bitValue = (val >> i) & 1;
if (bitValue) { if (bitValue) {
highestBit = i; highestBit = i;
@ -63,13 +64,14 @@ struct McInt {
template<typename I> template<typename I>
[[nodiscard]] [[nodiscard]]
constexpr McInt encodeInteger(I input) noexcept { constexpr McInt encodeInteger(I pInput) noexcept {
auto const input = ox::ResizedInt_t<I, 64>{pInput};
McInt out; McInt out;
const auto inputNegative = is_signed_v<I> && input < 0; const auto inputNegative = is_signed_v<I> && input < 0;
// move input to uint64_t to allow consistent bit manipulation, and to avoid // move input to uint64_t to allow consistent bit manipulation, and to avoid
// overflow concerns // overflow concerns
uint64_t val = 0; uint64_t val = 0;
ox_memcpy(&val, &input, sizeof(I)); ox::memcpy(&val, &input, sizeof(input));
if (val) { if (val) {
// bits needed to represent number factoring in space possibly // bits needed to represent number factoring in space possibly
// needed for signed bit // needed for signed bit
@ -92,7 +94,7 @@ constexpr McInt encodeInteger(I input) noexcept {
} }
if (bytes == 9) { if (bytes == 9) {
out.data[0] = bytesIndicator; out.data[0] = bytesIndicator;
ox_memcpy(&out.data[1], &leVal, sizeof(I)); ox::memcpy(&out.data[1], &leVal, 8);
if (inputNegative) { if (inputNegative) {
out.data[1] |= 0b1000'0000; out.data[1] |= 0b1000'0000;
} }
@ -102,7 +104,7 @@ constexpr McInt encodeInteger(I input) noexcept {
auto intermediate = auto intermediate =
static_cast<uint64_t>(leVal.raw() | (negBit << (valBits - 1))) << bytes | static_cast<uint64_t>(leVal.raw() | (negBit << (valBits - 1))) << bytes |
static_cast<uint64_t>(bytesIndicator); static_cast<uint64_t>(bytesIndicator);
ox_memcpy(out.data, &intermediate, sizeof(intermediate)); ox::memcpy(out.data, &intermediate, sizeof(intermediate));
} }
out.length = bytes; out.length = bytes;
} }
@ -114,7 +116,7 @@ constexpr McInt encodeInteger(I input) noexcept {
* length integer. * length integer.
*/ */
[[nodiscard]] [[nodiscard]]
static constexpr std::size_t countBytes(unsigned b) noexcept { constexpr std::size_t countBytes(unsigned b) noexcept {
std::size_t i = 0; std::size_t i = 0;
while ((b >> i) & 1) ++i; while ((b >> i) & 1) ++i;
return i + 1; return i + 1;
@ -131,17 +133,21 @@ static_assert(countBytes(0b0111'1111) == 8);
static_assert(countBytes(0b1111'1111) == 9); static_assert(countBytes(0b1111'1111) == 9);
template<typename I> template<typename I>
constexpr Result<I> decodeInteger(const uint8_t buff[9], std::size_t buffLen, std::size_t *bytesRead) noexcept { constexpr Result<I> decodeInteger(Reader_c auto&rdr, std::size_t *bytesRead) noexcept {
const auto bytes = countBytes(buff[0]); uint8_t firstByte = 0;
oxReturnError(rdr.read(&firstByte, 1));
oxReturnError(rdr.seekg(-1, ox::ios_base::cur));
const auto bytes = countBytes(firstByte);
if (bytes == 9) { if (bytes == 9) {
*bytesRead = bytes; *bytesRead = bytes;
I out = 0; I out = 0;
ox_memcpy(&out, &buff[1], sizeof(I)); oxReturnError(rdr.seekg(1, ox::ios_base::cur));
oxReturnError(rdr.read(&out, sizeof(I)));
return fromLittleEndian<I>(out); return fromLittleEndian<I>(out);
} else if (buffLen >= bytes) { }
*bytesRead = bytes; *bytesRead = bytes;
uint64_t decoded = 0; uint64_t decoded = 0;
ox_memcpy(&decoded, &buff[0], bytes); oxReturnError(rdr.read(&decoded, bytes));
decoded >>= bytes; decoded >>= bytes;
// move sign bit // move sign bit
if constexpr(is_signed_v<I>) { if constexpr(is_signed_v<I>) {
@ -152,7 +158,9 @@ constexpr Result<I> decodeInteger(const uint8_t buff[9], std::size_t buffLen, st
// fill in all bits between encoded sign and real sign with 1s // fill in all bits between encoded sign and real sign with 1s
// split it up because the 32-bit ARM can't shift more than 32 bits // split it up because the 32-bit ARM can't shift more than 32 bits
ox::Array<uint32_t, 2> d = {}; ox::Array<uint32_t, 2> d = {};
ox_memcpy(d.data(), &decoded, sizeof(decoded)); //d[0] = decoded & 0xffff'ffff;
//d[1] = decoded >> 32;
ox::memcpy(d.data(), &decoded, sizeof(decoded));
auto bit = negBit; auto bit = negBit;
for (; bit < ox::min<std::size_t>(Bits<I>, 32); ++bit) { for (; bit < ox::min<std::size_t>(Bits<I>, 32); ++bit) {
d[0] |= 1 << bit; d[0] |= 1 << bit;
@ -167,19 +175,18 @@ constexpr Result<I> decodeInteger(const uint8_t buff[9], std::size_t buffLen, st
d[0] = d[1]; d[0] = d[1];
d[1] = d0Tmp; d[1] = d0Tmp;
} }
ox_memcpy(&out, d.data(), sizeof(out)); ox::memcpy(&out, d.data(), sizeof(out));
return out; return out;
} }
} }
return static_cast<I>(decoded); return static_cast<I>(decoded);
}
return OxError(1);
} }
template<typename I> template<typename I>
constexpr Result<I> decodeInteger(McInt m) noexcept { Result<I> decodeInteger(McInt m) noexcept {
std::size_t bytesRead; std::size_t bytesRead{};
return decodeInteger<I>(m.data, 9, &bytesRead); BufferReader br({reinterpret_cast<const char*>(m.data), 9});
return decodeInteger<I>(br, &bytesRead);
} }
} }

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include "err.hpp" #include "err.hpp"
@ -11,7 +11,7 @@
namespace ox { namespace ox {
template class FieldBitmapReader<uint8_t*>; template class FieldBitmapWriterBase<uint8_t*>;
template class FieldBitmapReader<const uint8_t*>; template class FieldBitmapWriterBase<const uint8_t*>;
} }

View File

@ -1,28 +1,84 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
#include <ox/std/array.hpp>
#include <ox/std/bit.hpp>
#include <ox/std/error.hpp> #include <ox/std/error.hpp>
#include <ox/std/types.hpp> #include <ox/std/types.hpp>
#include <ox/std/reader.hpp>
#include "err.hpp" #include "err.hpp"
namespace ox { namespace ox {
template<typename T> template<Reader_c Reader>
class FieldBitmapReader { class FieldBitmapReader {
protected:
mutable std::size_t m_mapBlockIdx = ~std::size_t{0};
mutable uint64_t m_mapBlock = 0;
std::size_t m_mapStart = 0;
Reader &m_reader;
public:
explicit constexpr FieldBitmapReader(Reader &reader) noexcept;
constexpr Result<bool> get(std::size_t i) const noexcept;
private:
constexpr ox::Error loadMapBlock(std::size_t id) const noexcept;
};
template<Reader_c Reader>
constexpr FieldBitmapReader<Reader>::FieldBitmapReader(Reader &reader) noexcept:
m_mapStart(reader.tellg()),
m_reader(reader) {
}
template<Reader_c Reader>
constexpr Result<bool> FieldBitmapReader<Reader>::get(std::size_t idx) const noexcept {
constexpr auto blockBits = sizeof(m_mapBlock);
auto const blockIdx = idx / blockBits;
if (m_mapBlockIdx != blockIdx) [[unlikely]] {
oxReturnError(loadMapBlock(blockIdx));
}
idx %= blockBits;
return (m_mapBlock >> idx) & 1;
}
template<Reader_c Reader>
constexpr ox::Error FieldBitmapReader<Reader>::loadMapBlock(std::size_t idx) const noexcept {
oxRequire(g, m_reader.tellg());
oxReturnError(m_reader.seekg(static_cast<int>(m_mapStart + idx), ox::ios_base::beg));
ox::Array<char, sizeof(m_mapBlock)> mapBlock{};
oxReturnError(m_reader.read(mapBlock.data(), sizeof(m_mapBlock)));
// Warning: narrow-conv
oxReturnError(m_reader.seekg(static_cast<int>(g), ox::ios_base::beg));
m_mapBlock = 0;
for (auto i = 0ull; auto b : mapBlock) {
m_mapBlock |= static_cast<uint64_t>(std::bit_cast<uint8_t>(b)) << i;
i += 8;
}
m_mapBlockIdx = idx;
return {};
}
template<typename T>
class FieldBitmapWriterBase {
protected: protected:
T m_map = nullptr; T m_map = nullptr;
std::size_t m_mapLen = 0; std::size_t m_mapLen = 0;
public: public:
constexpr FieldBitmapReader(T map, std::size_t maxLen) noexcept; constexpr FieldBitmapWriterBase(T map, std::size_t maxLen) noexcept;
constexpr auto setBuffer(T map, std::size_t maxLen) noexcept; constexpr auto setBuffer(T map, std::size_t maxLen) noexcept;
@ -38,45 +94,45 @@ class FieldBitmapReader {
}; };
template<typename T> template<typename T>
constexpr FieldBitmapReader<T>::FieldBitmapReader(T map, std::size_t maxLen) noexcept { constexpr FieldBitmapWriterBase<T>::FieldBitmapWriterBase(T map, std::size_t maxLen) noexcept {
m_map = map; m_map = map;
m_mapLen = maxLen; m_mapLen = maxLen;
} }
template<typename T> template<typename T>
constexpr auto FieldBitmapReader<T>::setBuffer(T map, std::size_t maxLen) noexcept { constexpr auto FieldBitmapWriterBase<T>::setBuffer(T map, std::size_t maxLen) noexcept {
m_map = map; m_map = map;
m_mapLen = maxLen; m_mapLen = maxLen;
} }
template<typename T> template<typename T>
constexpr Result<bool> FieldBitmapReader<T>::get(std::size_t i) const noexcept { constexpr Result<bool> FieldBitmapWriterBase<T>::get(std::size_t i) const noexcept {
if (i / 8 < m_mapLen) { if (i / 8 < m_mapLen) {
return (m_map[i / 8] >> (i % 8)) & 1; return (m_map[i / 8] >> (i % 8)) & 1;
} else { } else {
return OxError(MC_PRESENCEMASKOUTBOUNDS); return OxError(McPresenceMapOverflow);
} }
} }
template<typename T> template<typename T>
constexpr void FieldBitmapReader<T>::setFields(int fields) noexcept { constexpr void FieldBitmapWriterBase<T>::setFields(int fields) noexcept {
m_mapLen = static_cast<std::size_t>((fields / 8 + 1) - (fields % 8 == 0)); m_mapLen = static_cast<std::size_t>((fields / 8 + 1) - (fields % 8 == 0));
} }
template<typename T> template<typename T>
constexpr void FieldBitmapReader<T>::setMaxLen(int maxLen) noexcept { constexpr void FieldBitmapWriterBase<T>::setMaxLen(int maxLen) noexcept {
m_mapLen = static_cast<std::size_t>(maxLen); m_mapLen = static_cast<std::size_t>(maxLen);
} }
template<typename T> template<typename T>
constexpr int64_t FieldBitmapReader<T>::getMaxLen() const noexcept { constexpr int64_t FieldBitmapWriterBase<T>::getMaxLen() const noexcept {
return static_cast<int64_t>(m_mapLen); return static_cast<int64_t>(m_mapLen);
} }
extern template class FieldBitmapReader<uint8_t*>; extern template class FieldBitmapWriterBase<uint8_t*>;
extern template class FieldBitmapReader<const uint8_t*>; extern template class FieldBitmapWriterBase<const uint8_t*>;
class FieldBitmap: public FieldBitmapReader<uint8_t*> { class FieldBitmap: public FieldBitmapWriterBase<uint8_t*> {
public: public:
constexpr FieldBitmap(uint8_t *map, std::size_t maxLen) noexcept; constexpr FieldBitmap(uint8_t *map, std::size_t maxLen) noexcept;
@ -85,7 +141,8 @@ class FieldBitmap: public FieldBitmapReader<uint8_t*> {
}; };
constexpr FieldBitmap::FieldBitmap(uint8_t *map, std::size_t maxLen) noexcept: FieldBitmapReader<uint8_t*>(map, maxLen) { constexpr FieldBitmap::FieldBitmap(uint8_t *map, std::size_t maxLen) noexcept:
FieldBitmapWriterBase<uint8_t*>(map, maxLen) {
} }
constexpr Error FieldBitmap::set(std::size_t i, bool on) noexcept { constexpr Error FieldBitmap::set(std::size_t i, bool on) noexcept {
@ -97,7 +154,7 @@ constexpr Error FieldBitmap::set(std::size_t i, bool on) noexcept {
} }
return {}; return {};
} else { } else {
return OxError(MC_PRESENCEMASKOUTBOUNDS); return OxError(McPresenceMapOverflow);
} }
} }

View File

@ -1,11 +1,19 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include <ox/model/modelhandleradaptor.hpp>
#include <ox/std/buffer.hpp>
#include <ox/std/reader.hpp>
#include "read.hpp"
namespace ox { namespace ox {
template class ModelHandlerInterface<MetalClawReaderTemplate<BufferReader>>;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -15,6 +15,7 @@
#include <ox/model/types.hpp> #include <ox/model/types.hpp>
#include <ox/std/buffer.hpp> #include <ox/std/buffer.hpp>
#include <ox/std/byteswap.hpp> #include <ox/std/byteswap.hpp>
#include <ox/std/optional.hpp>
#include <ox/std/string.hpp> #include <ox/std/string.hpp>
#include <ox/std/trace.hpp> #include <ox/std/trace.hpp>
#include <ox/std/vector.hpp> #include <ox/std/vector.hpp>
@ -26,22 +27,20 @@
namespace ox { namespace ox {
template<auto HandlerMaker> template<Reader_c Reader>
class MetalClawReaderTemplate { class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<Reader>, ox::OpType::Read> {
private: private:
FieldBitmapReader<const uint8_t*> m_fieldPresence; FieldBitmapReader<Reader> m_fieldPresence;
std::size_t m_fields = 0; std::size_t m_fields = 0;
std::size_t m_field = 0; std::size_t m_field = 0;
int m_unionIdx = -1; ox::Optional<int> m_unionIdx;
std::size_t m_buffIt = 0; Reader &m_reader;
std::size_t m_buffLen = 0;
const uint8_t *m_buff = nullptr;
MetalClawReaderTemplate<HandlerMaker> *m_parent = nullptr;
public: public:
constexpr MetalClawReaderTemplate(const uint8_t *buff, std::size_t buffLen, int unionIdx = -1, explicit constexpr MetalClawReaderTemplate(
MetalClawReaderTemplate<HandlerMaker> *parent = nullptr) noexcept; Reader &reader,
ox::Optional<int> const&unionIdx = {}) noexcept;
constexpr ~MetalClawReaderTemplate() noexcept; constexpr ~MetalClawReaderTemplate() noexcept;
@ -78,7 +77,7 @@ class MetalClawReaderTemplate {
constexpr Error field(const char*, BasicString<SmallStringSize> *val) noexcept; constexpr Error field(const char*, BasicString<SmallStringSize> *val) noexcept;
template<std::size_t L> template<std::size_t L>
constexpr Error field(const char*, BString<L> *val) noexcept; constexpr Error field(const char*, IString<L> *val) noexcept;
constexpr Error fieldCString(const char*, char *val, std::size_t buffLen) noexcept; constexpr Error fieldCString(const char*, char *val, std::size_t buffLen) noexcept;
@ -95,8 +94,7 @@ class MetalClawReaderTemplate {
/** /**
* Reads an string length from the current location in the buffer. * Reads an string length from the current location in the buffer.
*/ */
[[nodiscard]] constexpr Result<StringLength> stringLength(const char *name) noexcept;
constexpr StringLength stringLength(const char *name) noexcept;
template<typename T = std::nullptr_t> template<typename T = std::nullptr_t>
constexpr ox::Error setTypeInfo( constexpr ox::Error setTypeInfo(
@ -109,7 +107,7 @@ class MetalClawReaderTemplate {
* Returns a MetalClawReader to parse a child object. * Returns a MetalClawReader to parse a child object.
*/ */
[[nodiscard]] [[nodiscard]]
constexpr MetalClawReaderTemplate<HandlerMaker> child(const char *name, int unionIdx = -1) noexcept; constexpr MetalClawReaderTemplate<Reader> child(const char *name, ox::Optional<int> unionIdx = {}) noexcept;
/** /**
* Indicates whether or not the next field to be read is present. * Indicates whether or not the next field to be read is present.
@ -128,142 +126,130 @@ class MetalClawReaderTemplate {
constexpr void nextField() noexcept; constexpr void nextField() noexcept;
[[nodiscard]]
static constexpr auto opType() noexcept {
return OpType::Read;
}
private: private:
template<typename I> template<typename I>
constexpr Error readInteger(I *val) noexcept; constexpr Error readInteger(I *val) noexcept;
}; };
template<auto HandlerMaker> template<Reader_c Reader>
constexpr MetalClawReaderTemplate<HandlerMaker>::MetalClawReaderTemplate(const uint8_t *buff, std::size_t buffLen, constexpr MetalClawReaderTemplate<Reader>::MetalClawReaderTemplate(
int unionIdx, Reader &reader,
MetalClawReaderTemplate *parent) noexcept: ox::Optional<int> const&unionIdx) noexcept:
m_fieldPresence(buff, buffLen), m_fieldPresence(reader),
m_unionIdx(unionIdx), m_unionIdx(unionIdx),
m_buffLen(buffLen), m_reader(reader) {
m_buff(buff),
m_parent(parent) {
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr MetalClawReaderTemplate<HandlerMaker>::~MetalClawReaderTemplate() noexcept { constexpr MetalClawReaderTemplate<Reader>::~MetalClawReaderTemplate() noexcept {
if (m_parent) {
m_parent->m_buffIt += m_buffIt;
}
if (m_field != m_fields) { if (m_field != m_fields) {
oxTrace("ox::mc::MetalClawReader::error") << "MetalClawReader: incorrect fields number given"; oxTrace("ox.mc.MetalClawReader.error") << "MetalClawReader: incorrect fields number given";
} }
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int8_t *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int8_t *val) noexcept {
return readInteger(val); return readInteger(val);
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int16_t *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int16_t *val) noexcept {
return readInteger(val); return readInteger(val);
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int32_t *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int32_t *val) noexcept {
return readInteger(val); return readInteger(val);
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int64_t *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int64_t *val) noexcept {
return readInteger(val); return readInteger(val);
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint8_t *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint8_t *val) noexcept {
return readInteger(val); return readInteger(val);
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint16_t *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint16_t *val) noexcept {
return readInteger(val); return readInteger(val);
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint32_t *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint32_t *val) noexcept {
return readInteger(val); return readInteger(val);
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint64_t *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint64_t *val) noexcept {
return readInteger(val); return readInteger(val);
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, bool *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, bool *val) noexcept {
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
auto valErr = m_fieldPresence.get(static_cast<std::size_t>(m_field)); auto const result = m_fieldPresence.get(static_cast<std::size_t>(m_field));
*val = valErr.value; *val = result.value;
oxReturnError(valErr.error); oxReturnError(result);
} }
++m_field; ++m_field;
return OxError(0); return OxError(0);
} }
// array handler // array handler
template<auto HandlerMaker> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char *name, auto *val, std::size_t valLen) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, auto *val, std::size_t valLen) noexcept {
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length // read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0; std::size_t bytesRead = 0;
oxRequire(len, mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead)); oxRequire(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
m_buffIt += bytesRead;
// read the list // read the list
if (valLen >= len) { if (valLen >= len) {
auto reader = child(""); auto reader = child({});
auto handler = HandlerMaker(&reader); auto &handler = *reader.interface();
oxReturnError(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len))); oxReturnError(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len)));
for (std::size_t i = 0; i < len; ++i) { for (std::size_t i = 0; i < len; ++i) {
oxReturnError(handler.field("", &val[i])); oxReturnError(handler.field({}, &val[i]));
} }
} else { } else {
oxTrace("ox::mc::read::field(T)") << name << ", size:" << valLen; oxTracef("ox.mc.read.field(T)", "{}, length: {}", name, valLen);
return OxError(MC_OUTBUFFENDED); return OxError(McOutputBuffEnded);
} }
} }
} }
++m_field; ++m_field;
return OxError(0); return {};
} }
template<auto HandlerMaker> template<Reader_c Reader>
template<typename T> template<typename T>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, HashMap<String, T> *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, HashMap<String, T> *val) noexcept {
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length // read the length
if (m_buffIt >= m_buffLen) { oxRequire(g, m_reader.tellg());
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0; std::size_t bytesRead = 0;
oxRequire(len, mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead)); oxRequire(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
m_buffIt += bytesRead; oxReturnError(m_reader.seekg(g));
// read the list // read the list
auto reader = child(""); auto reader = child("");
auto handler = HandlerMaker(&reader); auto &handler = *reader.interface();
oxReturnError(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len))); oxReturnError(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len)));
for (std::size_t i = 0; i < len; ++i) { // this loop body needs to be in a lambda because of the potential alloca call
const auto keyLen = handler.stringLength(nullptr); constexpr auto loopBody = [](auto &handler, auto &val) {
oxRequire(keyLen, handler.stringLength(nullptr));
auto wkey = ox_malloca(keyLen + 1, char, 0); auto wkey = ox_malloca(keyLen + 1, char, 0);
auto wkeyPtr = wkey.get(); auto wkeyPtr = wkey.get();
oxReturnError(handler.fieldCString("", &wkeyPtr, keyLen + 1)); oxReturnError(handler.fieldCString("", &wkeyPtr, keyLen + 1));
oxReturnError(handler.field("", &val->operator[](wkey.get()))); return handler.field("", &val[wkeyPtr]);
};
for (std::size_t i = 0; i < len; ++i) {
oxReturnError(loopBody(handler, *val));
} }
} }
} }
@ -271,22 +257,23 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, HashMa
return OxError(0); return OxError(0);
} }
template<auto HandlerMaker> template<Reader_c Reader>
template<typename T> template<typename T>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char *name, T *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val) noexcept {
if constexpr(isVector_v<T>) { if constexpr(isVector_v<T>) {
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
// set size of val if the field is present, don't worry about it if not // set size of val if the field is present, don't worry about it if not
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
oxRequire(len, arrayLength(name, false)); oxRequire(len, arrayLength(name, false));
val->resize(len); oxReturnError(ox::resizeVector(*val, len));
}
return field(name, val->data(), val->size()); return field(name, val->data(), val->size());
} }
oxReturnError(ox::resizeVector(*val, 0));
}
++m_field; ++m_field;
return {}; return {};
} else if constexpr(isArray_v<T>) { } else if constexpr(isArray_v<T>) {
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
// set size of val if the field is present, don't worry about it if not // set size of val if the field is present, don't worry about it if not
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
oxRequire(len, arrayLength(name, false)); oxRequire(len, arrayLength(name, false));
@ -299,11 +286,10 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char *name, T
++m_field; ++m_field;
return {}; return {};
} else { } else {
if ((m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) && val) { if ((!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) && val) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
auto reader = child(""); auto reader = child("");
auto handler = HandlerMaker(&reader); oxReturnError(model(reader.interface(), val));
oxReturnError(model(&handler, val));
} }
} }
++m_field; ++m_field;
@ -311,44 +297,32 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char *name, T
} }
} }
template<auto HandlerMaker> template<Reader_c Reader>
template<typename U, bool force> template<typename U, bool force>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, UnionView<U, force> val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, UnionView<U, force> val) noexcept {
if ((m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) && val.get()) { if ((!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) && val.get()) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
auto reader = child("", val.idx()); auto reader = child("", ox::Optional<int>(ox::in_place, val.idx()));
auto handler = HandlerMaker(&reader); oxReturnError(model(reader.interface(), val.get()));
oxReturnError(model(&handler, val.get()));
} }
} }
++m_field; ++m_field;
return OxError(0); return {};
} }
template<auto HandlerMaker> template<Reader_c Reader>
template<std::size_t SmallStringSize> template<std::size_t SmallStringSize>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, BasicString<SmallStringSize> *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, BasicString<SmallStringSize> *val) noexcept {
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length // read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0; std::size_t bytesRead = 0;
oxRequire(size, mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead)); oxRequire(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
m_buffIt += bytesRead;
const auto cap = size; const auto cap = size;
*val = BasicString<SmallStringSize>(cap); *val = BasicString<SmallStringSize>(cap);
auto data = val->data(); auto data = val->data();
// read the string // read the string
if (static_cast<StringLength>(cap) < size) { oxReturnError(m_reader.read(data, size));
return OxError(MC_OUTBUFFENDED);
}
if (m_buffIt + size > m_buffLen) {
return OxError(MC_BUFFENDED);
}
ox_strncpy(data, &m_buff[m_buffIt], size);
m_buffIt += size;
} else { } else {
*val = ""; *val = "";
} }
@ -357,81 +331,71 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, BasicS
return OxError(0); return OxError(0);
} }
template<auto HandlerMaker> template<Reader_c Reader>
template<std::size_t L> template<std::size_t L>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char *name, BString<L> *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, IString<L> *val) noexcept {
return fieldCString(name, val->data(), val->cap()); if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::fieldCString(const char*, char *val, std::size_t buffLen) noexcept {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length // read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0; std::size_t bytesRead = 0;
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead); oxRequire(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
if (size > buffLen) { *val = IString<L>();
return OxError(MC_OUTBUFFENDED); oxReturnError(val->resize(size));
auto const data = val->data();
// read the string
oxReturnError(m_reader.read(data, size));
} else {
*val = "";
}
}
++m_field;
return {};
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char *val, std::size_t buffLen) noexcept {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
std::size_t bytesRead = 0;
oxRequire(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
if (size > buffLen) {
return OxError(McOutputBuffEnded);
} }
m_buffIt += bytesRead;
oxReturnError(err);
// re-allocate in case too small // re-allocate in case too small
auto data = val; auto data = val;
// read the string // read the string
if (m_buffIt + size <= m_buffLen) { oxReturnError(m_reader.read(data, size));
ox_memcpy(data, &m_buff[m_buffIt], size);
data[size] = 0; data[size] = 0;
m_buffIt += size;
} else {
return OxError(MC_BUFFENDED);
}
} }
++m_field; ++m_field;
return OxError(0); return OxError(0);
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::fieldCString(const char*, char **val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char **val) noexcept {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length // read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0; std::size_t bytesRead = 0;
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead); oxRequire(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
m_buffIt += bytesRead;
oxReturnError(err);
// re-allocate in case too small // re-allocate in case too small
safeDelete(*val); safeDelete(*val);
*val = new char[size + 1]; *val = new char[size + 1];
auto data = *val; auto data = *val;
// read the string // read the string
if (m_buffIt + size <= m_buffLen) { oxReturnError(m_reader.read(data, size));
ox_memcpy(data, &m_buff[m_buffIt], size);
data[size] = 0; data[size] = 0;
m_buffIt += size;
} else {
return OxError(MC_BUFFENDED);
}
} }
++m_field; ++m_field;
return OxError(0); return OxError(0);
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::fieldCString(const char*, char **val, std::size_t buffLen) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char **val, std::size_t buffLen) noexcept {
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length // read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0; std::size_t bytesRead = 0;
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead); oxRequire(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
m_buffIt += bytesRead;
oxReturnError(err);
// re-allocate if too small // re-allocate if too small
if (buffLen < size + 1) { if (buffLen < size + 1) {
safeDelete(*val); safeDelete(*val);
@ -440,13 +404,8 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::fieldCString(const char*,
} }
auto data = *val; auto data = *val;
// read the string // read the string
if (m_buffIt + size <= m_buffLen) { oxReturnError(m_reader.read(data, size));
ox_memcpy(data, &m_buff[m_buffIt], size);
data[size] = 0; data[size] = 0;
m_buffIt += size;
} else {
return OxError(MC_BUFFENDED);
}
} else { } else {
auto data = *val; auto data = *val;
if (data) { if (data) {
@ -458,18 +417,16 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::fieldCString(const char*,
return OxError(0); return OxError(0);
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr Result<ArrayLength> MetalClawReaderTemplate<HandlerMaker>::arrayLength(const char*, bool pass) noexcept { constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(const char*, bool pass) noexcept {
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length // read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0; std::size_t bytesRead = 0;
auto out = mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead).value; oxRequire(g, m_reader.tellg());
if (pass) { oxRequire(out, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
m_buffIt += bytesRead; if (!pass) {
oxReturnError(m_reader.seekg(g));
} }
return out; return out;
} }
@ -477,20 +434,29 @@ constexpr Result<ArrayLength> MetalClawReaderTemplate<HandlerMaker>::arrayLength
return OxError(1); return OxError(1);
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(const char*) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
std::size_t bytesRead = 0;
auto len = mc::decodeInteger<StringLength>(m_reader, &bytesRead);
oxReturnError(m_reader.seekg(-static_cast<int64_t>(bytesRead), ox::ios_base::cur));
return len;
}
}
return 0;
}
template<Reader_c Reader>
template<typename I> template<typename I>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::readInteger(I *val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::readInteger(I *val) noexcept {
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
std::size_t bytesRead = 0; std::size_t bytesRead = 0;
if (m_buffIt >= m_buffLen) { auto const result = mc::decodeInteger<I>(m_reader, &bytesRead);
oxTrace("ox::MetalClaw::readInteger") << "Buffer ended"; oxReturnError(result);
return OxError(MC_BUFFENDED); *val = result.value;
}
auto valErr = mc::decodeInteger<I>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
m_buffIt += bytesRead;
oxReturnError(valErr.error);
*val = valErr.value;
} else { } else {
*val = 0; *val = 0;
} }
@ -499,22 +465,17 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::readInteger(I *val) noexc
return OxError(0); return OxError(0);
} }
template<auto HandlerMaker> template<Reader_c Reader>
template<typename T, typename CB> template<typename T, typename CB>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, CB cb) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, CB cb) noexcept {
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) { if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length // read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0; std::size_t bytesRead = 0;
oxRequire(len, mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead)); oxRequire(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
m_buffIt += bytesRead;
// read the list // read the list
auto reader = child(""); auto reader = child("");
auto handler = HandlerMaker(&reader); auto &handler = *reader.interface();
oxReturnError(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len))); oxReturnError(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len)));
for (std::size_t i = 0; i < len; ++i) { for (std::size_t i = 0; i < len; ++i) {
T val; T val;
@ -527,50 +488,38 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, CB cb)
return OxError(0); return OxError(0);
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr StringLength MetalClawReaderTemplate<HandlerMaker>::stringLength(const char*) noexcept {
if (m_unionIdx == -1 || static_cast<std::size_t>(m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
std::size_t bytesRead = 0;
auto len = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
return len.value;
}
}
return 0;
}
template<auto HandlerMaker>
template<typename T> template<typename T>
constexpr ox::Error MetalClawReaderTemplate<HandlerMaker>::setTypeInfo( constexpr ox::Error MetalClawReaderTemplate<Reader>::setTypeInfo(
const char*, int, const Vector<String>&, std::size_t fields) noexcept { const char*, int, const Vector<String>&, std::size_t fields) noexcept {
m_fields = fields; m_fields = fields;
m_buffIt = static_cast<std::size_t>((fields / 8 + 1) - (fields % 8 == 0)); // Warning: narrow-conv
m_fieldPresence.setFields(static_cast<int>(fields)); return m_reader.seekg(
m_fieldPresence.setMaxLen(static_cast<int>(m_buffIt)); static_cast<int>((fields / 8 + 1) - (fields % 8 == 0)),
return {}; ox::ios_base::cur);
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr MetalClawReaderTemplate<HandlerMaker> MetalClawReaderTemplate<HandlerMaker>::child(const char*, int unionIdx) noexcept { constexpr MetalClawReaderTemplate<Reader> MetalClawReaderTemplate<Reader>::child(
return MetalClawReaderTemplate<HandlerMaker>(m_buff + m_buffIt, m_buffLen - m_buffIt, unionIdx, this); const char*,
ox::Optional<int> unionIdx) noexcept {
return MetalClawReaderTemplate<Reader>(m_reader, unionIdx);
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr bool MetalClawReaderTemplate<HandlerMaker>::fieldPresent(const char*) const noexcept { constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(const char*) const noexcept {
return m_fieldPresence.get(static_cast<std::size_t>(m_field)).value; return m_fieldPresence.get(static_cast<std::size_t>(m_field)).value;
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr bool MetalClawReaderTemplate<HandlerMaker>::fieldPresent(int fieldNo) const noexcept { constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(int fieldNo) const noexcept {
return m_fieldPresence.get(static_cast<std::size_t>(fieldNo)).value; return m_fieldPresence.get(static_cast<std::size_t>(fieldNo)).value;
} }
template<auto HandlerMaker> template<Reader_c Reader>
[[nodiscard]] [[nodiscard]]
constexpr int MetalClawReaderTemplate<HandlerMaker>::whichFieldPresent(const char*, const ModelUnion &u) const noexcept { constexpr int MetalClawReaderTemplate<Reader>::whichFieldPresent(const char*, const ModelUnion &u) const noexcept {
FieldBitmapReader<const uint8_t*> p(m_buff + m_buffIt, m_buffLen - m_buffIt); FieldBitmapReader<Reader> p(m_reader);
p.setFields(static_cast<int>(u.fieldCount()));
for (auto i = 0u; i < u.fieldCount(); ++i) { for (auto i = 0u; i < u.fieldCount(); ++i) {
if (p.get(i)) { if (p.get(i)) {
return static_cast<int>(i); return static_cast<int>(i);
@ -579,32 +528,28 @@ constexpr int MetalClawReaderTemplate<HandlerMaker>::whichFieldPresent(const cha
return -1; return -1;
} }
template<auto HandlerMaker> template<Reader_c Reader>
constexpr void MetalClawReaderTemplate<HandlerMaker>::nextField() noexcept { constexpr void MetalClawReaderTemplate<Reader>::nextField() noexcept {
++m_field; ++m_field;
} }
using MetalClawReader = MetalClawReaderTemplate<[](auto r) { using MetalClawReader = MetalClawReaderTemplate<ox::BufferReader>;
return ModelHandlerInterface{r};
}>;
template<typename T> template<typename T>
Error readMC(const char *buff, std::size_t buffLen, T *val) noexcept { Error readMC(ox::BufferView buff, T &val) noexcept {
MetalClawReader reader(reinterpret_cast<const uint8_t*>(buff), buffLen); BufferReader br(buff);
ModelHandlerInterface handler(&reader); MetalClawReader reader(br);
return model(&handler, val); ModelHandlerInterface<MetalClawReader, ox::OpType::Read> handler(&reader);
return model(&handler, &val);
} }
template<typename T> template<typename T>
Result<T> readMC(const char *buff, std::size_t buffLen) noexcept { Result<T> readMC(ox::BufferView buff) noexcept {
T val; Result<T> val;
oxReturnError(readMC(buff, buffLen, &val)); oxReturnError(readMC(buff, val.value));
return val; return val;
} }
template<typename T> extern template class ModelHandlerInterface<MetalClawReaderTemplate<BufferReader>>;
Result<T> readMC(const Buffer &buff) noexcept {
return readMC<T>(buff.data(), buff.size());
}
} }

View File

@ -8,9 +8,9 @@ target_link_libraries(
OxMetalClaw OxMetalClaw
) )
add_test("[ox/mc] McTest Writer" McTest MetalClawWriter) add_test("[ox/mc] Writer" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/McTest MetalClawWriter)
add_test("[ox/mc] McTest Reader" McTest MetalClawReader) add_test("[ox/mc] Reader" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/McTest MetalClawReader)
#add_test("[ox/mc] McTest MetalClawDef" McTest MetalClawDef) #add_test("[ox/mc] MetalClawDef" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/McTest MetalClawDef)
add_test("[ox/mc] McTest MetalClawModelValue" McTest MetalClawModelValue) add_test("[ox/mc] MetalClawModelValue" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/McTest MetalClawModelValue)
add_test("[ox/mc] McTest encodeInteger" McTest encodeInteger) add_test("[ox/mc] encodeInteger" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/McTest encodeInteger)
add_test("[ox/mc] McTest decodeInteger" McTest decodeInteger) add_test("[ox/mc] decodeInteger" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/McTest decodeInteger)

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -18,8 +18,8 @@ union TestUnion {
static constexpr auto TypeName = "TestUnion"; static constexpr auto TypeName = "TestUnion";
static constexpr auto TypeVersion = 1; static constexpr auto TypeVersion = 1;
bool Bool; bool Bool;
uint32_t Int = 5; uint32_t Int;
char *CString; char *CString{};
}; };
struct TestStructNest { struct TestStructNest {
@ -27,7 +27,7 @@ struct TestStructNest {
static constexpr auto TypeVersion = 1; static constexpr auto TypeVersion = 1;
bool Bool = false; bool Bool = false;
uint32_t Int = 0; uint32_t Int = 0;
ox::BString<32> BString = ""; ox::IString<32> IString = "";
}; };
struct TestStruct { struct TestStruct {
@ -45,10 +45,11 @@ struct TestStruct {
int32_t Int8 = 0; int32_t Int8 = 0;
int unionIdx = 1; int unionIdx = 1;
TestUnion Union; TestUnion Union;
ox::String String = ""; ox::String String;
ox::BString<32> BString = ""; ox::IString<32> IString = "";
uint32_t List[4] = {0, 0, 0, 0}; uint32_t List[4] = {0, 0, 0, 0};
ox::Vector<uint32_t> Vector = {1, 2, 3, 4, 5}; ox::Vector<uint32_t> Vector = {1, 2, 3, 4, 5};
ox::Vector<uint32_t> Vector2 = {1, 2, 3, 4, 5};
ox::HashMap<ox::String, int> Map; ox::HashMap<ox::String, int> Map;
TestStructNest EmptyStruct; TestStructNest EmptyStruct;
TestStructNest Struct; TestStructNest Struct;
@ -71,13 +72,12 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith<TestUnion> auto *obj) noexcep
oxModelBegin(TestStructNest) oxModelBegin(TestStructNest)
oxModelField(Bool) oxModelField(Bool)
oxModelField(Int) oxModelField(Int)
oxModelField(BString) oxModelField(IString)
oxModelEnd() oxModelEnd()
template<typename T> template<typename T>
constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) noexcept { constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) noexcept {
oxReturnError(io->template setTypeInfo<TestStruct>()); oxReturnError(io->template setTypeInfo<TestStruct>());
oxReturnError(io->field("Vector", &obj->Vector));
oxReturnError(io->field("Bool", &obj->Bool)); oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int)); oxReturnError(io->field("Int", &obj->Int));
oxReturnError(io->field("Int1", &obj->Int1)); oxReturnError(io->field("Int1", &obj->Int1));
@ -95,25 +95,26 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) noexce
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, obj->unionIdx})); oxReturnError(io->field("Union", ox::UnionView{&obj->Union, obj->unionIdx}));
} }
oxReturnError(io->field("String", &obj->String)); oxReturnError(io->field("String", &obj->String));
oxReturnError(io->field("BString", &obj->BString)); oxReturnError(io->field("IString", &obj->IString));
oxReturnError(io->field("List", obj->List, 4)); oxReturnError(io->field("List", obj->List, 4));
oxReturnError(io->field("Vector", &obj->Vector));
oxReturnError(io->field("Vector2", &obj->Vector2));
oxReturnError(io->field("Map", &obj->Map)); oxReturnError(io->field("Map", &obj->Map));
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));
oxReturnError(io->field("Struct", &obj->Struct)); oxReturnError(io->field("Struct", &obj->Struct));
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));
return OxError(0); return OxError(0);
} }
std::map<ox::String, ox::Error(*)()> tests = { std::map<ox::StringView, ox::Error(*)()> tests = {
{ {
{ {
"MetalClawWriter", "MetalClawWriter",
[] { [] {
// This test doesn't confirm much, but it does show that the writer // This test doesn't confirm much, but it does show that the writer
// doesn't segfault // doesn't segfault
static constexpr size_t buffLen = 1024; ox::Array<char, 1024> buff;
char buff[buffLen];
TestStruct ts; TestStruct ts;
oxReturnError(ox::writeMC(buff, buffLen, ts)); oxReturnError(ox::writeMC(buff.data(), buff.size(), ts));
oxReturnError(ox::writeMC(ts)); oxReturnError(ox::writeMC(ts));
return OxError(0); return OxError(0);
} }
@ -126,22 +127,23 @@ std::map<ox::String, ox::Error(*)()> tests = {
TestStruct testIn, testOut; TestStruct testIn, testOut;
testIn.Bool = true; testIn.Bool = true;
testIn.Int = 42; testIn.Int = 42;
testIn.Union.Int = 42; testIn.IString = "Test String 1";
testIn.String = "Test String 0"; testIn.String = "Test String 2";
testIn.BString = "Test String 1"; testIn.Vector = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, };
testIn.Vector2 = {};
testIn.List[0] = 1; testIn.List[0] = 1;
testIn.List[1] = 2; testIn.List[1] = 2;
testIn.List[2] = 3; testIn.List[2] = 3;
testIn.List[3] = 4; testIn.List[3] = 4;
testIn.Map["asdf"] = 93; testIn.Struct.Bool = true;
testIn.Map["aoeu"] = 94;
testIn.Struct.Bool = false;
testIn.Struct.Int = 300; testIn.Struct.Int = 300;
testIn.Struct.BString = "Test String 2"; testIn.Struct.IString = "Test String 3";
testIn.unionIdx = 1;
testIn.Union.Int = 93;
// run tests // run tests
const auto [buff, err] = ox::writeMC(testIn); const auto [buff, err] = ox::writeMC(testIn);
oxAssert(err, "writeMC failed"); oxAssert(err, "writeMC failed");
oxAssert(ox::readMC(buff.data(), buff.size(), &testOut), "readMC failed"); oxAssert(ox::readMC(buff, testOut), "readMC failed");
//std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n"; //std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n";
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch"); oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");
oxAssert(testIn.Int == testOut.Int, "Int value mismatch"); oxAssert(testIn.Int == testOut.Int, "Int value mismatch");
@ -155,22 +157,24 @@ std::map<ox::String, ox::Error(*)()> tests = {
oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch"); oxAssert(testIn.Int8 == testOut.Int8, "Int8 value mismatch");
oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch"); oxAssert(testIn.Union.Int == testOut.Union.Int, "Union.Int value mismatch");
oxAssert(testIn.String == testOut.String, "String value mismatch"); oxAssert(testIn.String == testOut.String, "String value mismatch");
oxAssert(testIn.BString == testOut.BString, "BString value mismatch"); oxDebugf("{}", testOut.IString.len());
oxExpect(testIn.IString, testOut.IString);
oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch"); oxAssert(testIn.List[0] == testOut.List[0], "List[0] value mismatch");
oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch"); oxAssert(testIn.List[1] == testOut.List[1], "List[1] value mismatch");
oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch"); oxAssert(testIn.List[2] == testOut.List[2], "List[2] value mismatch");
oxAssert(testIn.List[3] == testOut.List[3], "List[3] value mismatch"); oxAssert(testIn.List[3] == testOut.List[3], "List[3] value mismatch");
oxAssert(testIn.Vector[0] == testOut.Vector[0], "Vector[0] value mismatch"); oxAssert(testIn.Vector.size() == testOut.Vector.size(), "Vector size mismatch");
oxAssert(testIn.Vector[1] == testOut.Vector[1], "Vector[1] value mismatch"); for (auto i = 0u; i < testIn.Vector.size(); ++i) {
oxAssert(testIn.Vector[2] == testOut.Vector[2], "Vector[2] value mismatch"); oxAssert(testIn.Vector[i] == testOut.Vector[i], ox::sfmt("Vector[{}] value mismatch", i));
oxAssert(testIn.Vector[3] == testOut.Vector[3], "Vector[3] value mismatch"); }
oxAssert(testIn.Vector2.size() == testOut.Vector2.size(), "Vector2 size mismatch");
oxAssert(testIn.Map["asdf"] == testOut.Map["asdf"], "Map[\"asdf\"] value mismatch"); oxAssert(testIn.Map["asdf"] == testOut.Map["asdf"], "Map[\"asdf\"] value mismatch");
oxAssert(testIn.Map["aoeu"] == testOut.Map["aoeu"], "Map[\"aoeu\"] value mismatch"); oxAssert(testIn.Map["aoeu"] == testOut.Map["aoeu"], "Map[\"aoeu\"] value mismatch");
oxAssert(testIn.EmptyStruct.Bool == testOut.EmptyStruct.Bool, "EmptyStruct.Bool value mismatch"); oxAssert(testIn.EmptyStruct.Bool == testOut.EmptyStruct.Bool, "EmptyStruct.Bool value mismatch");
oxAssert(testIn.EmptyStruct.Int == testOut.EmptyStruct.Int, "EmptyStruct.Int value mismatch"); oxAssert(testIn.EmptyStruct.Int == testOut.EmptyStruct.Int, "EmptyStruct.Int value mismatch");
oxAssert(testIn.EmptyStruct.BString == testOut.EmptyStruct.BString, "EmptyStruct.BString value mismatch"); oxAssert(testIn.EmptyStruct.IString == testOut.EmptyStruct.IString, "EmptyStruct.IString value mismatch");
oxAssert(testIn.Struct.Int == testOut.Struct.Int, "Struct.Int value mismatch"); oxAssert(testIn.Struct.Int == testOut.Struct.Int, "Struct.Int value mismatch");
oxAssert(testIn.Struct.BString == testOut.Struct.BString, "Struct.BString value mismatch"); oxAssert(testIn.Struct.IString == testOut.Struct.IString, "Struct.IString value mismatch");
oxAssert(testIn.Struct.Bool == testOut.Struct.Bool, "Struct.Bool value mismatch"); oxAssert(testIn.Struct.Bool == testOut.Struct.Bool, "Struct.Bool value mismatch");
return OxError(0); return OxError(0);
} }
@ -264,6 +268,9 @@ std::map<ox::String, ox::Error(*)()> tests = {
return OxError(0); return OxError(0);
}; };
oxAssert(check(uint32_t(14)), "Decode of 14 failed."); oxAssert(check(uint32_t(14)), "Decode of 14 failed.");
oxAssert(check(int8_t(-1)), "Decode of -1 failed.");
oxAssert(check(int16_t(-1)), "Decode of -1 failed.");
oxAssert(check(int32_t(-1)), "Decode of -1 failed.");
oxAssert(check(int64_t(-1)), "Decode of -1 failed."); oxAssert(check(int64_t(-1)), "Decode of -1 failed.");
oxAssert(check(int64_t(-2)), "Decode of -2 failed."); oxAssert(check(int64_t(-2)), "Decode of -2 failed.");
oxAssert(check(int64_t(-127)), "Decode of -127 failed."); oxAssert(check(int64_t(-127)), "Decode of -127 failed.");
@ -297,14 +304,14 @@ std::map<ox::String, ox::Error(*)()> tests = {
TestStruct testIn; TestStruct testIn;
testIn.Bool = true; testIn.Bool = true;
testIn.Int = 42; testIn.Int = 42;
testIn.BString = "Test String 1"; testIn.IString = "Test String 1";
testIn.List[0] = 1; testIn.List[0] = 1;
testIn.List[1] = 2; testIn.List[1] = 2;
testIn.List[2] = 3; testIn.List[2] = 3;
testIn.List[3] = 4; testIn.List[3] = 4;
testIn.Struct.Bool = true; testIn.Struct.Bool = true;
testIn.Struct.Int = 300; testIn.Struct.Int = 300;
testIn.Struct.BString = "Test String 2"; testIn.Struct.IString = "Test String 2";
testIn.unionIdx = 1; testIn.unionIdx = 1;
testIn.Union.Int = 93; testIn.Union.Int = 93;
oxAssert(ox::writeMC(dataBuff.data(), dataBuff.size(), testIn), "Data generation failed"); oxAssert(ox::writeMC(dataBuff.data(), dataBuff.size(), testIn), "Data generation failed");
@ -313,28 +320,28 @@ std::map<ox::String, ox::Error(*)()> tests = {
oxAssert(typeErr, "Descriptor write failed"); oxAssert(typeErr, "Descriptor write failed");
ox::ModelObject testOut; ox::ModelObject testOut;
oxReturnError(testOut.setType(type)); oxReturnError(testOut.setType(type));
oxAssert(ox::readMC(dataBuff.data(), dataBuff.size(), &testOut), "Data read failed"); oxAssert(ox::readMC(dataBuff, testOut), "Data read failed");
oxAssert(testOut["Int"].get<int>() == testIn.Int, "testOut.Int failed"); oxAssert(testOut.at("Int").unwrap()->get<int>() == testIn.Int, "testOut.Int failed");
oxAssert(testOut["Bool"].get<bool>() == testIn.Bool, "testOut.Bool failed"); oxAssert(testOut.at("Bool").unwrap()->get<bool>() == testIn.Bool, "testOut.Bool failed");
oxAssert(testOut["BString"].get<ox::String>() == testIn.BString.c_str(), "testOut.String failed"); oxAssert(testOut.at("IString").unwrap()->get<ox::String>() == testIn.IString.c_str(), "testOut.String failed");
oxAssert(testOut["String"].get<ox::String>() == testIn.String, "testOut.String failed"); oxAssert(testOut.at("String").unwrap()->get<ox::String>() == testIn.String, "testOut.String failed");
auto &testOutStruct = testOut["Struct"].get<ox::ModelObject>(); auto &testOutStruct = testOut.at("Struct").unwrap()->get<ox::ModelObject>();
auto &testOutUnion = testOut["Union"].get<ox::ModelUnion>(); auto &testOutUnion = testOut.at("Union").unwrap()->get<ox::ModelUnion>();
auto &testOutList = testOut["List"].get<ox::ModelValueVector>(); auto &testOutList = testOut.at("List").unwrap()->get<ox::ModelValueVector>();
auto testOutStructCopy = testOut["Struct"].get<ox::ModelObject>(); auto testOutStructCopy = testOut.at("Struct").unwrap()->get<ox::ModelObject>();
auto testOutUnionCopy = testOut["Union"].get<ox::ModelUnion>(); auto testOutUnionCopy = testOut.at("Union").unwrap()->get<ox::ModelUnion>();
auto testOutListCopy = testOut["List"].get<ox::ModelValueVector>(); auto testOutListCopy = testOut.at("List").unwrap()->get<ox::ModelValueVector>();
oxAssert(testOutStruct.typeName() == TestStructNest::TypeName, "ModelObject TypeName failed"); oxAssert(testOutStruct.typeName() == TestStructNest::TypeName, "ModelObject TypeName failed");
oxAssert(testOutStruct.typeVersion() == TestStructNest::TypeVersion, "ModelObject TypeVersion failed"); oxAssert(testOutStruct.typeVersion() == TestStructNest::TypeVersion, "ModelObject TypeVersion failed");
oxAssert(testOutStruct["Bool"].get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool failed"); oxAssert(testOutStruct.at("Bool").unwrap()->get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool failed");
oxAssert(testOutStruct["BString"].get<ox::String>() == testIn.Struct.BString.c_str(), "testOut.Struct.BString failed"); oxAssert(testOutStruct.at("IString").unwrap()->get<ox::String>() == testIn.Struct.IString.c_str(), "testOut.Struct.IString failed");
oxAssert(testOut["unionIdx"].get<int>() == testIn.unionIdx, "testOut.unionIdx failed"); oxAssert(testOut.at("unionIdx").unwrap()->get<int>() == testIn.unionIdx, "testOut.unionIdx failed");
oxAssert(testOutUnion.unionIdx() == testIn.unionIdx, "testOut.Union idx wrong"); oxAssert(testOutUnion.unionIdx() == testIn.unionIdx, "testOut.Union idx wrong");
oxAssert(testOutUnion["Int"].get<uint32_t>() == testIn.Union.Int, "testOut.Union.Int failed"); oxAssert(testOutUnion.at("Int").unwrap()->get<uint32_t>() == testIn.Union.Int, "testOut.Union.Int failed");
oxAssert(testOutList[0].get<uint32_t>() == testIn.List[0], "testOut.List[0] failed"); oxAssert(testOutList[0].get<uint32_t>() == testIn.List[0], "testOut.List[0] failed");
oxAssert(testOutList[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] failed"); oxAssert(testOutList[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] failed");
oxAssert(testOutStructCopy["Bool"].get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool (copy) failed"); oxAssert(testOutStructCopy.at("Bool").unwrap()->get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool (copy) failed");
oxAssert(testOutStructCopy["BString"].get<ox::String>() == testIn.Struct.BString.c_str(), "testOut.Struct.BString (copy) failed"); oxAssert(testOutStructCopy.at("IString").unwrap()->get<ox::String>() == testIn.Struct.IString.c_str(), "testOut.Struct.IString (copy) failed");
oxAssert(testOutListCopy[0].get<uint32_t>() == testIn.List[0], "testOut.Struct.List[0] (copy) failed"); oxAssert(testOutListCopy[0].get<uint32_t>() == testIn.List[0], "testOut.Struct.List[0] (copy) failed");
oxAssert(testOutListCopy[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] (copy) failed"); oxAssert(testOutListCopy[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] (copy) failed");
return OxError(0); return OxError(0);
@ -351,19 +358,20 @@ std::map<ox::String, ox::Error(*)()> tests = {
TestStruct testIn, testOut; TestStruct testIn, testOut;
testIn.Bool = true; testIn.Bool = true;
testIn.Int = 42; testIn.Int = 42;
testIn.BString = "Test String 1"; testIn.IString = "Test String 1";
testIn.List[0] = 1; testIn.List[0] = 1;
testIn.List[1] = 2; testIn.List[1] = 2;
testIn.List[2] = 3; testIn.List[2] = 3;
testIn.List[3] = 4; testIn.List[3] = 4;
testIn.Struct.Bool = false; testIn.Struct.Bool = false;
testIn.Struct.Int = 300; testIn.Struct.Int = 300;
testIn.Struct.BString = "Test String 2"; testIn.Struct.IString = "Test String 2";
oxAssert(ox::writeMC(dataBuff, dataBuffLen, testIn), "Data generation failed"); oxAssert(ox::writeMC(dataBuff, dataBuffLen, testIn), "Data generation failed");
ox::TypeStore typeStore; ox::TypeStore typeStore;
const auto [type, typeErr] = ox::buildTypeDef(&typeStore, &testIn); const auto [type, typeErr] = ox::buildTypeDef(&typeStore, &testIn);
oxAssert(typeErr, "Descriptor write failed"); oxAssert(typeErr, "Descriptor write failed");
oxReturnError(ox::walkModel<ox::MetalClawReader>(type, dataBuff, dataBuffLen, ox::BufferReader br({dataBuff, dataBuffLen});
oxReturnError(ox::walkModel<ox::MetalClawReader>(type, br,
[](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::String>&, const ox::DescriptorField &f, ox::MetalClawReader *rdr) -> ox::Error { [](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::String>&, const ox::DescriptorField &f, ox::MetalClawReader *rdr) -> ox::Error {
//std::cout << f.fieldName.c_str() << '\n'; //std::cout << f.fieldName.c_str() << '\n';
auto fieldName = f.fieldName.c_str(); auto fieldName = f.fieldName.c_str();
@ -456,11 +464,14 @@ std::map<ox::String, ox::Error(*)()> tests = {
}; };
int main(int argc, const char **args) { int main(int argc, const char **args) {
if (argc > 0) { if (argc < 2) {
auto testName = args[1]; oxError("Must specify test to run");
if (tests.find(testName) != tests.end()) {
oxAssert(tests[testName](), "Test failed...");
}
} }
auto const testName = args[1];
auto const func = tests.find(testName);
if (func != tests.end()) {
oxAssert(func->second(), "Test returned Error");
return 0; return 0;
}
return -1;
} }

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
@ -14,7 +14,7 @@
namespace ox { namespace ox {
using StringLength = uint32_t; using StringLength = std::size_t;
using ArrayLength = uint32_t; using ArrayLength = std::size_t;
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -16,6 +16,7 @@
#include <ox/std/buffer.hpp> #include <ox/std/buffer.hpp>
#include <ox/std/byteswap.hpp> #include <ox/std/byteswap.hpp>
#include <ox/std/hashmap.hpp> #include <ox/std/hashmap.hpp>
#include <ox/std/optional.hpp>
#include <ox/std/string.hpp> #include <ox/std/string.hpp>
#include <ox/std/types.hpp> #include <ox/std/types.hpp>
#include <ox/std/units.hpp> #include <ox/std/units.hpp>
@ -34,47 +35,38 @@ class MetalClawWriter {
ox::Vector<uint8_t, 16> m_presenceMapBuff{}; ox::Vector<uint8_t, 16> m_presenceMapBuff{};
FieldBitmap m_fieldPresence; FieldBitmap m_fieldPresence;
int m_field = 0; int m_field = 0;
int m_unionIdx = -1; ox::Optional<int> m_unionIdx;
std::size_t m_writerBeginP{}; std::size_t m_writerBeginP{};
Writer &m_writer; Writer &m_writer;
public: public:
constexpr explicit MetalClawWriter(Writer &writer, int unionIdx = -1) noexcept; constexpr explicit MetalClawWriter(Writer &writer, ox::Optional<int> const&unionIdx = {}) noexcept;
constexpr ~MetalClawWriter() noexcept = default; constexpr ~MetalClawWriter() noexcept = default;
constexpr Error field(const char*, CommonPtrWith<int8_t> auto *val) noexcept; constexpr Error field(const char*, const int8_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<int16_t> auto *val) noexcept; constexpr Error field(const char*, const int16_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<int32_t> auto *val) noexcept; constexpr Error field(const char*, const int32_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<int64_t> auto *val) noexcept; constexpr Error field(const char*, const int64_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<uint8_t> auto *val) noexcept; constexpr Error field(const char*, const uint8_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<uint16_t> auto *val) noexcept; constexpr Error field(const char*, const uint16_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<uint32_t> auto *val) noexcept; constexpr Error field(const char*, const uint32_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<uint64_t> auto *val) noexcept; constexpr Error field(const char*, const uint64_t *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<bool> auto *val) noexcept; constexpr Error field(const char*, const bool *val) noexcept;
template<typename T> template<typename T>
constexpr Error field(const char*, T *val, std::size_t len) noexcept; constexpr Error field(const char*, const T *val, std::size_t len) noexcept;
template<typename T> template<typename T>
constexpr Error field(const char *name, const HashMap<String, T> *val) noexcept; constexpr Error field(const char *name, const HashMap<String, T> *val) noexcept;
template<typename T>
constexpr Error field(const char*, HashMap<String, T> *val) noexcept;
template<std::size_t SmallStringSize> template<std::size_t SmallStringSize>
constexpr Error field(const char*, const BasicString<SmallStringSize> *val) noexcept; constexpr Error field(const char*, const BasicString<SmallStringSize> *val) noexcept;
template<std::size_t L> template<std::size_t L>
constexpr Error field(const char*, const BString<L> *val) noexcept; constexpr Error field(const char*, const IString<L> *val) noexcept;
template<std::size_t SmallStringSize>
constexpr Error field(const char*, BasicString<SmallStringSize> *val) noexcept;
template<std::size_t L>
constexpr Error field(const char*, BString<L> *val) noexcept;
constexpr Error fieldCString(const char *name, const char *const*val, std::size_t buffLen) noexcept; constexpr Error fieldCString(const char *name, const char *const*val, std::size_t buffLen) noexcept;
@ -84,20 +76,8 @@ class MetalClawWriter {
constexpr Error fieldCString(const char *name, const char *val, std::size_t len) noexcept; constexpr Error fieldCString(const char *name, const char *val, std::size_t len) noexcept;
constexpr Error fieldCString(const char *name, char **val, std::size_t buffLen) noexcept {
return fieldCString(name, const_cast<const char**>(val), buffLen);
}
constexpr Error fieldCString(const char *name, char **val) noexcept {
return fieldCString(name, const_cast<const char**>(val));
}
constexpr Error fieldCString(const char *name, char *val, std::size_t buffLen) noexcept {
return fieldCString(name, const_cast<const char*>(val), buffLen);
}
template<typename T> template<typename T>
constexpr Error field(const char*, T *val) noexcept; constexpr Error field(const char*, const T *val) noexcept;
template<typename U, bool force = false> template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U, force> val) noexcept; constexpr Error field(const char*, UnionView<U, force> val) noexcept;
@ -135,7 +115,7 @@ class MetalClawWriter {
private: private:
constexpr Error appendInteger(Integer_c auto val) noexcept { constexpr Error appendInteger(Integer_c auto val) noexcept {
bool fieldSet = false; bool fieldSet = false;
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) { if (val && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
auto mi = mc::encodeInteger(val); auto mi = mc::encodeInteger(val);
oxReturnError(m_writer.write(reinterpret_cast<const char*>(mi.data), mi.length)); oxReturnError(m_writer.write(reinterpret_cast<const char*>(mi.data), mi.length));
fieldSet = true; fieldSet = true;
@ -151,7 +131,7 @@ extern template class ModelHandlerInterface<MetalClawWriter<BufferWriter>>;
extern template class ModelHandlerInterface<MetalClawWriter<CharBuffWriter>>; extern template class ModelHandlerInterface<MetalClawWriter<CharBuffWriter>>;
template<Writer_c Writer> template<Writer_c Writer>
constexpr MetalClawWriter<Writer>::MetalClawWriter(Writer &writer, int unionIdx) noexcept: constexpr MetalClawWriter<Writer>::MetalClawWriter(Writer &writer, ox::Optional<int> const&unionIdx) noexcept:
m_fieldPresence(m_presenceMapBuff.data(), m_presenceMapBuff.size()), m_fieldPresence(m_presenceMapBuff.data(), m_presenceMapBuff.size()),
m_unionIdx(unionIdx), m_unionIdx(unionIdx),
m_writerBeginP(writer.tellp()), m_writerBeginP(writer.tellp()),
@ -159,48 +139,48 @@ constexpr MetalClawWriter<Writer>::MetalClawWriter(Writer &writer, int unionIdx)
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<int8_t> auto *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const int8_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<int16_t> auto *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const int16_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<int32_t> auto *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const int32_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<int64_t> auto *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const int64_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<uint8_t> auto *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const uint8_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<uint16_t> auto *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const uint16_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<uint32_t> auto *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const uint32_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<uint64_t> auto *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const uint64_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, CommonPtrWith<bool> auto *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const bool *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) { if (!m_unionIdx.has_value() || *m_unionIdx == m_field) {
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), *val)); oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), *val));
} }
++m_field; ++m_field;
@ -211,7 +191,7 @@ template<Writer_c Writer>
template<std::size_t SmallStringSize> template<std::size_t SmallStringSize>
constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<SmallStringSize> *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<SmallStringSize> *val) noexcept {
bool fieldSet = false; bool fieldSet = false;
if (val->len() && (m_unionIdx == -1 || m_unionIdx == m_field)) { if (val->len() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length // write the length
const auto strLen = mc::encodeInteger(val->len()); const auto strLen = mc::encodeInteger(val->len());
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLen.data), strLen.length)); oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLen.data), strLen.length));
@ -226,27 +206,15 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const BasicString<Sm
template<Writer_c Writer> template<Writer_c Writer>
template<std::size_t L> template<std::size_t L>
constexpr Error MetalClawWriter<Writer>::field(const char *name, const BString<L> *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char *name, const IString<L> *val) noexcept {
return fieldCString(name, val->data(), val->cap()); return fieldCString(name, val->data(), val->len());
}
template<Writer_c Writer>
template<std::size_t SmallStringSize>
constexpr Error MetalClawWriter<Writer>::field(const char *name, BasicString<SmallStringSize> *val) noexcept {
return field(name, const_cast<const BasicString<SmallStringSize>*>(val));
}
template<Writer_c Writer>
template<std::size_t L>
constexpr Error MetalClawWriter<Writer>::field(const char *name, BString<L> *val) noexcept {
return fieldCString(name, val->data(), val->cap());
} }
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *const*val, std::size_t) noexcept { constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *const*val, std::size_t) noexcept {
bool fieldSet = false; bool fieldSet = false;
if (m_unionIdx == -1 || m_unionIdx == m_field) { if (!m_unionIdx.has_value() || *m_unionIdx == m_field) {
const auto strLen = *val ? ox_strlen(*val) : 0; const auto strLen = *val ? ox::strlen(*val) : 0;
// write the length // write the length
const auto strLenBuff = mc::encodeInteger(strLen); const auto strLenBuff = mc::encodeInteger(strLen);
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data), strLenBuff.length)); oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data), strLenBuff.length));
@ -272,7 +240,7 @@ constexpr Error MetalClawWriter<Writer>::fieldCString(const char *name, const ch
template<Writer_c Writer> template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *val, std::size_t strLen) noexcept { constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *val, std::size_t strLen) noexcept {
bool fieldSet = false; bool fieldSet = false;
if (strLen && (m_unionIdx == -1 || m_unionIdx == m_field)) { if (strLen && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length // write the length
const auto strLenBuff = mc::encodeInteger(strLen); const auto strLenBuff = mc::encodeInteger(strLen);
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data), strLenBuff.length)); oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data), strLenBuff.length));
@ -287,21 +255,22 @@ constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *v
template<Writer_c Writer> template<Writer_c Writer>
template<typename T> template<typename T>
constexpr Error MetalClawWriter<Writer>::field(const char*, T *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const T *val) noexcept {
if constexpr(isVector_v<T> || isArray_v<T>) { if constexpr(isVector_v<T> || isArray_v<T>) {
return field(nullptr, val->data(), val->size()); return field(nullptr, val->data(), val->size());
} else { } else {
bool fieldSet = false; bool fieldSet = false;
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) { if (val && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
auto const writeIdx = m_writer.tellp();
MetalClawWriter<Writer> writer(m_writer); MetalClawWriter<Writer> writer(m_writer);
ModelHandlerInterface<MetalClawWriter<Writer>> handler{&writer}; ModelHandlerInterface<MetalClawWriter<Writer>> handler{&writer};
oxReturnError(model(&handler, val)); oxReturnError(model(&handler, val));
oxReturnError(writer.finalize()); oxReturnError(writer.finalize());
fieldSet = true; fieldSet = writeIdx != m_writer.tellp();
} }
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field; ++m_field;
return OxError(0); return {};
} }
} }
@ -309,35 +278,37 @@ template<Writer_c Writer>
template<typename U, bool force> template<typename U, bool force>
constexpr Error MetalClawWriter<Writer>::field(const char*, UnionView<U, force> val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, UnionView<U, force> val) noexcept {
bool fieldSet = false; bool fieldSet = false;
if (val.get() && (m_unionIdx == -1 || m_unionIdx == m_field)) { if (val.get() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
MetalClawWriter<Writer> writer(m_writer, val.idx()); auto const writeIdx = m_writer.tellp();
MetalClawWriter<Writer> writer(m_writer, ox::Optional<int>(ox::in_place, val.idx()));
ModelHandlerInterface handler{&writer}; ModelHandlerInterface handler{&writer};
oxReturnError(model(&handler, val.get())); oxReturnError(model(&handler, val.get()));
oxReturnError(writer.finalize()); oxReturnError(writer.finalize());
fieldSet = true; fieldSet = writeIdx != m_writer.tellp();
} }
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field; ++m_field;
return OxError(0); return {};
} }
template<Writer_c Writer> template<Writer_c Writer>
template<typename T> template<typename T>
constexpr Error MetalClawWriter<Writer>::field(const char*, T *val, std::size_t len) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const T *val, std::size_t len) noexcept {
bool fieldSet = false; bool fieldSet = false;
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) { if (len && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length // write the length
const auto arrLen = mc::encodeInteger(len); const auto arrLen = mc::encodeInteger(len);
oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data), arrLen.length)); oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data), arrLen.length));
auto const writeIdx = m_writer.tellp();
MetalClawWriter<Writer> writer(m_writer); MetalClawWriter<Writer> writer(m_writer);
ModelHandlerInterface handler{&writer}; ModelHandlerInterface handler{&writer};
oxReturnError(handler.template setTypeInfo<T>("List", 0, {}, static_cast<std::size_t>(len))); oxReturnError(handler.template setTypeInfo<T>("List", 0, {}, static_cast<std::size_t>(len)));
// write the array // write the array
for (std::size_t i = 0; i < len; i++) { for (std::size_t i = 0; i < len; ++i) {
oxReturnError(handler.field("", &val[i])); oxReturnError(handler.field("", &val[i]));
} }
oxReturnError(writer.finalize()); oxReturnError(writer.finalize());
fieldSet = true; fieldSet = writeIdx != m_writer.tellp();
} }
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field; ++m_field;
@ -350,7 +321,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String
const auto &keys = val->keys(); const auto &keys = val->keys();
const auto len = keys.size(); const auto len = keys.size();
bool fieldSet = false; bool fieldSet = false;
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) { if (len && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length // write the length
const auto arrLen = mc::encodeInteger(len); const auto arrLen = mc::encodeInteger(len);
oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data), arrLen.length)); oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data), arrLen.length));
@ -359,15 +330,19 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String
ModelHandlerInterface handler{&writer}; ModelHandlerInterface handler{&writer};
// double len for both key and value // double len for both key and value
oxReturnError(handler.setTypeInfo("Map", 0, {}, len * 2)); oxReturnError(handler.setTypeInfo("Map", 0, {}, len * 2));
// write the array // this loop body needs to be in a lambda because of the potential alloca call
for (std::size_t i = 0; i < len; i++) { constexpr auto loopBody = [](auto &handler, auto const&key, auto const&val) -> ox::Error {
const auto &key = keys[i]; const auto keyLen = key.len();
const auto keyLen = ox_strlen(key);
auto wkey = ox_malloca(keyLen + 1, char, 0); auto wkey = ox_malloca(keyLen + 1, char, 0);
memcpy(wkey, key.c_str(), keyLen + 1); memcpy(wkey.get(), key.c_str(), keyLen + 1);
oxReturnError(handler.fieldCString("", wkey.get(), keyLen)); oxReturnError(handler.fieldCString("", wkey.get(), keyLen));
oxRequireM(value, val->at(key)); oxRequireM(value, val.at(key));
oxReturnError(handler.field("", value)); return handler.field("", value);
};
// write the array
for (std::size_t i = 0; i < len; ++i) {
auto const&key = keys[i];
oxReturnError(loopBody(handler, key, *val));
} }
oxReturnError(writer.finalize()); oxReturnError(writer.finalize());
fieldSet = true; fieldSet = true;
@ -377,12 +352,6 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String
return OxError(0); return OxError(0);
} }
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter<Writer>::field(const char *name, HashMap<String, T> *val) noexcept {
return field(name, const_cast<const HashMap<String, T>*>(val));
}
template<Writer_c Writer> template<Writer_c Writer>
template<typename T> template<typename T>
constexpr ox::Error MetalClawWriter<Writer>::setTypeInfo( constexpr ox::Error MetalClawWriter<Writer>::setTypeInfo(
@ -417,7 +386,7 @@ Result<Buffer> writeMC(Writer_c auto &writer, const auto &val) noexcept {
return {}; return {};
} }
Result<Buffer> writeMC(const auto &val, std::size_t buffReserveSz = 2 * units::KB) noexcept { Result<Buffer> writeMC(auto const&val, std::size_t buffReserveSz = 2 * units::KB) noexcept {
Buffer buff(buffReserveSz); Buffer buff(buffReserveSz);
BufferWriter bw(&buff, 0); BufferWriter bw(&buff, 0);
oxReturnError(writeMC(bw, val)); oxReturnError(writeMC(bw, val));
@ -425,7 +394,7 @@ Result<Buffer> writeMC(const auto &val, std::size_t buffReserveSz = 2 * units::K
return buff; return buff;
} }
Error writeMC(char *buff, std::size_t buffLen, const auto &val, std::size_t *sizeOut = nullptr) noexcept { Error writeMC(char *buff, std::size_t buffLen, auto const&val, std::size_t *sizeOut = nullptr) noexcept {
CharBuffWriter bw(buff, buffLen); CharBuffWriter bw(buff, buffLen);
oxReturnError(writeMC(bw, val)); oxReturnError(writeMC(bw, val));
if (sizeOut) { if (sizeOut) {

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -13,5 +13,5 @@
#define oxModelBegin(modelName) constexpr ox::Error model(auto *io, [[maybe_unused]] ox::CommonPtrWith<modelName> auto *o) noexcept { oxReturnError(io->template setTypeInfo<modelName>()); #define oxModelBegin(modelName) constexpr ox::Error model(auto *io, [[maybe_unused]] ox::CommonPtrWith<modelName> auto *o) noexcept { oxReturnError(io->template setTypeInfo<modelName>());
#define oxModelEnd() return OxError(0); } #define oxModelEnd() return OxError(0); }
#define oxModelField(fieldName) oxReturnError(io->field(#fieldName, &o->fieldName)); #define oxModelField(fieldName) oxReturnError(io->field(#fieldName, &o->fieldName));
#define oxModelFieldRename(serFieldName, objFieldName) oxReturnError(io->field(#serFieldName, &o->objFieldName)); #define oxModelFieldRename(objFieldName, serFieldName) oxReturnError(io->field(#serFieldName, &o->objFieldName));
#define oxModelFriend(modelName) friend constexpr ox::Error model(auto*, ox::CommonPtrWith<modelName> auto*) noexcept #define oxModelFriend(modelName) friend constexpr ox::Error model(auto*, ox::CommonPtrWith<modelName> auto*) noexcept

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once

View File

@ -1,9 +1,9 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#include "desctypes.hpp" #include "desctypes.hpp"

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -37,12 +37,12 @@ constexpr auto buildTypeId() noexcept {
static constexpr auto buildTypeId(CRStringView name, int version, static constexpr auto buildTypeId(CRStringView name, int version,
const TypeParamPack &typeParams = {}) noexcept { const TypeParamPack &typeParams = {}) noexcept {
String tp; String tp;
if (typeParams.size()) { if (!typeParams.empty()) {
tp = "#"; tp = "#";
for (const auto &p : typeParams) { for (const auto &p : typeParams) {
tp += p + ","; tp += p + ",";
} }
tp = tp.substr(0, tp.len() - 1); tp.resize(tp.len() - 1);
tp += "#"; tp += "#";
} }
return ox::sfmt("{}{};{}", name, tp, version); return ox::sfmt("{}{};{}", name, tp, version);

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
@ -9,7 +9,7 @@
#pragma once #pragma once
#include <ox/std/byteswap.hpp> #include <ox/std/byteswap.hpp>
#include <ox/std/bstring.hpp> #include <ox/std/istring.hpp>
#include <ox/std/memory.hpp> #include <ox/std/memory.hpp>
#include <ox/std/string.hpp> #include <ox/std/string.hpp>
#include <ox/std/trace.hpp> #include <ox/std/trace.hpp>
@ -152,7 +152,7 @@ class TypeDescWriter {
template<std::size_t sz> template<std::size_t sz>
[[nodiscard]] [[nodiscard]]
constexpr const DescriptorType *type(const BString<sz> *val) const noexcept; constexpr const DescriptorType *type(const IString<sz> *val) const noexcept;
template<typename T> template<typename T>
[[nodiscard]] [[nodiscard]]
@ -175,7 +175,8 @@ class TypeDescWriter {
constexpr TypeDescWriter::TypeDescWriter(TypeStore *typeStore) noexcept: m_typeStore(typeStore) {} constexpr TypeDescWriter::TypeDescWriter(TypeStore *typeStore) noexcept: m_typeStore(typeStore) {}
template<typename T> template<typename T>
constexpr ox::Error TypeDescWriter::setTypeInfo(CRStringView typeName, int typeVersion, constexpr ox::Error TypeDescWriter::setTypeInfo(
CRStringView typeName, int typeVersion,
const TypeParamPack &typeParams, std::size_t) noexcept { const TypeParamPack &typeParams, std::size_t) noexcept {
PrimitiveType pt; PrimitiveType pt;
if constexpr(is_union_v<T>) { if constexpr(is_union_v<T>) {
@ -197,7 +198,7 @@ constexpr Error TypeDescWriter::field(CRStringView name, const T*, std::size_t,
constexpr typename remove_pointer<T>::type *p = nullptr; constexpr typename remove_pointer<T>::type *p = nullptr;
const auto t = type(p); const auto t = type(p);
oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated"); oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated");
m_type->fieldList.emplace_back(t, name, detail::indirectionLevels_v<T> + 1, subscriptStack, buildTypeId(*t)); m_type->fieldList.emplace_back(t, String(name), detail::indirectionLevels_v<T> + 1, subscriptStack, buildTypeId(*t));
return OxError(0); return OxError(0);
} }
return OxError(1); return OxError(1);
@ -208,7 +209,7 @@ constexpr Error TypeDescWriter::field(CRStringView name, UnionView<T, force> val
if (m_type) { if (m_type) {
const auto t = type(val); const auto t = type(val);
oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated"); oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated");
m_type->fieldList.emplace_back(t, name, 0, SubscriptStack{}, t->typeName); m_type->fieldList.emplace_back(t, String(name), 0, SubscriptStack{}, ox::String(t->typeName));
return OxError(0); return OxError(0);
} }
return OxError(1); return OxError(1);
@ -218,15 +219,17 @@ template<typename T>
constexpr Error TypeDescWriter::field(CRStringView name, const T *val) noexcept { constexpr Error TypeDescWriter::field(CRStringView name, const T *val) noexcept {
if (m_type) { if (m_type) {
if constexpr(isVector_v<T> || isArray_v<T>) { if constexpr(isVector_v<T> || isArray_v<T>) {
return field(name, val->data(), 0, detail::buildSubscriptStack(val)); typename T::value_type *data = nullptr;
return field(name, data, 0, detail::buildSubscriptStack(val));
} else if constexpr(isSmartPtr_v<T>) { } else if constexpr(isSmartPtr_v<T>) {
return field(name, val->get(), 0, detail::buildSubscriptStack(val)); typename T::value_type *data = nullptr;
return field(name, data, 0, detail::buildSubscriptStack(val));
} else if constexpr(is_pointer_v<T>) { } else if constexpr(is_pointer_v<T>) {
return field(name, val, 0, detail::buildSubscriptStack(val)); return field(name, val, 0, detail::buildSubscriptStack(val));
} else { } else {
const auto t = type(val); const auto t = type(val);
oxAssert(t != nullptr, "field(const char *name, T *val): Type not found or generated"); oxAssert(t != nullptr, "field(const char *name, T *val): Type not found or generated");
m_type->fieldList.emplace_back(t, name, 0, SubscriptStack{}, buildTypeId(*t)); m_type->fieldList.emplace_back(t, String(name), 0, SubscriptStack{}, buildTypeId(*t));
return {}; return {};
} }
} }
@ -237,7 +240,7 @@ template<typename ...Args>
constexpr Error TypeDescWriter::fieldCString(CRStringView name, Args&&...) noexcept { constexpr Error TypeDescWriter::fieldCString(CRStringView name, Args&&...) noexcept {
constexpr auto s = ""; constexpr auto s = "";
const auto t = type(s); const auto t = type(s);
m_type->fieldList.emplace_back(t, name, 0, SubscriptStack{}, t->typeName); m_type->fieldList.emplace_back(t, String(name), 0, SubscriptStack{}, ox::String(t->typeName));
return {}; return {};
} }
@ -331,7 +334,7 @@ constexpr const DescriptorType *TypeDescWriter::type(const char*) const noexcept
} }
template<std::size_t sz> template<std::size_t sz>
constexpr const DescriptorType *TypeDescWriter::type(const BString<sz>*) const noexcept { constexpr const DescriptorType *TypeDescWriter::type(const IString<sz>*) const noexcept {
constexpr auto PT = PrimitiveType::String; constexpr auto PT = PrimitiveType::String;
return getType(types::BString, 0, PT, 0); return getType(types::BString, 0, PT, 0);
} }
@ -344,7 +347,7 @@ constexpr const DescriptorType *TypeDescWriter::getType(CRStringView tn, int typ
oxAssert(type != nullptr, "TypeDescWriter::getType returning null DescriptorType"); oxAssert(type != nullptr, "TypeDescWriter::getType returning null DescriptorType");
return type; return type;
} else { } else {
auto dt = ox::make_unique<DescriptorType>(tn, typeVersion, pt, typeParams); auto dt = ox::make_unique<DescriptorType>(String(tn), typeVersion, pt, typeParams);
dt->length = b; dt->length = b;
const auto out = dt.get(); const auto out = dt.get();
const auto typeId = buildTypeId(tn, typeVersion, typeParams); const auto typeId = buildTypeId(tn, typeVersion, typeParams);
@ -356,15 +359,15 @@ constexpr const DescriptorType *TypeDescWriter::getType(CRStringView tn, int typ
template<typename T> template<typename T>
constexpr Result<DescriptorType*> buildTypeDef(TypeStore *typeStore) noexcept { constexpr Result<DescriptorType*> buildTypeDef(TypeStore *typeStore) noexcept {
TypeDescWriter writer(typeStore); TypeDescWriter writer(typeStore);
ModelHandlerInterface handler(&writer); ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(&writer);
if (std::is_constant_evaluated()) { if (std::is_constant_evaluated()) {
std::allocator<T> a; std::allocator<T> a;
T *t = a.allocate(1); T *t = a.allocate(1);
oxReturnError(model(&handler, t)); oxReturnError(model(&handler, t));
a.deallocate(t, 1); a.deallocate(t, 1);
} else { } else {
T *t = reinterpret_cast<T*>(ox_alloca(sizeof(T))); auto t = ox_malloca(sizeof(T), T);
oxReturnError(model(&handler, t)); oxReturnError(model(&handler, t.get()));
} }
return writer.definition(); return writer.definition();
} }
@ -372,7 +375,7 @@ constexpr Result<DescriptorType*> buildTypeDef(TypeStore *typeStore) noexcept {
template<typename T> template<typename T>
constexpr Result<DescriptorType*> buildTypeDef(TypeStore *typeStore, T *val) noexcept { constexpr Result<DescriptorType*> buildTypeDef(TypeStore *typeStore, T *val) noexcept {
TypeDescWriter writer(typeStore); TypeDescWriter writer(typeStore);
ModelHandlerInterface handler(&writer); ModelHandlerInterface<TypeDescWriter, ox::OpType::Reflect> handler(&writer);
oxReturnError(model(&handler, val)); oxReturnError(model(&handler, val));
return writer.definition(); return writer.definition();
} }

View File

@ -1,5 +1,5 @@
/* /*
* Copyright 2015 - 2023 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this

View File

@ -1,15 +1,15 @@
/* /*
* Copyright 2015 - 2022 gary@drinkingtea.net * Copyright 2015 - 2024 gary@drinkingtea.net
* *
* This Source Code Form is subject to the terms of the Mozilla Public * This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this * License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/ */
#pragma once #pragma once
#include <ox/std/byteswap.hpp> #include <ox/std/byteswap.hpp>
#include <ox/std/bstring.hpp> #include <ox/std/istring.hpp>
#include <ox/std/memory.hpp> #include <ox/std/memory.hpp>
#include <ox/std/string.hpp> #include <ox/std/string.hpp>
#include <ox/std/trace.hpp> #include <ox/std/trace.hpp>

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