Compare commits

..

738 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
39eb82596b [nostalgia/core,turbine] Give Turbine and NostalgiaCore Context types virtual destructors 2023-06-27 19:38:16 -05:00
de6308418e [studio] Add GlUtils as Studio dependency 2023-06-27 19:15:59 -05:00
7755168004 [ox/logconn] Change some C strings to StringViews, add macro for initializing logger 2023-06-26 23:58:10 -05:00
cf5786a4ed [ox/std] Change InitTraceMsg::appName from C string to BString<128> 2023-06-26 23:57:17 -05:00
874592cffd [nostalgia/core] Cleanup 2023-06-26 23:51:23 -05:00
741026680a [ox/std] Add Result::to for passing value to functions 2023-06-25 17:21:56 -05:00
822090f309 [ox/std] Make Vector functions also noexcept for pointers 2023-06-25 17:21:29 -05:00
696bae0721 [nostalgia/core/gba] Cleanup 2023-06-25 17:12:14 -05:00
07fb60ed3d [nostalgia/core] Add a function for resizing tile sheets 2023-06-25 17:11:18 -05:00
341217b78e [nostalgia] Make run commands not require install 2023-06-24 12:41:41 -05:00
56f2533754 [nostalgia/core/studio] Cleanup reinterpret_cast 2023-06-24 12:38:39 -05:00
3a149fad6d [nostalgia/core/studio] Fix scaling of controls panel in TileSheetEditorImGui 2023-06-24 00:16:38 -05:00
de50a5392a [keel] Make keel init not be a template anymore 2023-06-20 19:27:36 -05:00
c5233e0d1d [keel,nostalgia,studio,turbine] Make turbine::Context have a keel::Context instead of being one 2023-06-20 00:56:55 -05:00
d4eaade326 [studio] Make all libraries and includes install correctly 2023-06-19 23:37:37 -05:00
690935e4ec [nostalgia/core] Cleanup 2023-06-19 20:28:27 -05:00
56e980385c [nostalgia,turbine] Make GBA files (other than ARM asm) build on all platforms 2023-06-18 23:03:06 -05:00
7c1c9a697e [teagba] Make TeaGBA (other than the ARM asm) build on all platforms 2023-06-18 22:59:01 -05:00
bac3eed958 [nostalgia/scene] Cleanup 2023-06-18 20:28:08 -05:00
de45e7a075 [nostalgia/core/opengl] Cleanup 2023-06-18 17:58:01 -05:00
0f797a17d5 [studio] Make clear screen before redraw 2023-06-18 17:56:01 -05:00
47858ef619 [studio] Fix crash in NewMenu 2023-06-18 17:54:34 -05:00
a95aae2b68 [nostalgia/scene] Delete duplicate keelmodule.cpp 2023-06-18 17:36:10 -05:00
50e0dd4c8e [nostalgia/player] Fix GBA debug build 2023-06-18 10:23:41 -05:00
969914ce41 [keel] Add convert function to bare metal build so that the symbol is available 2023-06-18 10:23:00 -05:00
9ba13b17b1 [nostalgia/scene] Make Scene::setupDisplay const 2023-06-18 01:40:34 -05:00
7437487340 [ox/std] Make many Vector functions conditionally noexcept 2023-06-18 01:39:35 -05:00
7a0312ba91 [nostalgia] CMake cleanup, install studiomodules.hpp 2023-06-17 21:24:19 -05:00
bb694b9b13 [nostalgia] CMake cleanup 2023-06-17 20:53:08 -05:00
76a8499630 [nostalgia] Cleanup Keel modules 2023-06-17 20:52:44 -05:00
6680ffa7a8 [keel] Make most of pack build regardless of platform 2023-06-17 20:51:36 -05:00
04cb710d56 [glutils,keel,nostalgia,turbine] Cleanup sign conversion warnings that are now enabled universal 2023-06-17 20:03:45 -05:00
2974fa5863 [nostalgia] Reorganize Keel components of modules into own directories 2023-06-17 19:37:34 -05:00
ecde759bec [nostalgia] Move modules into modules directory 2023-06-17 17:22:56 -05:00
dd54e7363f [nostalgia/core] Cleanup 2023-06-17 16:21:35 -05:00
bde511dd85 [teagba] Wrap BIOS functions in namespaced C++ functions 2023-06-17 16:20:56 -05:00
32df55ea43 [buildcore] Make configure-xcode only available on Mac 2023-06-15 19:49:05 -05:00
cbb67c51ef [keel] Cleanup 2023-06-14 00:05:41 -05:00
ba50b083ff [nostalgia,studio] Update for Ox changes, cleanup 2023-06-14 00:05:24 -05:00
dde51151ff [ox] Cleanup Vector 2023-06-13 23:51:13 -05:00
20e5b7e617 [ox/std] Fix code duplication 2023-06-10 01:15:55 -05:00
bb85e6ab6c [ox/std] Add UUID::toString variant that takes a Writer_c 2023-06-09 22:07:19 -05:00
fb43c956e7 [keel] Cleanup 2023-06-09 22:06:16 -05:00
952a2f153e [nostalgia,keel] Update for Ox changes 2023-06-09 21:15:22 -05:00
b67359ddb0 [ox] Make StringView write function take a Writer_c reference 2023-06-09 21:14:28 -05:00
b2103e558e [ox/mc] Make write's setTypeInfo return Error if unable to allocate field presence buff 2023-06-09 20:53:20 -05:00
fbfc0afc89 [nostalgia/core/gba] Update for Ox changes 2023-06-09 20:50:10 -05:00
e22743961a [ox] Make model system's setTypeInfo return an Error 2023-06-09 20:49:36 -05:00
7c3aaf99c2 [keel] Update for Ox changes 2023-06-08 22:13:38 -05:00
5a021043f4 [ox] Make OC and Claw writers take const values 2023-06-08 21:57:43 -05:00
23054c9f6f [ox] Remove SerStr 2023-06-08 21:34:33 -05:00
e0289ee7e0 [keel,studio] Update for Ox changes 2023-06-08 21:18:30 -05:00
2c8e073172 [ox] Cleanup serialization writers, make MC and Claw use Writer_c 2023-06-08 21:18:26 -05:00
6f5f2c7219 [ox/mc] Make writeOC work with const inputs 2023-06-08 01:13:24 -05:00
ce4dcdcd18 [ox/mc] Make MC Write use Writer_c 2023-06-08 00:56:02 -05:00
ae3f0bb5db [teagba] Fix type conversions 2023-06-07 21:14:39 -05:00
f5b1da09b5 [nostalgia/core/opengl] Fix type conversion 2023-06-07 21:11:54 -05:00
d0579014d8 [buildcore] Enable implicit type conversion warnings 2023-06-07 00:42:01 -05:00
aa19cdf535 [keel,nostalgia,studio] Fix implicit conversions 2023-06-07 00:41:31 -05:00
3fdfee33a9 [ox] Fix remaining implicit conversion issues 2023-06-07 00:41:09 -05:00
acf04665bc [ox/fs] Cleanup formatting 2023-06-06 00:29:17 -05:00
13b2df57fe [glutils,nostalgia,studio] Fix Xcode build errors 2023-06-06 00:28:22 -05:00
7bccfc8a00 [ox] Fix Xcode build errors 2023-06-06 00:17:51 -05:00
4549569746 [nostalgia/core/studio] Fix pixel line grid scaling on zoom 2023-06-06 00:09:49 -05:00
aff3b04fe2 [buildcore] Make cmake-build command ignore build directories that are not directories 2023-06-05 21:17:50 -05:00
f8eaf9b325 [nostalgia/core] Make Context::turbineCtx private 2023-06-04 09:48:04 -05:00
1bff41d9f1 [nostalgia/core] Cleanup 2023-06-03 23:45:20 -05:00
2887fa7819 [nostaliga] Cleanup 2023-06-03 22:06:08 -05:00
8c7f6ffafc [ox/fs] Make directAccess functions const 2023-06-03 22:04:02 -05:00
5dd3b678ae [nostalgia/core] Delete all of core::Context's friendships 2023-06-03 21:20:04 -05:00
7d0dcae00e [nostalgia,turbine] Change NOSTALGIA_BUILD_TYPE to TURBINE_BUILD_TYPE 2023-06-03 20:51:18 -05:00
65268408cd [turbine] Remove default appName 2023-06-03 20:40:26 -05:00
ff242e3488 [studio] Put StudioAppLib in studio namespace 2023-06-03 19:35:40 -05:00
6137a2b892 [studio/modlib] Fix Linux build 2023-06-03 19:29:02 -05:00
1097990113 [turbine/gba] Change isr to turbine_isr 2023-06-03 16:50:31 -05:00
c6706f743d [nostalgia] Cleanup 2023-06-03 16:34:01 -05:00
e1a8c6de01 [nostalgia/core/studio] Cleanup module 2023-06-03 15:50:20 -05:00
8d07f6110e [keel] Replace last Nostalgia reference in Keel 2023-06-03 15:44:08 -05:00
6f4b869fa2 [keel] Fix string comparison bug in K1 header check 2023-06-03 15:43:38 -05:00
ed169eb9b8 [nostalgia,studio] Make module handling consistent 2023-06-03 15:36:28 -05:00
2874620bc6 [nostalgia] Add .clang-tidy 2023-06-03 14:36:41 -05:00
fee0a73b0d [nostalgia/core/opengl] Cleanup 2023-06-03 12:44:35 -05:00
10d1e860bb [nostalgia,studio] Make studio a library 2023-06-03 12:42:13 -05:00
6593d429fe [nostaliga,turbine] Move rest of ImGui init to Turbine 2023-06-03 12:41:52 -05:00
37f6c388fc [nostaliga/studio] Remove old studio profiles 2023-06-02 20:30:43 -05:00
25954d5503 [ox/std] Make stacktrace code more readable 2023-06-02 20:29:58 -05:00
68b6942606 [nostalgia/scene/studio] Replace glutils::bind with glutils::FrameBufferBind 2023-06-02 20:29:17 -05:00
ce2ac2e29e [nostalgia/appmodules] Cleanup 2023-06-02 20:28:45 -05:00
536f0ee8b7 [glutils] Fix FrameBufferBind unbind to no frame buffer 2023-06-02 20:28:26 -05:00
e1a1938762 [nostalgia/studio] Update year in Info.plist 2023-06-02 20:16:04 -05:00
1741822ba0 [nostalgia/studio] Replace NostalgiaCore with Turbine as NostalgiaStudio dependency 2023-06-02 20:15:49 -05:00
be7b32906f [nostalgia/studio] Move BuiltinModules to a cpp file 2023-06-02 20:14:51 -05:00
db3f29d52f [nostalgia] Make drawMainView render size seting come from function param 2023-06-02 00:55:57 -05:00
022f148701 [teagba] Make install library 2023-06-02 00:21:41 -05:00
b484d601e5 [glutils] Make static lib instead of object lib 2023-06-02 00:06:37 -05:00
60aad6335c [keel] Enable sign-conversion warning 2023-06-02 00:00:39 -05:00
8cd2ef2d8b [nostalgia] Move GlUtils out of Nostalgia 2023-06-01 23:58:39 -05:00
5c8242490e [ox] Make panic always print message 2023-06-01 23:48:39 -05:00
4364911229 [nostalgia,keel] Move core::TypeStore to Keel 2023-06-01 23:43:19 -05:00
1d35f6ce70 [nostalgia/core/studio] Remove old unused files 2023-06-01 23:27:07 -05:00
8c43baedea [nostalgia] Break part of core out into Turbine and TeaGBA libraries 2023-06-01 23:22:31 -05:00
07284ac595 [ox/std] Cleanup geo types to not depend on ox/model 2023-06-01 23:19:51 -05:00
437b33cdb5 [nostalgia] Remove anti-references policy from dev handbook 2023-05-30 20:55:20 -05:00
d598efb5ea [ox] Put oxReturnError and oxThrowError in brackets 2023-05-30 20:51:54 -05:00
fa4e3c6329 [ox] Cleanup 2023-05-30 20:50:47 -05:00
90ef5866dd [ox] Add makeCatch function 2023-05-30 20:49:57 -05:00
03a1a8abca [nostalgia] Move geo types to Ox 2023-05-30 20:44:22 -05:00
4e0ce57594 [ox/std] Add geo types 2023-05-30 20:43:39 -05:00
220f272867 [nostalgia/scene/studio] Cleanup 2023-05-30 20:01:56 -05:00
79e6838ab3 [nostalgia/studio] Make file open error report which file failed to open 2023-05-30 19:58:52 -05:00
78eeb30b15 [nostalgia/glutils] Add bind(FrameBuffer) function 2023-05-30 19:42:05 -05:00
8679f6b5a3 [nostalgia/core] Make core::setMainViewEnabled take a Context 2023-05-25 00:37:43 -05:00
323d5d8d53 [nostalgia/core] Cleanup 2023-05-24 20:43:00 -05:00
bd665cfc35 [ox] GCC13 fix 2023-05-19 21:35:00 -05:00
fcf0a9be95 [ox] Fix for a broken new memory safety check in GCC13 2023-05-19 21:32:18 -05:00
f63fe6c995 [nostalgia/core] Cleanup 2023-05-16 21:20:07 -05:00
2c7e134606 [keel,nostalgia] Remove keel and nostalgia subdirs in lib install path 2023-04-19 23:21:52 -05:00
dd12509d7d [glfw] Make GLFW an object library 2023-04-19 23:17:55 -05:00
546ce9b253 [ox] Get rid of ox subdirectory in lib install path 2023-04-19 20:45:18 -05:00
fddc6c2d04 [keel] Cleanup 2023-04-05 01:41:06 -05:00
7194f81b5b [keel] Make Keel preload functions templates to allow for different plat specs 2023-04-05 01:37:10 -05:00
9af8530e24 [ox/std] Cleanup 2023-04-02 09:42:49 -05:00
b8c0bbe03a [ox] Switch Mac to use builtin bit_cast 2023-04-01 23:23:36 -05:00
a36a642cf5 [keel] Change Nostalgia media and preload headers to Keel 2023-04-01 20:29:24 -05:00
834d01226d [keel] Cleanup 2023-04-01 20:18:16 -05:00
651db7a842 [nostalgia] Fix pkg-gba to use uname -n instead of hostname 2023-04-01 19:52:03 -05:00
b56d3692d0 [keel] Make PreloadPtr 64 bit 2023-04-01 19:51:31 -05:00
2a8f7e074f [keel] Fix PreloadPtr type id 2023-04-01 19:19:43 -05:00
bccc58c463 [keel] Fix variable name 2023-04-01 19:16:34 -05:00
272aba8eb5 [nostalgia/sample_project] Change Nostalgia headers to Keel headers 2023-04-01 19:12:37 -05:00
ab7dd9189e [keel] Cleanup headers 2023-04-01 19:12:33 -05:00
7beb3cc6fc [keel] Split out Nostalgia Foundation and Pack lib into Keel 2023-03-24 21:26:17 -05:00
4a95a79926 [nostalgia/scene] ACTUALLY add Scene Studio module 2023-03-11 18:45:35 -06:00
986ee3d7b0 [nostalgia/tools/pack] Fix build 2023-03-11 18:18:41 -06:00
ae9272841f [nostalgia] Add start for Scene editor in Studio 2023-03-11 16:59:26 -06:00
19d5641c6e [ox/oc] Fix unnecessary copy 2023-03-11 16:57:04 -06:00
21131a35a3 [ox/preloader] Cleanup NativePlatSpec 2023-03-11 16:56:44 -06:00
b58431c09a [ox/std] Add all_of and any_of range functions, cleanup 2023-03-11 16:46:17 -06:00
488f73f60f [nostalgia/core/studio] Cleanup, make FrameBuffer resize use resizeInitFrameBuffer 2023-03-11 15:00:04 -06:00
a5547487f8 [nostalgia/glutils] Add resizeInitFrameBuffer function, cleanup inconsistent argument names 2023-03-11 14:53:55 -06:00
9583b223ca [ox/std] Add test for non-constexpr version of UUID::isNull() 2023-03-04 16:12:51 -06:00
aab02f25c0 [ox/std] Updated UUID test for changed random num gen 2023-03-04 02:49:52 -06:00
c75ff7881f [ox/std] Add UUID::isNull() 2023-03-03 23:24:38 -06:00
3510e38ae5 [nostalgia/core] Rename userland to opengl 2023-03-03 01:13:38 -06:00
06f6656c85 [ox/std] Shift away 4 lowest bits of random numbers generated in UUID,
as Xoroshiro128+ is apparently weaker for those bits
2023-03-03 00:57:25 -06:00
b576a7ec12 [nostalgia/appmodules] Cleanup 2023-03-01 00:16:19 -06:00
8c1ad5ed63 [nostalgia/foundation] Removed unused member from AssetContainer 2023-02-28 00:45:10 -06:00
e9965a63ce [nostalgia/tools/pack] Update for GbaPlatSpec for preloader cleanup 2023-02-25 22:25:43 -06:00
317e714373 [ox/preloader] Cleanup 2023-02-25 22:25:14 -06:00
1767821161 [ox/std] Fix various issues with Optional copy and move constructors 2023-02-19 16:48:35 -06:00
edd21017d3 [ox/std] Make Optional more like std::optional 2023-02-19 01:40:29 -06:00
2e051f947d [ox/mc,oc] Add support for ox::Array serialization 2023-02-18 17:07:14 -06:00
58b7f813cc [nostalgia/core/studio] Make Edit Subsheet popup close on escape press 2023-02-18 00:52:49 -06:00
762804905a [ox] Make UUID serializable, and make serialize as a string in OC 2023-02-16 01:36:20 -06:00
b53e8626d7 [nostalgia/core/studio] Make TileSheets use UUIDs to refer to Palettes 2023-02-14 00:45:56 -06:00
71354fcbbc [nostalgia] Fix the initialization of UUIDs for new assets 2023-02-13 23:16:41 -06:00
044a87b1c4 [nostalgia/studio] Seed UUID generator at the start of Studio 2023-02-13 21:55:19 -06:00
53229b05da [nostalgia] Fix to allow building UUID map later 2023-02-13 21:45:54 -06:00
d17f536832 [ox/std] Add write(Writer_c, StringView) 2023-02-13 21:35:37 -06:00
b6ed919b01 [ox/std] Fix ox::join to work with list types that done have a front function 2023-02-13 19:08:46 -06:00
777a6d54f0 [ox/std] Add test for UUID::generate() and fix bug 2023-02-13 19:08:04 -06:00
86a3bf1248 [nostalgia] Make assets loadable through UUID references 2023-02-13 19:00:25 -06:00
a96d173fdc [ox/std] Fix BString(StringView) constructor 2023-02-12 22:30:28 -06:00
5e43eff631 [nostalgia] Add UUID to file path mapping 2023-02-12 22:13:32 -06:00
ba7ee92ad2 [ox/fs] Add error messgae to PassthroughFS::statPath 2023-02-12 21:45:18 -06:00
6d4c57d37d [ox/std] Fix BString == and != operators 2023-02-12 21:14:16 -06:00
54eebf81da [ox/std] Add UUID str conv test and fix bugs found 2023-02-12 20:38:29 -06:00
1b7b6e306e [nostalgia] Add support for asset UUID headers 2023-02-12 00:02:41 -06:00
2b821b73ff [ox/std] Add UUID fromString 2023-02-12 00:02:07 -06:00
e19559d7a7 [ox/claw] Add non-ox::Buffer version of readClaw function 2023-02-11 23:59:37 -06:00
af3de01e1b [ox/preloader] clang-tidy fix 2023-02-11 23:56:03 -06:00
9561a68483 [ox/std] Fix BString assign and compare 2023-02-11 02:32:24 -06:00
08899074cf [nostalgia/studio] Add Module types to Project TypeStore 2023-02-09 01:21:12 -06:00
86f639c7f7 [ox/std] Add tests for UUID int to hex str conversion 2023-02-08 21:40:29 -06:00
014daa6b57 [nostalgia/core/userland] Fix magic numbers 2023-02-08 21:37:25 -06:00
4f906f6e47 [ox/std] Add UUID implementation 2023-02-08 21:37:17 -06:00
3b05d4e16b [nostalgia] Add type registration to Module, fix FileAddress conversion in vectors for nost-pack 2023-02-08 03:06:57 -06:00
dba31d2cd9 [ox/model] Fix ModelUnion to copy type on copy and move 2023-02-07 23:19:18 -06:00
8077aaf0ae [nostalgia] Fill out basic Scene system functionality 2023-02-07 23:17:58 -06:00
eb55144211 [ox/std] Make ox::min/max use values instead of refs for integrals, add CommonRefWith 2023-02-07 01:35:50 -06:00
5de5eee215 [ox/std] Fix alignment of Optional's buffer 2023-02-07 01:33:30 -06:00
d571d49cce [ox/std] Fix String to StringView compare 2023-02-07 01:30:59 -06:00
6769bb63d9 [ox/std] Fix Optional 2023-02-06 22:43:30 -06:00
b064239ab1 [nostalgia] Remove World package 2023-02-06 00:18:16 -06:00
24ea7fee39 [nostalgia] Update liccor file 2023-02-06 00:17:24 -06:00
8a4ce3c8f1 [nostalgia/foundation] Fix CMake install 2023-02-05 02:25:22 -06:00
3c9e6d10ea [ox/std] Add StringView split and find functions 2023-02-05 00:33:27 -06:00
4b9b70a90e [nostalgia] Remove .trace.json 2023-02-04 16:57:28 -06:00
4ddf7a88c9 [nostalgia/foundation] Make transformRule include type params in type id 2023-02-03 23:13:51 -06:00
78798f69af [nostalgia] Add module for Scene 2023-02-03 23:07:31 -06:00
ccf47c0e4b [nostalgia/core] Cleanup typeconv.hpp 2023-02-03 22:32:43 -06:00
05a46c3b07 [nostalgia] Move pack transforms to modules 2023-02-03 22:16:01 -06:00
b1b2780eb9 [ox] GBA fixes 2023-02-03 21:56:30 -06:00
535480ef26 [nostalgia/toos/pack] Cleanup 2023-02-03 02:04:33 -06:00
26a1f2e4ad [ox/fs] Add error message to an error 2023-02-03 02:02:57 -06:00
8bcffc73ff [nostalgia/tools/pack] Fix nost-pack to pass in proper Context 2023-02-03 01:54:56 -06:00
7868b0678f [nostalgia] Split part of Core out into Foundation, add module system 2023-02-03 00:55:44 -06:00
83589287bc [ox/model] Add default type params arg to buildTypeId 2023-02-03 00:22:11 -06:00
cd28fee8fd [nostalgia/player] Add PC controls and Bullock integration 2023-02-01 22:50:08 -06:00
231f460668 [nostalgia/core] Cleanup 2023-02-01 22:46:18 -06:00
09d30acd7b [nostalgia/studio] Add Bullock integration 2023-02-01 22:44:11 -06:00
fea6a0764c [nostalgia/studio] Cleanup 2023-02-01 22:43:50 -06:00
fad8837ad1 [nostalgia/tools/pack] Add Bullock integration and cleanup FS access 2023-02-01 22:41:04 -06:00
1cc3549d00 [nostalgia/core/userland] Fix sprite location wrapping 2023-02-01 21:01:20 -06:00
4bcef4bd35 [nostalgia/core/userland] Add support for multiple sprite size/shapes 2023-02-01 02:07:55 -06:00
17cb40c0ec [ox/model] Add type name and version functions overload option 2023-01-30 23:13:07 -06:00
838187797a [ox/fs] Fix a log message's channel 2023-01-27 01:34:43 -06:00
1aceeebd5d [nostalgia/core/gba] Update for Ox FS changes 2023-01-27 00:01:14 -06:00
1cfa594c92 [ox/fs] Wrap overloaded virtual functions in FileSystem 2023-01-27 00:00:35 -06:00
94cb2e982a [ox] Add logconn for Bullock logging 2023-01-25 02:08:52 -06:00
e1fa48ea2f [ox/model] Fix FieldCounter to count CString fields 2023-01-25 00:21:23 -06:00
4cb6992178 [ox/std] Add Vector::emplace 2023-01-14 19:42:17 -06:00
5fa614ab83 [nostalgia/sample_project] Add Studio logo source to sample_project 2023-01-03 03:40:59 -06:00
7a4fbd1160 [gbastartup] Correct enabled languages in CMake 2023-01-03 03:39:53 -06:00
bb643bce42 [nostalgia] Add implementation of single tile sprites on OpenGL 2023-01-03 03:37:51 -06:00
cf6c05f4c6 [nostalgia/tools/pack] Fix for a non-compliant implementation of fstream 2023-01-03 03:33:54 -06:00
497bbc1a17 [nostalgia/studio] Update for new String beginsWith API 2023-01-03 03:32:16 -06:00
3cd638737a [ox] Update more C strings to StringViews 2023-01-03 03:31:22 -06:00
5508dc5dc0 [ox/std] Make String::beginsWtih and endsWith functions that take StringViews 2023-01-03 03:30:33 -06:00
03378ebe43 [nostalgia/core/gba] Fix buttonDown to return false for non-gamepad buttons 2023-01-03 00:13:40 -06:00
2669aafe81 [nostalgia] Cleanup frequent allocations and const correctness in project explorer 2023-01-01 15:27:28 -06:00
679226ef73 [nostalgia] Replace C strings with ox::StringView 2022-12-31 17:14:43 -06:00
55ea405a54 [ox/std] Add toStdStringView and endsWith functions 2022-12-31 17:14:09 -06:00
6cfa8dd40d [nostalgia] Replace unnecessary ox::Strings with ox::StringViews 2022-12-31 15:48:47 -06:00
5a09918b64 [nostalgia/studio] Add logo 2022-12-31 15:28:04 -06:00
2c2fce2c5a [nostalgia] Replace C strings with StringViews 2022-12-31 15:03:04 -06:00
ca07dc6152 [ox] Replace C strings in FS with StringView 2022-12-31 14:58:35 -06:00
5cae7cbd24 [nostalgia/studio] Cleanup 2022-12-30 18:19:39 -06:00
887d3b3d13 [ox/std] Remove some unnecessary/breaking checks in BasicString::set functions 2022-12-29 02:12:11 -06:00
b08559b3f3 [ox/model] MSVC fix 2022-12-19 00:19:28 -06:00
c9f1b3aaa3 [ox/claw] MSVC fix 2022-12-18 23:27:59 -06:00
907393dfe6 [nostalgia/studio] Fix MSVC issue 2022-12-18 23:18:24 -06:00
bd192ba47a [nostalgia/studio] Fix FDFilterItem to work on Windows 2022-12-18 21:56:30 -06:00
e2d5090f44 [nostalgia/core/userland] Fix namespace of forward declared Palette 2022-12-18 21:13:04 -06:00
b818c1e3d6 [ox/std] Change __has_include_nexts to __has_include 2022-12-18 21:11:41 -06:00
706f5b345a [ox/claw] Remove ambiguous second TypeInfoCatcher::setTypeInfo 2022-12-18 21:11:12 -06:00
22a7ff74ce [ox/std] Fix unnecessary implicit sign conversion 2022-12-18 21:04:44 -06:00
d8153e71e1 [nostalgia] Fix for Windows 2022-12-18 21:04:44 -06:00
4077f0bddc [ox] Fix for Windows 2022-12-18 21:04:44 -06:00
ad412177ab [nostalgia/studio] MSVC fixes for NFDE file dialog 2022-12-18 21:04:44 -06:00
1dddf4ad9d [ox] MSVC fixes 2022-12-18 16:39:20 -06:00
31e9af032a [nostalgia] Replace most new calls with ox::make 2022-12-17 22:30:49 -06:00
716b3d6022 [nostalgia/core/studio] Cleanup 2022-12-17 14:05:35 -06:00
9b36381b00 [nostalgia/studio] Fix config dir creation not create duplicate dirs 2022-12-17 14:00:39 -06:00
839a791ddd [ox/std] Add ox::make to wrap new in exception handling 2022-12-17 13:54:26 -06:00
0d040ad752 [nostalgia/tools/pack] Add PtrSize to GbaPlatSpec 2022-12-17 13:41:59 -06:00
b506c5defb [nostalgia/sample_project] Update type descriptors 2022-12-17 13:40:01 -06:00
26d6143006 [ox/model] Change <> markers for type params to ## in type IDs to deal with NTFS' ineptitude 2022-12-17 13:38:59 -06:00
44f45e64e9 [nostalgia/studio] Add ClawViewer for unknown types 2022-12-15 01:36:55 -06:00
79d255b63f [nostalgia/core/userland] Make palettes swappable in GL renderer 2022-12-11 08:38:38 -06:00
592 changed files with 22880 additions and 13682 deletions

66
.clang-tidy Normal file
View File

@ -0,0 +1,66 @@
# Generated from CLion Inspection settings
---
Checks: '-*,
cppcoreguidelines-interfaces-global-init,
cppcoreguidelines-narrowing-conversions,
cppcoreguidelines-pro-type-member-init,
-cppcoreguidelines-pro-type-static-cast-downcast,
cppcoreguidelines-slicing,
google-default-arguments,
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-*,
-misc-include-cleaner
-misc-use-anonymous-namespace,
readability-duplicate-include,
-misc-non-private-member-variables-in-classes,
-misc-no-recursion,
-misc-include-cleaner,
bugprone-*,
clang-analyzer-*,
modernize-*,
portability-*,
-modernize-use-trailing-return-type,
-bugprone-easily-swappable-parameters'

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 - 2022 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

@ -1,16 +0,0 @@
{
"init_functions": [
{
"bin_path": "dist/linux-x86_64-debug/lib/ox/libOxTraceHook.so",
"function": "oxTraceInitHook",
"ignore_frames": 3
}
],
"log_functions": [
{
"bin_path": "dist/linux-x86_64-debug/lib/ox/libOxTraceHook.so",
"function": "oxTraceHook",
"ignore_frames": 3
}
]
}

View File

@ -11,54 +11,49 @@ 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(NOSTALGIA_BUILD_TYPE "GBA")
include(deps/gbabuildcore/base.cmake) include(deps/gbabuildcore/base.cmake)
else() else()
set(NOSTALGIA_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)
include_directories( include_directories(
deps/ox/src deps/ox/src
) )
add_subdirectory(deps/teagba)
if(BUILDCORE_TARGET STREQUAL "gba") if(NOT BUILDCORE_TARGET STREQUAL "gba")
add_subdirectory(deps/gbastartup)
else()
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,40 +1,40 @@
PROJECT_NAME=nostalgia BC_VAR_PROJECT_NAME=nostalgia
BC_VAR_PROJECT_NAME_CAP=Nostalgia
BUILDCORE_PATH=deps/buildcore BUILDCORE_PATH=deps/buildcore
VCPKG_PKGS=sdl2 jsoncpp
include ${BUILDCORE_PATH}/base.mk include ${BUILDCORE_PATH}/base.mk
ifeq ($(OS),darwin) ifeq ($(BC_VAR_OS),darwin)
NOSTALGIA_STUDIO=./dist/${CURRENT_BUILD}/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=./dist/${CURRENT_BUILD}/bin/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: install run: build
./dist/${CURRENT_BUILD}/bin/nostalgia sample_project ./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME} sample_project
.PHONY: run-studio .PHONY: run-studio
run-studio: install 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: install debug: build
${DEBUGGER} ./dist/${CURRENT_BUILD}/bin/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: install 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

View File

@ -44,12 +44,13 @@ else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat=2") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat=2")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-field-initializers") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-field-initializers")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnull-dereference") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-null-dereference")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-compare") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-compare")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-conversion") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wsign-conversion")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wconversion")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused-variable") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunused-variable")
# release build options # release build options

188
deps/buildcore/base.mk vendored
View File

@ -1,5 +1,5 @@
# #
# Copyright 2016 - 2021 gary@drinkingtea.net # Copyright 2016 - 2023 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,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
else
ifeq ($(shell python -c 'import sys; print(sys.version_info[0])'),3)
BC_CMD_HOST_PY3=python
else
echo 'Please install Python3 on host'
exit 1
endif
endif
ifdef BC_VAR_USE_DOCKER_DEVENV
ifneq ($(shell which docker 2> /dev/null),) ifneq ($(shell which docker 2> /dev/null),)
ifeq ($(shell docker inspect --format="{{.State.Status}}" ${DEVENV} 2>&1),running) BC_VAR_DEVENV=devenv$(shell pwd | sed 's/\//-/g')
ENV_RUN=docker exec -i -t --user $(shell id -u ${USER}) ${DEVENV} BC_VAR_DEVENV_IMAGE=${BC_VAR_PROJECT_NAME}-devenv
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 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
ifneq ($(shell ${ENV_RUN} which python3 2> /dev/null),) BC_VAR_SCRIPTS=${BUILDCORE_PATH}/scripts
PYTHON3=python3 BC_CMD_SETUP_BUILD=${BC_CMD_PY3} ${BC_VAR_SCRIPTS}/setup-build.py
else BC_CMD_PYBB=${BC_CMD_PY3} ${BC_VAR_SCRIPTS}/pybb.py
ifeq ($(shell ${ENV_RUN} python -c 'import sys; print(sys.version_info[0])'),3) BC_CMD_HOST_PYBB=${BC_CMD_HOST_PY3} ${BC_VAR_SCRIPTS}/pybb.py
PYTHON3=python BC_CMD_CMAKE_BUILD=${BC_CMD_PYBB} cmake-build
endif BC_CMD_GETENV=${BC_CMD_PYBB} getenv
endif BC_CMD_CTEST=${BC_CMD_PYBB} ctest-all
BC_CMD_RM_RF=${BC_CMD_PYBB} rm
BC_CMD_MKDIR_P=${BC_CMD_PYBB} mkdir
BC_CMD_CAT=${BC_CMD_PYBB} cat
BC_CMD_DEBUGGER=${BC_CMD_PYBB} debug
BC_CMD_HOST_DEBUGGER=${BC_CMD_HOST_PYBB} debug
BC_VAR_HOSTENV=$(shell ${BC_CMD_ENVRUN} ${BC_CMD_PYBB} hostenv)
BC_VAR_BUILD_PATH=build
BC_VAR_CURRENT_BUILD=$(BC_VAR_HOSTENV)-$(shell ${BC_CMD_ENVRUN} ${BC_CMD_CAT} .current_build)
SCRIPTS=${BUILDCORE_PATH}/scripts ifdef BC_VAR_USE_VCPKG
SETUP_BUILD=${PYTHON3} ${SCRIPTS}/setup-build.py ifndef BC_VAR_VCPKG_DIR_BASE
PYBB=${PYTHON3} ${SCRIPTS}/pybb.py BC_VAR_VCPKG_DIR_BASE=.vcpkg
CMAKE_BUILD=${PYBB} cmake-build
GET_ENV=${PYBB} getenv
CTEST=${PYBB} ctest-all
RM_RF=${PYBB} rm
HOST=$(shell ${PYBB} hostname)
BUILDCORE_HOST_SPECIFIC_BUILDPATH=$(shell ${GET_ENV} BUILDCORE_HOST_SPECIFIC_BUILDPATH)
ifneq (${BUILDCORE_HOST_SPECIFIC_BUILDPATH},)
BUILD_PATH=build/${HOST}
else
BUILD_PATH=build
endif endif
ifdef USE_VCPKG ifndef BC_VAR_VCPKG_VERSION
ifndef VCPKG_DIR_BASE BC_VAR_VCPKG_VERSION=2023.08.09
VCPKG_DIR_BASE=.vcpkg
endif endif
ifndef VCPKG_VERSION
VCPKG_VERSION=2020.06
endif 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)
CURRENT_BUILD=$(HOST_ENV)-$(shell ${ENV_RUN} ${PYBB} cat .current_build)
.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,71 +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 (${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
.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:
@ -52,7 +54,10 @@ def cmake_build(base_path: str, target: Optional[str]) -> int:
# nothing to build # nothing to build
return 0 return 0
for d in os.listdir(base_path): for d in os.listdir(base_path):
args = ['cmake', '--build', os.path.join(base_path, d)] path = os.path.join(base_path, d)
if not os.path.isdir(path):
continue
args = ['cmake', '--build', path]
if target is not None: if target is not None:
args.extend(['--target', target]) args.extend(['--target', target])
err = subprocess.run(args).returncode err = subprocess.run(args).returncode
@ -67,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:
@ -84,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

@ -1,12 +0,0 @@
enable_language(C ASM)
add_library(
GbaStartup OBJECT
gba_crt0.s
cstartup.cpp
)
target_link_libraries(
GbaStartup PUBLIC
OxStd
)

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 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved. * Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/ */
#pragma once #pragma once
@ -8,15 +8,18 @@
#include <glad/glad.h> #include <glad/glad.h>
#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 nostalgia::glutils { namespace glutils {
constexpr auto GlslVersion = "#version 330"; struct Empty {
virtual ~Empty() noexcept = default;
struct Empty {}; };
struct TextureBase { struct TextureBase {
@ -40,6 +43,8 @@ struct TextureBase {
return *this; return *this;
} }
virtual ~TextureBase() noexcept = default;
}; };
@ -59,7 +64,7 @@ struct GLObject: public Base {
o.id = 0; o.id = 0;
} }
~GLObject() noexcept { ~GLObject() noexcept override {
del(id); del(id);
} }
@ -106,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>;
@ -134,10 +139,50 @@ struct FrameBuffer {
} }
}; };
class FrameBufferBind {
private:
static const FrameBuffer *s_activeFb;
const FrameBuffer *m_restoreFb = nullptr;
public:
explicit FrameBufferBind(const FrameBuffer &fb) noexcept;
~FrameBufferBind() noexcept;
};
ox::Result<GLProgram> buildShaderProgram(const GLchar *vert, const GLchar *frag, const GLchar *geo = nullptr) noexcept; void bind(const FrameBuffer &fb) noexcept;
ox::Result<GLProgram> buildShaderProgram(const ox::String &vert, const ox::String &frag, const ox::String &geo = "") noexcept; struct ShaderVarSet {
GLsizei len{};
ox::String name;
};
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(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;
@ -146,6 +191,15 @@ 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.
*/
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;
glutils::GLBuffer vbo; glutils::GLBuffer vbo;
@ -155,8 +209,10 @@ struct BufferSet {
ox::Vector<GLuint> elements; ox::Vector<GLuint> elements;
}; };
void sendVbo(const BufferSet &bg) noexcept; void sendVbo(BufferSet const&bs) noexcept;
void sendEbo(const BufferSet &bg) noexcept; void sendEbo(BufferSet const&bs) noexcept;
void clearScreen() noexcept;
} }

23
deps/glutils/src/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,23 @@
add_library(
GlUtils
glutils.cpp
)
target_include_directories(
GlUtils PUBLIC
../include
)
target_link_libraries(
GlUtils PUBLIC
OxStd
glad
)
install(
TARGETS
GlUtils
DESTINATION
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)

233
deps/glutils/src/glutils.cpp vendored Normal file
View File

@ -0,0 +1,233 @@
/*
* Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <ox/std/assert.hpp>
#include <ox/std/istring.hpp>
#include <ox/std/trace.hpp>
#include "glutils/glutils.hpp"
namespace glutils {
void deleteBuffer(GLuint b) noexcept {
glDeleteBuffers(1, &b);
}
void deleteFrameBuffer(GLuint b) noexcept {
glDeleteFramebuffers(1, &b);
}
void deleteRenderBuffer(GLuint b) noexcept {
glDeleteRenderbuffers(1, &b);
}
void deleteTexture(GLuint t) noexcept {
glDeleteTextures(1, &t);
}
void deleteVertexArray(GLuint v) noexcept {
glDeleteVertexArrays(1, &v);
}
void deleteProgram(GLuint p) noexcept {
glDeleteProgram(p);
}
void deleteShader(GLuint s) noexcept {
glDeleteShader(s);
}
template struct GLObject<deleteBuffer>;
template struct GLObject<deleteFrameBuffer>;
template struct GLObject<deleteRenderBuffer>;
template struct GLObject<deleteTexture, TextureBase>;
template struct GLObject<deleteVertexArray>;
template struct GLObject<deleteProgram>;
template struct GLObject<deleteShader>;
const FrameBuffer *FrameBufferBind::s_activeFb = nullptr;
FrameBufferBind::FrameBufferBind(const FrameBuffer &fb) noexcept: m_restoreFb(s_activeFb) {
s_activeFb = &fb;
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glViewport(0, 0, fb.width, fb.height);
}
FrameBufferBind::~FrameBufferBind() noexcept {
s_activeFb = m_restoreFb;
if (s_activeFb) {
glBindFramebuffer(GL_FRAMEBUFFER, *s_activeFb);
glViewport(0, 0, s_activeFb->width, s_activeFb->height);
} else {
glBindFramebuffer(GL_FRAMEBUFFER, 0);
}
}
void bind(const FrameBuffer &fb) noexcept {
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glViewport(0, 0, fb.width, fb.height);
}
static ox::Result<GLShader> buildShader(
GLuint shaderType,
const GLchar *src,
ox::CRStringView shaderName) noexcept {
GLShader shader(glCreateShader(shaderType));
glShaderSource(shader, 1, &src, nullptr);
glCompileShader(shader);
GLint status;
glGetShaderiv(shader, GL_COMPILE_STATUS, &status);
if (status != GL_TRUE) {
ox::Vector<char> errMsg(ox::units::KB);
glGetShaderInfoLog(shader, static_cast<GLsizei>(errMsg.size()), nullptr, errMsg.data());
oxErrorf("shader compile error in {}: {}", shaderName, errMsg.data());
return OxError(1, "shader compile error");
}
return shader;
}
ox::Result<GLProgram> buildShaderProgram(ProgramSource const&src) noexcept {
oxRequireM(program, buildShaderProgram(
src.vertShader,
src.fragShader,
src.geomShader));
setupShaderParams(program, src.shaderParams, src.rowLen);
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);
}
}
void setupShaderParams(GLProgram const&shader, ox::Vector<ShaderVarSet> const&vars) noexcept {
// get row len
GLsizei vertexRowLen{};
for (auto const&v : vars) {
vertexRowLen += v.len;
}
setupShaderParams(shader, vars, vertexRowLen);
}
ox::Result<GLProgram> buildShaderProgram(
ox::CStringView const&vert,
ox::CStringView const&frag,
ox::CStringView const&geo) noexcept {
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 vao;
glGenVertexArrays(1, &vao.id);
return vao;
}
GLBuffer generateBuffer() noexcept {
GLBuffer buff;
glGenBuffers(1, &buff.id);
return buff;
}
FrameBuffer generateFrameBuffer(int width, int height) noexcept {
width = ox::max(1, width);
height = ox::max(1, height);
FrameBuffer fb;
fb.width = width;
fb.height = height;
glGenFramebuffers(1, &fb.fbo.id);
glBindFramebuffer(GL_FRAMEBUFFER, fb);
// color texture
glGenTextures(1, &fb.color.id);
glBindTexture(GL_TEXTURE_2D, fb.color);
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGB, width, height, 0, GL_RGB, GL_UNSIGNED_BYTE, nullptr);
glGenerateMipmap(GL_TEXTURE_2D);
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);
// depth texture
glGenRenderbuffers(1, &fb.depth.id);
glBindRenderbuffer(GL_RENDERBUFFER, fb.depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, fb.depth);
// verify FBO
oxAssert(glCheckFramebufferStatus(GL_FRAMEBUFFER) == GL_FRAMEBUFFER_COMPLETE, "Frame Buffer is incomplete");
// restore primary FB
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
return fb;
}
void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
width = ox::max(1, width);
height = ox::max(1, height);
fb.width = width;
fb.height = height;
glBindFramebuffer(GL_FRAMEBUFFER, fb);
// color texture
glBindTexture(GL_TEXTURE_2D, fb.color);
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
glBindRenderbuffer(GL_RENDERBUFFER, fb.depth);
glRenderbufferStorage(GL_RENDERBUFFER, GL_DEPTH24_STENCIL8, width, height);
// restore primary FB
glBindFramebuffer(GL_FRAMEBUFFER, 0);
glBindTexture(GL_TEXTURE_2D, 0);
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
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());
glBindBuffer(GL_ARRAY_BUFFER, bs.vbo);
glBufferData(GL_ARRAY_BUFFER, bufferSize, bs.vertices.data(), GL_DYNAMIC_DRAW);
}
void sendEbo(BufferSet const&bs) noexcept {
const auto bufferSize = static_cast<GLsizeiptr>(sizeof(decltype(bs.elements)::value_type) * bs.elements.size());
glBindBuffer(GL_ELEMENT_ARRAY_BUFFER, bs.ebo);
glBufferData(GL_ELEMENT_ARRAY_BUFFER, bufferSize, bs.elements.data(), GL_STATIC_DRAW);
}
void clearScreen() noexcept {
glClearColor(0, 0, 0, 1);
glClear(GL_COLOR_BUFFER_BIT);
}
}

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)
@ -56,7 +56,7 @@ if(NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat=2") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat=2")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-field-initializers") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-field-initializers")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnull-dereference") #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnull-dereference")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")
@ -76,10 +76,11 @@ enable_testing()
include_directories(src) include_directories(src)
install(FILES OxConfig.cmake DESTINATION lib/ox) install(FILES OxConfig.cmake DESTINATION lib/cmake/ox)
if(OX_USE_STDLIB) 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)

View File

@ -1,15 +1,16 @@
if("${CMAKE_FIND_ROOT_PATH}" STREQUAL "") if("${CMAKE_FIND_ROOT_PATH}" STREQUAL "")
set(Ox_INCLUDE_DIRS /usr/local/include/) set(OX_PATH /usr/local/include/)
set(OxStd_LIBRARY /usr/local/lib/ox/libOxStd.a)
set(OxFS_LIBRARY /usr/local/lib/ox/libOxFS.a)
set(OxClArgs_LIBRARY /usr/local/lib/ox/libOxClArgs.a)
set(OxMetalClaw_LIBRARY /usr/local/lib/ox/libOxMetalClaw.a)
set(OxModel_LIBRARY /usr/local/lib/ox/libOxModelClaw.a)
else("${CMAKE_FIND_ROOT_PATH}" STREQUAL "") else("${CMAKE_FIND_ROOT_PATH}" STREQUAL "")
set(Ox_INCLUDE_DIRS ${CMAKE_FIND_ROOT_PATH}/include/) set(OX_PATH ${CMAKE_FIND_ROOT_PATH})
set(OxStd_LIBRARY ${CMAKE_FIND_ROOT_PATH}/lib/ox/libOxStd.a)
set(OxFS_LIBRARY ${CMAKE_FIND_ROOT_PATH}/lib/ox/libOxFS.a)
set(OxClArgs_LIBRARY ${CMAKE_FIND_ROOT_PATH}/lib/ox/libOxClArgs.a)
set(OxMetalClaw_LIBRARY ${CMAKE_FIND_ROOT_PATH}/lib/ox/libOxMetalClaw.a)
set(OxModel_LIBRARY ${CMAKE_FIND_ROOT_PATH}/lib/ox/libOxModel.a)
endif("${CMAKE_FIND_ROOT_PATH}" STREQUAL "") endif("${CMAKE_FIND_ROOT_PATH}" STREQUAL "")
set(OxClArgs_LIBRARY ${OX_PATH}/lib/ox/libOxClArgs.a)
set(OxEvent_LIBRARY ${OX_PATH}/lib/ox/libOxEvent.a)
set(OxFS_LIBRARY ${OX_PATH}/lib/ox/libOxFS.a)
set(OxLogConn_LIBRARY ${OX_PATH}/lib/ox/libOxLogConn.a)
set(OxMetalClaw_LIBRARY ${OX_PATH}/lib/ox/libOxMetalClaw.a)
set(OxModel_LIBRARY ${OX_PATH}/lib/ox/libOxModel.a)
set(OxOrganicClaw_LIBRARY ${OX_PATH}/lib/ox/libOxOrganicClaw.a)
set(OxPreloader_LIBRARY ${OX_PATH}/lib/ox/libOxPreloader.a)
set(OxStd_LIBRARY ${OX_PATH}/lib/ox/libOxStd.a)
set(Ox_INCLUDE_DIRS ${OX_PATH}/include/)

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()
@ -5,6 +20,7 @@ add_subdirectory(clargs)
add_subdirectory(claw) add_subdirectory(claw)
add_subdirectory(event) add_subdirectory(event)
add_subdirectory(fs) add_subdirectory(fs)
add_subdirectory(logconn)
add_subdirectory(mc) add_subdirectory(mc)
add_subdirectory(model) add_subdirectory(model)
add_subdirectory(preloader) add_subdirectory(preloader)

View File

@ -12,6 +12,11 @@ set_property(
POSITION_INDEPENDENT_CODE ON POSITION_INDEPENDENT_CODE ON
) )
if(NOT MSVC)
target_compile_options(OxClArgs PRIVATE -Wsign-conversion)
target_compile_options(OxClArgs PRIVATE -Wconversion)
endif()
target_link_libraries( target_link_libraries(
OxClArgs PUBLIC OxClArgs PUBLIC
OxStd OxStd
@ -27,6 +32,6 @@ install(
install( install(
TARGETS TARGETS
OxClArgs OxClArgs
LIBRARY DESTINATION lib/ox LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/ox 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/.
*/ */
#include <ox/std/string.hpp> #include <ox/std/string.hpp>
@ -12,57 +12,57 @@
namespace ox { namespace ox {
ClArgs::ClArgs(int argc, const char **args) noexcept { ClArgs::ClArgs(int argc, const char **args) noexcept {
for (int i = 0; i < 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);
} }
m_bools[arg] = true; m_bools[arg] = true;
// parse additional arguments // parse additional arguments
if (i < 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;
} }
} }
} }
} }
} }
bool ClArgs::getBool(const char *arg, bool defaultValue) const noexcept { bool ClArgs::getBool(ox::CRStringView arg, bool defaultValue) const noexcept {
auto [value, err] = m_ints.at(arg); auto [value, err] = m_ints.at(arg);
return !err ? *value : defaultValue; return !err ? *value : defaultValue;
} }
String ClArgs::getString(const char *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(const char *arg, int defaultValue) const noexcept { int ClArgs::getInt(ox::CRStringView arg, int defaultValue) const noexcept {
auto [value, err] = m_ints.at(arg); auto [value, err] = m_ints.at(arg);
return !err ? *value : defaultValue; return !err ? *value : defaultValue;
} }
Result<bool> ClArgs::getBool(const char *arg) const noexcept { Result<bool> ClArgs::getBool(ox::CRStringView arg) const noexcept {
oxRequire(out, m_bools.at(arg)); oxRequire(out, m_bools.at(arg));
return *out; return *out;
} }
Result<String> ClArgs::getString(const char *argName) const noexcept { Result<String> ClArgs::getString(ox::CRStringView argName) const noexcept {
oxRequire(out, m_strings.at(argName)); oxRequire(out, m_strings.at(argName));
return *out; return *out;
} }
Result<int> ClArgs::getInt(const char *arg) const noexcept { Result<int> ClArgs::getInt(ox::CRStringView arg) const noexcept {
oxRequire(out, m_ints.at(arg)); oxRequire(out, m_ints.at(arg));
return *out; return *out;
} }

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
@ -22,17 +22,22 @@ class ClArgs {
public: public:
ClArgs(int argc, const char **args) noexcept; ClArgs(int argc, const char **args) noexcept;
bool getBool(const char *arg, bool defaultValue) const noexcept; [[nodiscard]]
bool getBool(ox::CRStringView arg, bool defaultValue) const noexcept;
String getString(const char *argName, const char *defaultArg) const noexcept; [[nodiscard]]
String getString(ox::CRStringView argName, ox::StringView defaultValue) const noexcept;
int getInt(const char *arg, int defaultValue) const noexcept; [[nodiscard]]
int getInt(ox::CRStringView arg, int defaultValue) const noexcept;
Result<bool> getBool(const char *arg) const noexcept; [[nodiscard]]
Result<bool> getBool(ox::CRStringView arg) const noexcept;
Result<String> getString(const char *argName) const noexcept; [[nodiscard]]
Result<String> getString(ox::CRStringView argName) const noexcept;
Result<int> getInt(const char *arg) const noexcept; Result<int> getInt(ox::CRStringView arg) const noexcept;
}; };

View File

@ -5,6 +5,10 @@ add_library(
write.cpp write.cpp
) )
if(NOT MSVC)
target_compile_options(OxClaw PRIVATE -Wsign-conversion)
target_compile_options(OxClaw PRIVATE -Wconversion)
endif()
target_link_libraries( target_link_libraries(
OxClaw PUBLIC OxClaw PUBLIC
@ -12,6 +16,22 @@ 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
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
if(OX_RUN_TESTS) if(OX_RUN_TESTS)
add_subdirectory(test) add_subdirectory(test)
endif() endif()

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 - 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
@ -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 = 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 = 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 = 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());
}
Result<Buffer> stripClawHeader(const char *buff, std::size_t buffLen) noexcept {
oxRequire(header, readClawHeader(buff, buffLen));
Buffer out(header.dataSize);
ox_memcpy(out.data(), header.data, out.size());
return out;
}
Result<Buffer> stripClawHeader(const ox::Buffer &buff) noexcept {
return stripClawHeader(buff.data(), buff.size());
}
Result<ModelObject> readClaw(TypeStore *ts, const Buffer &buff) noexcept {
oxRequire(header, readClawHeader(buff)); oxRequire(header, readClawHeader(buff));
oxRequire(t, ts->template getLoad(header.typeName, header.typeVersion, header.typeParams)); return {{header.data, header.dataSize}};
}
Result<ModelObject> readClaw(TypeStore &ts, BufferView buff) noexcept {
oxRequire(header, readClawHeader(buff));
auto const [t, tdErr] = ts.getLoad(
header.typeName, header.typeVersion, header.typeParams);
if (tdErr) {
return OxError(3, "Could not load type descriptor");
}
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 Buffer &buff) noexcept {
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;

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,22 +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 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 - 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,11 +8,7 @@
#undef NDEBUG #undef NDEBUG
#include <assert.h>
#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;
@ -66,7 +62,7 @@ struct TestStruct {
template<typename T> template<typename T>
constexpr ox::Error model(T *io, ox::CommonPtrWith<TestUnion> auto *obj) { constexpr ox::Error model(T *io, ox::CommonPtrWith<TestUnion> auto *obj) {
io->template setTypeInfo<TestUnion>(); oxReturnError(io->template setTypeInfo<TestUnion>());
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->fieldCString("String", &obj->String)); oxReturnError(io->fieldCString("String", &obj->String));
@ -75,7 +71,7 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith<TestUnion> auto *obj) {
template<typename T> template<typename T>
constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStructNest> auto *obj) { constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStructNest> auto *obj) {
io->template setTypeInfo<TestStructNest>(); oxReturnError(io->template setTypeInfo<TestStructNest>());
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("String", &obj->String)); oxReturnError(io->field("String", &obj->String));
@ -84,7 +80,7 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStructNest> auto *obj) {
template<typename T> template<typename T>
constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) { constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) {
io->template setTypeInfo<TestStruct>(); oxReturnError(io->template setTypeInfo<TestStruct>());
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));
@ -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,13 +129,23 @@ 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",
[] { [] {
// 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
TestStruct ts; TestStruct ts;
oxReturnError(ox::writeClaw(&ts, ox::ClawFormat::Metal)); oxReturnError(ox::writeClaw(ts, ox::ClawFormat::Metal));
return OxError(0); return OxError(0);
} }
}, },
@ -158,12 +164,10 @@ static std::map<std::string_view, ox::Error(*)()> tests = {
testIn.Struct.Bool = false; testIn.Struct.Bool = false;
testIn.Struct.Int = 300; testIn.Struct.Int = 300;
testIn.Struct.String = "Test String 2"; testIn.Struct.String = "Test String 2";
const auto [buff, err] = ox::writeMC(testIn);
auto [buff, err] = ox::writeClaw(&testIn, ox::ClawFormat::Metal); oxAssert(err, "writeClaw failed");
oxAssert(err, "writeMC failed"); oxAssert(ox::readMC(buff, testOut), "readClaw failed");
oxAssert(ox::readClaw(buff.data(), buff.size(), &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");
oxAssert(testIn.Int1 == testOut.Int1, "Int1 value mismatch"); oxAssert(testIn.Int1 == testOut.Int1, "Int1 value mismatch");
@ -194,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 = 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 - 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 @@
#endif #endif
#include <ox/std/buffer.hpp> #include <ox/std/buffer.hpp>
#include <ox/std/string.hpp> #include <ox/std/string.hpp>
#include <ox/std/stringview.hpp>
#include "format.hpp" #include "format.hpp"
@ -26,10 +27,15 @@ struct TypeInfoCatcher {
const char *name = nullptr; const char *name = nullptr;
int version = 0; int version = 0;
template<typename T = void> template<typename T>
constexpr void setTypeInfo(const char *name = T::TypeName, int v = T::TypeVersion, const Vector<String>& = {}, int = 0) noexcept { constexpr ox::Error setTypeInfo(
this->name = name; const char *pName = T::TypeName,
this->version = v; int pVersion = T::TypeVersion,
const Vector<String>& = {},
std::size_t = 0) noexcept {
this->name = pName;
this->version = pVersion;
return {};
} }
constexpr Error field(...) noexcept { constexpr Error field(...) noexcept {
@ -53,50 +59,64 @@ struct type_version<T, decltype((void) T::TypeVersion, -1)> {
}; };
template<typename T> template<typename T>
constexpr const char *getTypeName(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(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;
} }
template<typename T> template<typename T>
Result<String> writeClawHeader(T *t, ClawFormat fmt) noexcept { ox::Error writeClawHeader(Writer_c auto &writer, const T *t, ClawFormat fmt) noexcept {
String out;
switch (fmt) { switch (fmt) {
case ClawFormat::Metal: case ClawFormat::Metal:
out += "M2;"; oxReturnError(write(writer, "M2;"));
break; break;
case ClawFormat::Organic: case ClawFormat::Organic:
out += "O1;"; oxReturnError(write(writer, "O1;"));
break; break;
default: default:
return OxError(1); return OxError(1);
} }
out += detail::getTypeName(t); oxReturnError(write(writer, detail::getTypeName(t)));
out += ";"; oxReturnError(writer.put(';'));
const auto tn = detail::getTypeVersion(t); const auto tn = detail::getTypeVersion(t);
if (tn > -1) { if (tn > -1) {
out += tn; oxReturnError(ox::writeItoa(tn, writer));
} }
out += ";"; oxReturnError(writer.put(';'));
return out; return {};
} }
} }
Result<Buffer> writeClaw(auto *t, ClawFormat fmt = ClawFormat::Metal) { Result<Buffer> writeClaw(
oxRequire(header, detail::writeClawHeader(t, fmt)); const auto &t,
oxRequire(data, fmt == ClawFormat::Metal ? writeMC(t) : writeOC(t)); ClawFormat fmt = ClawFormat::Metal,
Buffer out(header.len() + data.size()); std::size_t buffReserveSz = 2 * units::KB) noexcept {
memcpy(out.data(), header.data(), header.len()); Buffer out(buffReserveSz);
memcpy(out.data() + header.len(), data.data(), data.size()); BufferWriter bw(&out, 0);
oxReturnError(detail::writeClawHeader(bw, &t, fmt));
#ifdef OX_USE_STDLIB
if (fmt == ClawFormat::Metal) {
oxReturnError(writeMC(bw, t));
} else if (fmt == ClawFormat::Organic) {
oxRequire(data, writeOC(t));
oxReturnError(bw.write(data.data(), data.size()));
}
#else
if (fmt != ClawFormat::Metal) {
return OxError(1, "OC is not supported in this build");
}
oxReturnError(writeMC(bw, t));
#endif
out.resize(bw.tellp());
return out; return out;
} }

View File

@ -5,6 +5,7 @@ add_library(
if(NOT MSVC) if(NOT MSVC)
target_compile_options(OxEvent PRIVATE -Wsign-conversion) target_compile_options(OxEvent PRIVATE -Wsign-conversion)
target_compile_options(OxEvent PRIVATE -Wconversion)
endif() endif()
if(NOT OX_BARE_METAL) if(NOT OX_BARE_METAL)
@ -36,8 +37,8 @@ install(
) )
install(TARGETS OxEvent install(TARGETS OxEvent
LIBRARY DESTINATION lib/ox LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/ox ARCHIVE DESTINATION lib
) )
if(OX_RUN_TESTS) if(OX_RUN_TESTS)

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

@ -1,6 +1,8 @@
add_library( add_library(
OxFS OxFS
ptrarith/nodebuffer.hpp
ptrarith/ptr.hpp
filestore/filestoretemplate.cpp filestore/filestoretemplate.cpp
filesystem/filelocation.cpp filesystem/filelocation.cpp
filesystem/pathiterator.cpp filesystem/pathiterator.cpp
@ -9,13 +11,11 @@ add_library(
filesystem/passthroughfs.cpp filesystem/passthroughfs.cpp
) )
if(NOT OX_BARE_METAL) if(NOT MSVC)
if(NOT APPLE AND NOT MSVC) target_compile_options(OxFS PRIVATE -Wsign-conversion)
target_link_libraries(
OxFS PUBLIC
stdc++fs
)
endif() endif()
if(NOT OX_BARE_METAL)
set_property( set_property(
TARGET TARGET
OxFS OxFS
@ -38,7 +38,6 @@ if(NOT OX_BARE_METAL)
target_link_libraries( target_link_libraries(
oxfs-tool oxfs-tool
OxFS OxFS
OxStd
) )
install( install(
@ -75,8 +74,8 @@ install(
install( install(
TARGETS TARGETS
OxFS OxFS
LIBRARY DESTINATION lib/ox LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/ox ARCHIVE DESTINATION lib
) )
if(OX_RUN_TESTS) if(OX_RUN_TESTS)

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 - 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
@ -75,25 +75,25 @@ class FileStoreTemplate {
public: public:
FileStoreTemplate() = default; FileStoreTemplate() = default;
FileStoreTemplate(void *buff, size_t buffSize); FileStoreTemplate(void *buff, std::size_t buffSize);
static Error format(void *buffer, size_t bufferSize); static Error format(void *buffer, std::size_t bufferSize);
Error setSize(InodeId_t buffSize); Error setSize(std::size_t buffSize);
Error incLinks(InodeId_t id); Error incLinks(uint64_t id);
Error decLinks(InodeId_t id); Error decLinks(uint64_t id);
Error write(InodeId_t id, const void *data, FsSize_t dataSize, uint8_t fileType = 0); Error write(uint64_t id64, const void *data, FsSize_t dataSize, uint8_t fileType = 0);
Error remove(InodeId_t id); Error remove(uint64_t id);
Error read(InodeId_t id, void *out, FsSize_t outSize, FsSize_t *size = nullptr) const; Error read(uint64_t id, void *out, FsSize_t outSize, FsSize_t *size = nullptr) const;
Error read(InodeId_t id, FsSize_t readStart, FsSize_t readSize, void *data, FsSize_t *size = nullptr) const; Error read(uint64_t id, FsSize_t readStart, FsSize_t readSize, void *data, FsSize_t *size = nullptr) const;
ptrarith::Ptr<uint8_t, std::size_t> read(InodeId_t id) const; ptrarith::Ptr<uint8_t, std::size_t> read(uint64_t id) const;
/** /**
* Reads the "file" at the given id. You are responsible for freeing * Reads the "file" at the given id. You are responsible for freeing
@ -106,11 +106,11 @@ class FileStoreTemplate {
* @return 0 if read is a success * @return 0 if read is a success
*/ */
template<typename T> template<typename T>
Error read(InodeId_t id, FsSize_t readStart, Error read(uint64_t id, FsSize_t readStart,
FsSize_t readSize, T *data, FsSize_t readSize, T *data,
FsSize_t *size) const; FsSize_t *size) const;
Result<StatInfo> stat(InodeId_t id) const; Result<StatInfo> stat(uint64_t id) const;
Error resize(); Error resize();
@ -185,56 +185,56 @@ class FileStoreTemplate {
*/ */
ItemPtr rootInode(); ItemPtr rootInode();
bool canWrite(ItemPtr existing, size_t size); bool canWrite(ItemPtr existing, std::size_t size);
}; };
template<typename size_t> template<typename size_t>
FileStoreTemplate<size_t>::FileStoreTemplate(void *buff, size_t buffSize) { FileStoreTemplate<size_t>::FileStoreTemplate(void *buff, std::size_t buffSize) {
m_buffSize = buffSize; m_buffSize = static_cast<size_t>(buffSize);
m_buffer = reinterpret_cast<ptrarith::NodeBuffer<size_t, FileStoreItem<size_t>>*>(buff); m_buffer = reinterpret_cast<ptrarith::NodeBuffer<size_t, FileStoreItem<size_t>>*>(buff);
if (!m_buffer->valid(buffSize)) { if (!m_buffer->valid(m_buffSize)) {
m_buffSize = 0; m_buffSize = 0;
m_buffer = nullptr; m_buffer = nullptr;
} }
} }
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::format(void *buffer, size_t bufferSize) { Error FileStoreTemplate<size_t>::format(void *buffer, std::size_t bufferSize) {
auto nb = new (buffer) Buffer(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;
return OxError(0); return {};
} }
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::setSize(InodeId_t size) { Error FileStoreTemplate<size_t>::setSize(std::size_t size) {
if (m_buffSize >= size) { if (m_buffSize >= size) {
return m_buffer->setSize(size); return m_buffer->setSize(static_cast<size_t>(size));
} }
return OxError(1); return OxError(1);
} }
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::incLinks(InodeId_t id) { Error FileStoreTemplate<size_t>::incLinks(uint64_t id) {
oxRequireM(item, find(id).validate()); oxRequireM(item, find(static_cast<size_t>(id)).validate());
item->links++; ++item->links;
return OxError(0); return OxError(0);
} }
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::decLinks(InodeId_t id) { Error FileStoreTemplate<size_t>::decLinks(uint64_t id) {
oxRequireM(item, find(id).validate()); oxRequireM(item, find(static_cast<size_t>(id)).validate());
item->links--; --item->links;
if (item->links == 0) { if (item->links == 0) {
oxReturnError(remove(item)); oxReturnError(remove(item));
} }
@ -242,8 +242,9 @@ Error FileStoreTemplate<size_t>::decLinks(InodeId_t id) {
} }
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::write(InodeId_t id, 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) {
oxTracef("ox::fs::FileStoreTemplate::write", "Attempting to write to inode {}", id); const auto id = static_cast<size_t>(id64);
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());
@ -253,10 +254,10 @@ Error FileStoreTemplate<size_t>::write(InodeId_t id, 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;
@ -265,12 +266,12 @@ Error FileStoreTemplate<size_t>::write(InodeId_t id, 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);
@ -278,27 +279,27 @@ Error FileStoreTemplate<size_t>::write(InodeId_t id, 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.");
} }
} }
} }
@ -308,34 +309,34 @@ Error FileStoreTemplate<size_t>::write(InodeId_t id, const void *data, FsSize_t
} }
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::remove(InodeId_t id) { Error FileStoreTemplate<size_t>::remove(uint64_t id) {
return remove(find(id)); return remove(find(static_cast<size_t>(id)));
} }
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::read(InodeId_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(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, "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();
} }
@ -344,45 +345,72 @@ Error FileStoreTemplate<size_t>::read(InodeId_t id, void *out, FsSize_t outSize,
} }
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::read(InodeId_t id, FsSize_t readStart, FsSize_t readSize, void *data, FsSize_t *size) const { Error FileStoreTemplate<size_t>::read(uint64_t id, FsSize_t readStart, FsSize_t readSize, void *out, FsSize_t *size) const {
oxRequireM(src, find(id).validate()); oxTracef("ox.fs.FileStoreTemplate.read", "Attempting to read from inode {}", id);
oxRequireM(srcData, src->data().validate()); auto src = find(static_cast<size_t>(id));
oxRequire(sub, srcData.template subPtr<uint8_t>(readStart, readSize).validate()); // error check
memcpy(data, sub, sub.size()); if (!src.valid()) {
if (size) { oxTracef("ox.fs.FileStoreTemplate.read.fail", "Could not find requested item: {}", id);
*size = sub.size(); return OxError(1);
} }
return OxError(0);
auto srcData = m_buffer->template dataOf<uint8_t>(src);
oxTracef("ox.fs.FileStoreTemplate.read.found", "{} found at {} with data section at {}",
id, src.offset(), srcData.offset());
oxTracef("ox.fs.FileStoreTemplate.read.readSize", "{} {} {}", srcData.offset(), srcData.size(), readSize);
// error check
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",
"Item data section size: {}, Expected size: {}", srcData.size(), readSize);
return OxError(1);
}
ox::memcpy(out, srcData.get() + readStart, readSize);
if (size) {
*size = src.size();
}
return {};
} }
template<typename size_t> template<typename size_t>
template<typename T> template<typename T>
Error FileStoreTemplate<size_t>::read(InodeId_t id, FsSize_t readStart, Error FileStoreTemplate<size_t>::read(uint64_t id, FsSize_t readStart,
FsSize_t readSize, T *data, FsSize_t *size) const { FsSize_t readSize, T *out, FsSize_t *size) const {
oxRequireM(src, find(id).validate()); oxTracef("ox.fs.FileStoreTemplate.read", "Attempting to read from inode {}", id);
oxRequireM(srcData, src->data().validate()); auto src = find(static_cast<size_t>(id));
auto sub = srcData.template subPtr<uint8_t>(readStart, readSize); // error check
if (sub.valid() && sub.size() % sizeof(T)) { if (!src.valid()) {
for (FsSize_t i = 0; i < sub.size() / sizeof(T); i++) { oxTracef("ox.fs.FileStoreTemplate.read.fail", "Could not find requested item: {}", id);
// do byte-by-byte copy to ensure alignment is right when
// copying to final destination
T tmp;
for (size_t ii = 0; ii < sizeof(T); ii++) {
reinterpret_cast<uint8_t*>(&tmp)[ii] = *(sub.get() + ii);
}
*(data + i) = tmp;
}
if (size) {
*size = sub.size();
}
return OxError(0);
}
return OxError(1); return OxError(1);
} }
auto srcData = m_buffer->template dataOf<uint8_t>(src);
oxTracef("ox.fs.FileStoreTemplate.read.found", "{} found at {} with data section at {}",
id, src.offset(), srcData.offset());
oxTracef("ox.fs.FileStoreTemplate.read.readSize", "{} {} {}", srcData.offset(), srcData.size(), readSize);
// error check
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",
"Item data section size: {}, Expected size: {}", srcData.size(), readSize);
return OxError(1);
}
ox::memcpy(out, srcData.get() + readStart, readSize);
if (size) {
*size = src.size();
}
return {};
}
template<typename size_t> template<typename size_t>
ptrarith::Ptr<uint8_t, std::size_t> FileStoreTemplate<size_t>::read(InodeId_t id) const { ptrarith::Ptr<uint8_t, std::size_t> FileStoreTemplate<size_t>::read(uint64_t id) const {
auto item = find(id); auto item = find(static_cast<size_t>(id));
if (item.valid()) { if (item.valid()) {
return item->data(); return item->data();
} else { } else {
@ -393,10 +421,10 @@ ptrarith::Ptr<uint8_t, std::size_t> FileStoreTemplate<size_t>::read(InodeId_t id
template<typename size_t> template<typename size_t>
Error FileStoreTemplate<size_t>::resize() { Error FileStoreTemplate<size_t>::resize() {
oxReturnError(compact()); oxReturnError(compact());
const auto newSize = 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);
} }
@ -405,17 +433,17 @@ Error FileStoreTemplate<size_t>::resize(std::size_t size, void *newBuff) {
if (m_buffer->size() > size) { if (m_buffer->size() > size) {
return OxError(1); return OxError(1);
} }
m_buffSize = size; m_buffSize = static_cast<size_t>(size);
if (newBuff) { if (newBuff) {
m_buffer = reinterpret_cast<Buffer*>(newBuff); m_buffer = reinterpret_cast<Buffer*>(newBuff);
oxReturnError(m_buffer->setSize(size)); oxReturnError(m_buffer->setSize(static_cast<size_t>(size)));
} }
return OxError(0); return OxError(0);
} }
template<typename size_t> template<typename size_t>
Result<StatInfo> FileStoreTemplate<size_t>::stat(InodeId_t id) const { Result<StatInfo> FileStoreTemplate<size_t>::stat(uint64_t id) const {
oxRequire(inode, find(id).validate()); oxRequire(inode, find(static_cast<size_t>(id)).validate());
return StatInfo { return StatInfo {
id, id,
inode->links, inode->links,
@ -459,8 +487,8 @@ Result<typename FileStoreTemplate<size_t>::InodeId_t> FileStoreTemplate<size_t>:
return OxError(1); return OxError(1);
} }
for (auto i = 0; i < 100; i++) { for (auto i = 0; i < 100; i++) {
auto inode = fsData->random.gen() % MaxValue<InodeId_t>; auto inode = static_cast<typename FileStoreTemplate<size_t>::InodeId_t>(fsData->random.gen() % MaxValue<InodeId_t>);
if (inode > ReservedInodeEnd && !find(inode).valid()) { if (inode > ReservedInodeEnd && !find(static_cast<size_t>(inode)).valid()) {
return inode; return inode;
} }
} }
@ -478,13 +506,13 @@ Error FileStoreTemplate<size_t>::compact() {
if (!item.valid()) { if (!item.valid()) {
return OxError(1); return OxError(1);
} }
oxTracef("ox::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) {
fsData->rootNode = item.offset(); fsData->rootNode = item.offset();
} }
auto parent = findParent(rootInode(), item->id, oldAddr); auto parent = findParent(rootInode(), item->id, static_cast<size_t>(oldAddr));
oxAssert(parent.valid() || rootInode() == item.offset(), oxAssert(parent.valid() || rootInode() == item.offset(),
"Parent inode not found for item that should have parent."); "Parent inode not found for item that should have parent.");
if (parent.valid()) { if (parent.valid()) {
@ -521,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);
@ -531,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) {
@ -542,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);
@ -555,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.");
} }
} }
@ -603,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);
} }
@ -618,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);
} }
@ -673,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;
@ -696,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);
@ -704,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;
} }
@ -726,8 +754,9 @@ typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::rootInode
} }
template<typename size_t> template<typename size_t>
bool FileStoreTemplate<size_t>::canWrite(ItemPtr existing, size_t size) { bool FileStoreTemplate<size_t>::canWrite(ItemPtr existing, std::size_t size) {
return existing.size() >= size || m_buffer->spaceNeeded(size) <= m_buffer->available(); const auto sz = static_cast<size_t>(size);
return existing.size() >= sz || m_buffer->spaceNeeded(sz) <= m_buffer->available();
} }
template<typename size_t> template<typename size_t>

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 - 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
@ -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());
} }
@ -69,10 +69,10 @@ struct OX_PACKED DirectoryEntry {
[[nodiscard]] [[nodiscard]]
InodeId_t size() const { InodeId_t size() const {
return fullSize() - sizeof(*this); return fullSize() - static_cast<InodeId_t>(sizeof(*this));
} }
void setSize(InodeId_t) { void setSize(std::size_t) {
// ignore set value // ignore set value
} }
@ -94,9 +94,9 @@ class Directory {
FileStore m_fs; FileStore m_fs;
public: public:
Directory() = default; Directory() noexcept = default;
Directory(FileStore fs, InodeId_t inode); Directory(FileStore fs, uint64_t inode) noexcept;
/** /**
* Initializes Directory. * Initializes Directory.
@ -108,24 +108,26 @@ class Directory {
/** /**
* @param parents indicates the operation should create non-existent directories in the path, like mkdir -p * @param parents indicates the operation should create non-existent directories in the path, like mkdir -p
*/ */
Error write(PathIterator path, InodeId_t inode, FileName *nameBuff = nullptr) noexcept; Error write(PathIterator path, uint64_t inode64, FileName *nameBuff = nullptr) noexcept;
Error remove(PathIterator path, FileName *nameBuff = nullptr) noexcept; Error remove(PathIterator path, FileName *nameBuff = nullptr) noexcept;
template<typename F> template<typename F>
Error ls(F cb) noexcept; Error ls(F cb) noexcept;
[[nodiscard]]
Result<typename FileStore::InodeId_t> findEntry(const FileName &name) const noexcept; Result<typename FileStore::InodeId_t> findEntry(const FileName &name) const noexcept;
[[nodiscard]]
Result<typename FileStore::InodeId_t> find(PathIterator name, FileName *nameBuff = nullptr) const noexcept; Result<typename FileStore::InodeId_t> find(PathIterator name, FileName *nameBuff = nullptr) const noexcept;
}; };
template<typename FileStore, typename InodeId_t> template<typename FileStore, typename InodeId_t>
Directory<FileStore, InodeId_t>::Directory(FileStore fs, InodeId_t inodeId) { Directory<FileStore, InodeId_t>::Directory(FileStore fs, uint64_t inodeId) noexcept {
m_fs = fs; m_fs = fs;
m_inodeId = inodeId; m_inodeId = static_cast<InodeId_t>(inodeId);
auto buff = m_fs.read(inodeId).template to<Buffer>(); auto buff = m_fs.read(static_cast<InodeId_t>(inodeId)).template to<Buffer>();
if (buff.valid()) { if (buff.valid()) {
m_size = buff.size(); m_size = buff.size();
} }
@ -134,7 +136,7 @@ Directory<FileStore, InodeId_t>::Directory(FileStore fs, InodeId_t inodeId) {
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()) {
@ -149,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;
@ -157,8 +159,8 @@ 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(name->c_str()); 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,
// return an error // return an error
@ -166,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);
@ -174,7 +176,7 @@ Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, Fi
Directory<FileStore, InodeId_t> child(m_fs, childInode.value); Directory<FileStore, InodeId_t> child(m_fs, childInode.value);
oxReturnError(child.init()); oxReturnError(child.init());
auto err = write(name->c_str(), childInode.value); auto err = write(PathIterator(*name), childInode.value);
if (err) { if (err) {
oxLogError(err); oxLogError(err);
// could not index the directory, delete it // could not index the directory, delete it
@ -192,7 +194,8 @@ Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, Fi
} }
template<typename FileStore, typename InodeId_t> template<typename FileStore, typename InodeId_t>
Error Directory<FileStore, InodeId_t>::write(PathIterator path, InodeId_t inode, FileName *nameBuff) noexcept { Error Directory<FileStore, InodeId_t>::write(PathIterator path, uint64_t inode64, FileName *nameBuff) noexcept {
const auto inode = static_cast<InodeId_t>(inode64);
// 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;
@ -200,34 +203,34 @@ Error Directory<FileStore, InodeId_t>::write(PathIterator path, InodeId_t inode,
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->c_str(), path.fullPath()); *name, path.fullPath());
oxRequire(nextChild, findEntry(*name)); oxRequire(nextChild, findEntry(*name));
oxTracef("ox::fs::Directory::write", "{}: {}", name->c_str(), 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->c_str()); 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");
} }
@ -236,20 +239,20 @@ Error Directory<FileStore, InodeId_t>::write(PathIterator path, InodeId_t inode,
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));
} }
} }
@ -260,24 +263,24 @@ 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.c_str()); 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()) {
if (ox_strncmp(data->name, name.c_str(), name.len()) == 0) { if (name == data->name) {
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);
@ -286,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");
} }
} }
@ -308,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.c_str()); 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.c_str(), data->name); oxTracef("ox.fs.Directory.findEntry", "Comparing \"{}\" to \"{}\"", name, data->name);
if (ox_strncmp(data->name, name.c_str(), MaxFileNameLength) == 0) { if (name == data->name) {
oxTracef("ox::fs::Directory::findEntry", "\"{}\" match found.", name.c_str()); 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");
} }
@ -340,9 +343,9 @@ 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->c_str())); oxRequire(v, findEntry(*name));
// recurse if not at end of path // recurse if not at end of path
if (auto p = path.next(); p.valid()) { if (auto p = path.next(); p.valid()) {
Directory dir(m_fs, v); Directory dir(m_fs, v);

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,22 +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(const char *path) noexcept {
m_data.constPath = path;
m_type = FileAddressType::ConstPath;
}
FileAddress::~FileAddress() noexcept {
cleanup();
}
FileAddress &FileAddress::operator=(const FileAddress &other) noexcept { FileAddress &FileAddress::operator=(const FileAddress &other) noexcept {
if (this == &other) { if (this == &other) {
return *this; return *this;
@ -61,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:
@ -99,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) {
@ -107,16 +122,4 @@ bool FileAddress::operator==(CRStringView path) const noexcept {
return path == p; return path == p;
} }
void FileAddress::cleanup() noexcept {
if (m_type == FileAddressType::Path) {
safeDeleteArray(m_data.path);
clear();
}
}
void FileAddress::clear() noexcept {
m_data.path = nullptr;
m_type = FileAddressType::None;
}
} }

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;
@ -57,22 +57,18 @@ class FileAddress {
FileAddress(uint64_t inode) noexcept; FileAddress(uint64_t inode) noexcept;
FileAddress(CRStringView path) noexcept; explicit FileAddress(CRStringView path) noexcept;
template<std::size_t SmallStrSz> constexpr FileAddress(ox::StringLiteral path) noexcept;
FileAddress(const ox::BasicString<SmallStrSz> &path) noexcept: FileAddress(StringView(path)) {
}
FileAddress(char *path) noexcept; constexpr ~FileAddress() noexcept;
FileAddress(const char *path) noexcept;
~FileAddress() noexcept;
FileAddress &operator=(const FileAddress &other) noexcept; FileAddress &operator=(const FileAddress &other) noexcept;
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);
} }
@ -115,15 +110,36 @@ class FileAddress {
/** /**
* Cleanup memory allocations. * Cleanup memory allocations.
*/ */
void cleanup() noexcept; constexpr void cleanup() noexcept;
/** /**
* Clears fields, but does not delete allocations. * Clears fields, but does not delete allocations.
*/ */
void clear() noexcept; constexpr void clear() noexcept;
}; };
constexpr FileAddress::FileAddress(ox::StringLiteral path) noexcept {
m_data.constPath = path.c_str();
m_type = FileAddressType::ConstPath;
}
constexpr FileAddress::~FileAddress() noexcept {
cleanup();
}
constexpr void FileAddress::cleanup() noexcept {
if (m_type == FileAddressType::Path) {
safeDeleteArray(m_data.path);
clear();
}
}
constexpr void FileAddress::clear() noexcept {
m_data.path = nullptr;
m_type = FileAddressType::None;
}
template<> template<>
constexpr const char *getModelTypeName<FileAddress::Data>() noexcept { constexpr const char *getModelTypeName<FileAddress::Data>() noexcept {
return FileAddress::Data::TypeName; return FileAddress::Data::TypeName;
@ -135,32 +151,32 @@ constexpr const char *getModelTypeName<FileAddress>() noexcept {
} }
template<typename T> template<typename T>
constexpr Error model(T *io, CommonPtrWith<FileAddress::Data> auto *obj) noexcept { constexpr Error model(T *h, CommonPtrWith<FileAddress::Data> auto *obj) noexcept {
io->template setTypeInfo<FileAddress::Data>(); oxReturnError(h->template setTypeInfo<FileAddress::Data>());
oxReturnError(io->fieldCString("path", &obj->path)); oxReturnError(h->fieldCString("path", &obj->path));
oxReturnError(io->fieldCString("constPath", &obj->path)); oxReturnError(h->fieldCString("constPath", &obj->path));
oxReturnError(io->field("inode", &obj->inode)); oxReturnError(h->field("inode", &obj->inode));
return OxError(0); return {};
} }
template<typename T> template<typename T>
constexpr Error model(T *io, CommonPtrWith<FileAddress> auto *fa) noexcept { constexpr Error model(T *h, CommonPtrWith<FileAddress> auto *fa) noexcept {
io->template setTypeInfo<FileAddress>(); oxReturnError(h->template setTypeInfo<FileAddress>());
if constexpr(T::opType() == OpType::Reflect) { if constexpr(T::opType() == OpType::Reflect) {
int8_t type = 0; int8_t type = -1;
oxReturnError(io->field("type", &type)); oxReturnError(h->field("type", &type));
oxReturnError(io->field("data", UnionView(&fa->m_data, 0))); oxReturnError(h->field("data", UnionView(&fa->m_data, type)));
} else if constexpr(T::opType() == OpType::Read) { } else if constexpr(T::opType() == OpType::Read) {
auto type = static_cast<int8_t>(fa->m_type); auto type = static_cast<int8_t>(fa->m_type);
oxReturnError(io->field("type", &type)); oxReturnError(h->field("type", &type));
fa->m_type = static_cast<FileAddressType>(type); fa->m_type = static_cast<FileAddressType>(type);
oxReturnError(io->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type)))); oxReturnError(h->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
} else if constexpr(T::opType() == OpType::Write) { } else if constexpr(T::opType() == OpType::Write) {
auto type = static_cast<int8_t>(fa->m_type); auto const type = static_cast<int8_t>(fa->m_type);
oxReturnError(io->field("type", &type)); oxReturnError(h->field("type", &type));
oxReturnError(io->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type)))); oxReturnError(h->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
} }
return OxError(0); 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/.
*/ */
#include <ox/std/error.hpp> #include <ox/std/error.hpp>
@ -13,13 +13,13 @@
namespace ox { namespace ox {
Result<const char*> FileSystem::directAccess(const FileAddress &addr) noexcept { Result<const char*> MemFS::directAccess(const FileAddress &addr) const noexcept {
switch (addr.type()) { switch (addr.type()) {
case FileAddressType::Inode: case FileAddressType::Inode:
return directAccess(addr.getInode().value); return directAccess(addr.getInode().value);
case FileAddressType::ConstPath: case FileAddressType::ConstPath:
case FileAddressType::Path: case FileAddressType::Path:
return directAccess(addr.getPath().value); return directAccess(StringView(addr.getPath().value));
default: default:
return OxError(1); return OxError(1);
} }
@ -28,10 +28,10 @@ Result<const char*> FileSystem::directAccess(const FileAddress &addr) noexcept {
Error FileSystem::read(const FileAddress &addr, void *buffer, std::size_t size) noexcept { Error FileSystem::read(const FileAddress &addr, void *buffer, std::size_t size) noexcept {
switch (addr.type()) { switch (addr.type()) {
case FileAddressType::Inode: case FileAddressType::Inode:
return read(addr.getInode().value, buffer, size); return readFileInode(addr.getInode().value, buffer, size);
case FileAddressType::ConstPath: case FileAddressType::ConstPath:
case FileAddressType::Path: case FileAddressType::Path:
return read(addr.getPath().value, buffer, size); return readFilePath(StringView(addr.getPath().value), buffer, size);
default: default:
return OxError(1); return OxError(1);
} }
@ -39,34 +39,37 @@ Error FileSystem::read(const FileAddress &addr, void *buffer, std::size_t size)
Result<Buffer> FileSystem::read(const FileAddress &addr) noexcept { Result<Buffer> FileSystem::read(const FileAddress &addr) noexcept {
oxRequire(s, stat(addr)); oxRequire(s, stat(addr));
Buffer buff(s.size); Buffer buff(static_cast<std::size_t>(s.size));
oxReturnError(read(addr, buff.data(), buff.size())); oxReturnError(read(addr, buff.data(), buff.size()));
return buff; return buff;
} }
Result<Buffer> FileSystem::read(CRStringView path) noexcept {
oxRequire(s, statPath(path));
Buffer buff(static_cast<std::size_t>(s.size));
oxReturnError(readFilePath(path, buff.data(), buff.size()));
return buff;
}
Error FileSystem::read(const FileAddress &addr, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept { Error FileSystem::read(const FileAddress &addr, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept {
switch (addr.type()) { switch (addr.type()) {
case FileAddressType::Inode: case FileAddressType::Inode:
return read(addr.getInode().value, readStart, readSize, buffer, size); return read(addr.getInode().value, readStart, readSize, buffer, size);
case FileAddressType::ConstPath: case FileAddressType::ConstPath:
case FileAddressType::Path: case FileAddressType::Path:
return read(addr.getPath().value, readStart, readSize, buffer, size); return OxError(2, "Unsupported for path lookups");
default: default:
return OxError(1); return OxError(1);
} }
} }
Result<Vector<String>> FileSystem::ls(const String &dir) const noexcept {
return ls(dir.c_str());
}
Error FileSystem::remove(const FileAddress &addr, bool recursive) noexcept { Error FileSystem::remove(const FileAddress &addr, bool recursive) noexcept {
switch (addr.type()) { switch (addr.type()) {
case FileAddressType::Inode: case FileAddressType::Inode:
return remove(addr.getInode().value, recursive); return remove(addr.getInode().value, recursive);
case FileAddressType::ConstPath: case FileAddressType::ConstPath:
case FileAddressType::Path: case FileAddressType::Path:
return remove(addr.getPath().value, recursive); return remove(StringView(addr.getPath().value), recursive);
default: default:
return OxError(1); return OxError(1);
} }
@ -75,10 +78,10 @@ Error FileSystem::remove(const FileAddress &addr, bool recursive) noexcept {
Error FileSystem::write(const FileAddress &addr, const void *buffer, uint64_t size, FileType fileType) noexcept { Error FileSystem::write(const FileAddress &addr, const void *buffer, uint64_t size, FileType fileType) noexcept {
switch (addr.type()) { switch (addr.type()) {
case FileAddressType::Inode: case FileAddressType::Inode:
return write(addr.getInode().value, buffer, size, fileType); return writeFileInode(addr.getInode().value, buffer, size, fileType);
case FileAddressType::ConstPath: case FileAddressType::ConstPath:
case FileAddressType::Path: case FileAddressType::Path:
return write(addr.getPath().value, buffer, size, fileType); return writeFilePath(StringView(addr.getPath().value), buffer, size, fileType);
default: default:
return OxError(1); return OxError(1);
} }
@ -87,10 +90,10 @@ Error FileSystem::write(const FileAddress &addr, const void *buffer, uint64_t si
Result<FileStat> FileSystem::stat(const FileAddress &addr) const noexcept { Result<FileStat> FileSystem::stat(const FileAddress &addr) const noexcept {
switch (addr.type()) { switch (addr.type()) {
case FileAddressType::Inode: case FileAddressType::Inode:
return stat(addr.getInode().value); return statInode(addr.getInode().value);
case FileAddressType::ConstPath: case FileAddressType::ConstPath:
case FileAddressType::Path: case FileAddressType::Path:
return stat(addr.getPath().value); return statPath(StringView(addr.getPath().value));
default: default:
return OxError(1); return OxError(1);
} }

View File

@ -1,14 +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/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>
@ -29,61 +30,82 @@ class FileSystem {
public: public:
virtual ~FileSystem() noexcept = default; virtual ~FileSystem() noexcept = default;
virtual Error mkdir(const char *path, bool recursive) noexcept = 0; virtual Error mkdir(CRStringView path, bool recursive) noexcept = 0;
/** /**
* Moves an entry from one directory to another. * Moves an entry from one directory to another.
* @param src the path to the file * @param src the path to the file
* @param dest the path of the destination directory * @param dest the path of the destination directory
*/ */
virtual Error move(const char *src, const char *dest) noexcept = 0; virtual Error move(CRStringView src, CRStringView dest) noexcept = 0;
virtual Error read(const char *path, void *buffer, std::size_t buffSize) noexcept = 0;
virtual Result<const char*> directAccess(const char *path) noexcept = 0;
virtual Error read(uint64_t inode, void *buffer, std::size_t size) noexcept = 0;
virtual Error read(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept = 0;
virtual Result<const char*> directAccess(uint64_t inode) noexcept = 0;
Error read(const FileAddress &addr, void *buffer, std::size_t size) noexcept; Error read(const FileAddress &addr, void *buffer, std::size_t size) noexcept;
Result<Buffer> read(const FileAddress &addr) noexcept; Result<Buffer> read(const FileAddress &addr) noexcept;
Result<Buffer> read(CRStringView path) noexcept;
inline Error read(CRStringView path, void *buffer, std::size_t buffSize) noexcept {
return readFilePath(path, buffer, buffSize);
}
inline Error read(uint64_t inode, void *buffer, std::size_t buffSize) noexcept {
return readFileInode(inode, buffer, buffSize);
}
Error read(const FileAddress &addr, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept; Error read(const FileAddress &addr, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept;
[[maybe_unused]] virtual Result<Vector<String>> ls(CRStringView dir) const noexcept = 0;
Result<const char*> directAccess(const FileAddress &addr) noexcept;
Result<Vector<String>> ls(const String &dir) const noexcept; virtual Error remove(CRStringView path, bool recursive) noexcept = 0;
virtual Result<Vector<String>> ls(const char *dir) const noexcept = 0;
virtual Error remove(const char *path, bool recursive) noexcept = 0;
Error remove(const FileAddress &addr, bool recursive = false) noexcept; Error remove(const FileAddress &addr, bool recursive = false) noexcept;
virtual Error resize(uint64_t size, void *buffer) noexcept = 0; virtual Error resize(uint64_t size, void *buffer) noexcept = 0;
virtual Error write(const char *path, const void *buffer, uint64_t size, FileType fileType) noexcept = 0; Error write(CRStringView path, const void *buffer, uint64_t size) noexcept {
return writeFilePath(path, buffer, size, FileType::NormalFile);
}
virtual Error write(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept = 0; 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 {
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;
virtual Result<FileStat> stat(uint64_t inode) const noexcept = 0; inline Error write(CRStringView path, const void *buffer, uint64_t size, FileType fileType) noexcept {
return writeFilePath(path, buffer, size, fileType);
}
virtual Result<FileStat> stat(const char *path) const noexcept = 0; inline Error write(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept {
return writeFileInode(inode, buffer, size, fileType);
}
inline Result<FileStat> stat(uint64_t inode) const noexcept {
return statInode(inode);
}
inline Result<FileStat> stat(CRStringView path) const noexcept {
return statPath(path);
}
Result<FileStat> stat(const FileAddress &addr) const noexcept; Result<FileStat> stat(const FileAddress &addr) const noexcept;
[[nodiscard]] [[nodiscard]]
virtual uint64_t spaceNeeded(uint64_t size) const noexcept = 0; virtual uint64_t spaceNeeded(uint64_t size) const noexcept = 0;
[[nodiscard]]
virtual Result<uint64_t> available() const noexcept = 0; virtual Result<uint64_t> available() const noexcept = 0;
[[nodiscard]]
virtual Result<uint64_t> size() const noexcept = 0; virtual Result<uint64_t> size() const noexcept = 0;
[[nodiscard]] [[nodiscard]]
@ -94,6 +116,39 @@ class FileSystem {
[[nodiscard]] [[nodiscard]]
virtual bool valid() const noexcept = 0; virtual bool valid() const noexcept = 0;
protected:
virtual Result<FileStat> statInode(uint64_t inode) const noexcept = 0;
virtual Result<FileStat> statPath(CRStringView path) const noexcept = 0;
virtual Error readFilePath(CRStringView path, void *buffer, std::size_t buffSize) noexcept = 0;
virtual Error readFileInode(uint64_t inode, void *buffer, std::size_t size) noexcept = 0;
virtual Error readFileInodeRange(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept = 0;
virtual Error writeFilePath(CRStringView path, const void *buffer, uint64_t size, FileType fileType) noexcept = 0;
virtual Error writeFileInode(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept = 0;
};
class MemFS: public FileSystem {
public:
Result<const char*> directAccess(const FileAddress &addr) const noexcept;
inline Result<const char*> directAccess(CRStringView path) const noexcept {
return directAccessPath(path);
}
inline Result<const char*> directAccess(uint64_t inode) const noexcept {
return directAccessInode(inode);
}
protected:
virtual Result<const char*> directAccessPath(CRStringView path) const noexcept = 0;
virtual Result<const char*> directAccessInode(uint64_t inode) const noexcept = 0;
}; };
/** /**
@ -103,7 +158,7 @@ class FileSystem {
* Note: Directory parameter must have a default constructor. * Note: Directory parameter must have a default constructor.
*/ */
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
class FileSystemTemplate: public FileSystem { class FileSystemTemplate: public MemFS {
private: private:
static constexpr auto InodeFsData = 2; static constexpr auto InodeFsData = 2;
@ -119,32 +174,34 @@ class FileSystemTemplate: public FileSystem {
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;
static Error format(void *buff, uint64_t buffSize) noexcept; static Error format(void *buff, uint64_t buffSize) noexcept;
Error mkdir(const char *path, bool recursive) noexcept override; Error mkdir(CRStringView path, bool recursive) noexcept override;
Error move(const char *src, const char *dest) noexcept override; Error move(CRStringView src, CRStringView dest) noexcept override;
Error read(const char *path, void *buffer, std::size_t buffSize) noexcept override; Error readFilePath(CRStringView path, void *buffer, std::size_t buffSize) noexcept override;
Result<const char*> directAccess(const char*) noexcept override; Result<const char*> directAccessPath(CRStringView) const noexcept override;
Error read(uint64_t inode, void *buffer, std::size_t size) noexcept override; Error readFileInode(uint64_t inode, void *buffer, std::size_t size) noexcept override;
Error read(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept override; Error readFileInodeRange(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept override;
Result<const char*> directAccess(uint64_t) noexcept override; Result<const char*> directAccessInode(uint64_t) const noexcept override;
Result<Vector<String>> ls(const char *path) const noexcept override; Result<Vector<String>> ls(CRStringView dir) const noexcept override;
template<typename F> template<typename F>
Error ls(const char *path, F cb) const; Error ls(CRStringView path, F cb) const;
Error remove(const char *path, bool recursive) noexcept override; Error remove(CRStringView path, bool recursive) noexcept override;
/** /**
* Resizes FileSystem to minimum possible size. * Resizes FileSystem to minimum possible size.
@ -153,14 +210,15 @@ class FileSystemTemplate: public FileSystem {
Error resize(uint64_t size, void *buffer) noexcept override; Error resize(uint64_t size, void *buffer) noexcept override;
Error write(const char *path, const void *buffer, uint64_t size, FileType fileType) noexcept override; Error writeFilePath(CRStringView path, const void *buffer, uint64_t size, FileType fileType) noexcept override;
Error write(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept override; Error writeFileInode(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept override;
Result<FileStat> stat(uint64_t inode) const noexcept override; Result<FileStat> statInode(uint64_t inode) const noexcept override;
Result<FileStat> stat(const char *path) const noexcept override; Result<FileStat> statPath(CRStringView path) const noexcept override;
[[nodiscard]]
uint64_t spaceNeeded(uint64_t size) const noexcept override; uint64_t spaceNeeded(uint64_t size) const noexcept override;
Result<uint64_t> available() const noexcept override; Result<uint64_t> available() const noexcept override;
@ -180,7 +238,7 @@ class FileSystemTemplate: public FileSystem {
/** /**
* Finds the inode ID at the given path. * Finds the inode ID at the given path.
*/ */
Result<uint64_t> find(const char *path) const noexcept; Result<uint64_t> find(CRStringView path) const noexcept;
Result<Directory> rootDir() const noexcept; Result<Directory> rootDir() const noexcept;
@ -191,9 +249,14 @@ 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, bufferSize), m_fs(buffer, static_cast<std::size_t>(bufferSize)),
m_freeBuffer(freeBuffer) { m_freeBuffer(freeBuffer) {
} }
@ -206,8 +269,8 @@ FileSystemTemplate<FileStore, Directory>::~FileSystemTemplate() noexcept {
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::format(void *buff, uint64_t buffSize) noexcept { Error FileSystemTemplate<FileStore, Directory>::format(void *buff, uint64_t buffSize) noexcept {
oxReturnError(FileStore::format(buff, buffSize)); oxReturnError(FileStore::format(buff, static_cast<size_t>(buffSize)));
FileStore fs(buff, buffSize); FileStore fs(buff, static_cast<size_t>(buffSize));
constexpr auto rootDirInode = MaxValue<typename FileStore::InodeId_t> / 2; constexpr auto rootDirInode = MaxValue<typename FileStore::InodeId_t> / 2;
Directory rootDir(fs, rootDirInode); Directory rootDir(fs, rootDirInode);
@ -215,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);
} }
@ -227,14 +290,14 @@ 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(const char *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);
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::move(const char *src, const char *dest) noexcept { Error FileSystemTemplate<FileStore, Directory>::move(CRStringView src, CRStringView dest) noexcept {
oxRequire(fd, fileSystemData()); oxRequire(fd, fileSystemData());
Directory rootDir(m_fs, fd.rootDirInode); Directory rootDir(m_fs, fd.rootDirInode);
oxRequireM(inode, rootDir.find(src)); oxRequireM(inode, rootDir.find(src));
@ -244,44 +307,51 @@ Error FileSystemTemplate<FileStore, Directory>::move(const char *src, const char
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::read(const char *path, void *buffer, std::size_t buffSize) noexcept { Error FileSystemTemplate<FileStore, Directory>::readFilePath(CRStringView path, void *buffer, std::size_t buffSize) noexcept {
oxRequire(fd, fileSystemData());
Directory rootDir(m_fs, fd.rootDirInode);
oxRequire(s, stat(path));
if (s.size > buffSize) {
return OxError(1, "Buffer to small to load file");
}
return readFileInodeRange(s.inode, 0, static_cast<size_t>(s.size), buffer, &buffSize);
}
template<typename FileStore, typename Directory>
Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccessPath(CRStringView path) const noexcept {
oxRequire(fd, fileSystemData()); oxRequire(fd, fileSystemData());
Directory rootDir(m_fs, fd.rootDirInode); Directory rootDir(m_fs, fd.rootDirInode);
oxRequire(inode, rootDir.find(path)); oxRequire(inode, rootDir.find(path));
return read(inode, buffer, buffSize); return directAccessInode(inode);
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccess(const char *path) noexcept { Error FileSystemTemplate<FileStore, Directory>::readFileInode(uint64_t inode, void *buffer, std::size_t buffSize) noexcept {
oxRequire(fd, fileSystemData()); oxRequire(s, stat(inode));
Directory rootDir(m_fs, fd.rootDirInode); if (s.size > buffSize) {
oxRequire(inode, rootDir.find(path)); return OxError(1, "Buffer to small to load file");
return directAccess(inode); }
return readFileInodeRange(inode, 0, static_cast<size_t>(s.size), buffer, &buffSize);
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::read(uint64_t inode, void *buffer, std::size_t buffSize) noexcept { Error FileSystemTemplate<FileStore, Directory>::readFileInodeRange(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept {
return m_fs.read(inode, buffer, buffSize);
}
template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::read(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept {
return m_fs.read(inode, readStart, readSize, reinterpret_cast<uint8_t*>(buffer), size); return m_fs.read(inode, readStart, readSize, reinterpret_cast<uint8_t*>(buffer), size);
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccess(uint64_t inode) noexcept { Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccessInode(uint64_t inode) const noexcept {
auto data = m_fs.read(inode); auto data = m_fs.read(inode);
if (!data.valid()) { if (!data.valid()) {
return OxError(1); return OxError(1, "Data not valid");
} }
return reinterpret_cast<char*>(data.get()); return reinterpret_cast<char*>(data.get());
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Result<Vector<String>> FileSystemTemplate<FileStore, Directory>::ls(const char *path) const noexcept { Result<Vector<String>> FileSystemTemplate<FileStore, Directory>::ls(CRStringView path) const noexcept {
Vector<String> out; Vector<String> out;
oxReturnError(ls(path, [&out](const char *name, typename FileStore::InodeId_t) { oxReturnError(ls(path, [&out](CRStringView name, typename FileStore::InodeId_t) {
out.emplace_back(name); out.emplace_back(name);
return OxError(0); return OxError(0);
})); }));
@ -290,19 +360,19 @@ Result<Vector<String>> FileSystemTemplate<FileStore, Directory>::ls(const char *
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
template<typename F> template<typename F>
Error FileSystemTemplate<FileStore, Directory>::ls(const char *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);
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::remove(const char *path, bool recursive) noexcept { Error FileSystemTemplate<FileStore, Directory>::remove(CRStringView path, bool recursive) noexcept {
oxRequire(fd, fileSystemData()); oxRequire(fd, fileSystemData());
Directory rootDir(m_fs, fd.rootDirInode); Directory rootDir(m_fs, fd.rootDirInode);
oxRequire(inode, rootDir.find(path)); oxRequire(inode, rootDir.find(path));
oxRequire(st, stat(inode)); oxRequire(st, statInode(inode));
if (st.fileType == FileType::NormalFile || recursive) { if (st.fileType == FileType::NormalFile || recursive) {
if (auto err = rootDir.remove(path)) { if (auto err = rootDir.remove(path)) {
// removal failed, try putting the index back // removal failed, try putting the index back
@ -310,7 +380,7 @@ Error FileSystemTemplate<FileStore, Directory>::remove(const char *path, bool re
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);
@ -323,12 +393,12 @@ Error FileSystemTemplate<FileStore, Directory>::resize() noexcept {
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::resize(uint64_t size, void *buffer) noexcept { Error FileSystemTemplate<FileStore, Directory>::resize(uint64_t size, void *buffer) noexcept {
oxReturnError(m_fs.resize(size, buffer)); oxReturnError(m_fs.resize(static_cast<size_t>(size), buffer));
return OxError(0); return OxError(0);
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::write(const char *path, const void *buffer, uint64_t size, FileType fileType) noexcept { Error FileSystemTemplate<FileStore, Directory>::writeFilePath(CRStringView path, const void *buffer, uint64_t size, FileType fileType) noexcept {
auto [inode, err] = find(path); auto [inode, err] = find(path);
if (err) { if (err) {
oxRequire(generatedId, m_fs.generateInodeId()); oxRequire(generatedId, m_fs.generateInodeId());
@ -336,17 +406,17 @@ Error FileSystemTemplate<FileStore, Directory>::write(const char *path, const vo
oxRequireM(rootDir, this->rootDir()); oxRequireM(rootDir, this->rootDir());
oxReturnError(rootDir.write(path, inode)); oxReturnError(rootDir.write(path, inode));
} }
oxReturnError(write(inode, buffer, size, fileType)); oxReturnError(writeFileInode(inode, buffer, size, fileType));
return OxError(0); return OxError(0);
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::write(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept { Error FileSystemTemplate<FileStore, Directory>::writeFileInode(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept {
return m_fs.write(inode, buffer, size, static_cast<uint8_t>(fileType)); return m_fs.write(inode, buffer, static_cast<size_t>(size), static_cast<uint8_t>(fileType));
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Result<FileStat> FileSystemTemplate<FileStore, Directory>::stat(uint64_t inode) const noexcept { Result<FileStat> FileSystemTemplate<FileStore, Directory>::statInode(uint64_t inode) const noexcept {
oxRequire(s, m_fs.stat(inode)); oxRequire(s, m_fs.stat(inode));
FileStat out; FileStat out;
out.inode = s.inode; out.inode = s.inode;
@ -357,14 +427,14 @@ Result<FileStat> FileSystemTemplate<FileStore, Directory>::stat(uint64_t inode)
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Result<FileStat> FileSystemTemplate<FileStore, Directory>::stat(const char *path) const noexcept { Result<FileStat> FileSystemTemplate<FileStore, Directory>::statPath(CRStringView path) const noexcept {
oxRequire(inode, find(path)); oxRequire(inode, find(path));
return stat(inode); return stat(inode);
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
uint64_t FileSystemTemplate<FileStore, Directory>::spaceNeeded(uint64_t size) const noexcept { uint64_t FileSystemTemplate<FileStore, Directory>::spaceNeeded(uint64_t size) const noexcept {
return m_fs.spaceNeeded(size); return m_fs.spaceNeeded(static_cast<size_t>(size));
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
@ -400,10 +470,10 @@ Result<typename FileSystemTemplate<FileStore, Directory>::FileSystemData> FileSy
} }
template<typename FileStore, typename Directory> template<typename FileStore, typename Directory>
Result<uint64_t> FileSystemTemplate<FileStore, Directory>::find(const char *path) const noexcept { Result<uint64_t> FileSystemTemplate<FileStore, Directory>::find(CRStringView path) const noexcept {
oxRequire(fd, fileSystemData()); oxRequire(fd, fileSystemData());
// return root as a special case // return root as a special case
if (ox_strcmp(path, "/") == 0) { if (path == "/") {
return static_cast<uint64_t>(fd.rootDirInode); return static_cast<uint64_t>(fd.rootDirInode);
} }
Directory rootDir(m_fs, fd.rootDirInode); Directory rootDir(m_fs, fd.rootDirInode);

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/std/error.hpp> #include <ox/std/error.hpp>
@ -13,25 +13,25 @@
#if defined(OX_HAS_PASSTHROUGHFS) #if defined(OX_HAS_PASSTHROUGHFS)
#include <fstream> #include <fstream>
#include <string_view>
namespace ox { namespace ox {
PassThroughFS::PassThroughFS(const char *dirPath) { PassThroughFS::PassThroughFS(CRStringView dirPath) {
m_path = dirPath; m_path = std::string_view(dirPath.data(), dirPath.bytes());
} }
PassThroughFS::~PassThroughFS() noexcept { 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(const char *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", 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);
@ -39,7 +39,7 @@ Error PassThroughFS::mkdir(const char *path, bool recursive) noexcept {
success = true; success = true;
} else { } else {
success = std::filesystem::create_directories(p, ec); success = std::filesystem::create_directories(p, ec);
oxReturnError(OxError(ec.value(), "PassThroughFS: mkdir failed")); oxReturnError(OxError(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: mkdir failed"));
} }
} else { } else {
std::error_code ec; std::error_code ec;
@ -47,15 +47,14 @@ Error PassThroughFS::mkdir(const char *path, bool recursive) noexcept {
if (isDir) { if (isDir) {
success = true; success = true;
} else { } else {
std::error_code ec;
success = std::filesystem::create_directory(p, ec); success = std::filesystem::create_directory(p, ec);
oxReturnError(OxError(ec.value(), "PassThroughFS: mkdir failed")); oxReturnError(OxError(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: mkdir failed"));
} }
} }
return OxError(success ? 0 : 1); return OxError(success ? 0 : 1);
} }
Error PassThroughFS::move(const char *src, const char *dest) noexcept { Error PassThroughFS::move(CRStringView src, CRStringView dest) noexcept {
std::error_code ec; std::error_code ec;
std::filesystem::rename(m_path / stripSlash(src), m_path / stripSlash(dest), ec); std::filesystem::rename(m_path / stripSlash(src), m_path / stripSlash(dest), ec);
if (ec.value()) { if (ec.value()) {
@ -64,46 +63,11 @@ Error PassThroughFS::move(const char *src, const char *dest) noexcept {
return OxError(0); return OxError(0);
} }
Error PassThroughFS::read(const char *path, void *buffer, std::size_t buffSize) noexcept { Result<Vector<String>> PassThroughFS::ls(CRStringView dir) const noexcept {
try {
std::ifstream file((m_path / stripSlash(path)), std::ios::binary | std::ios::ate);
const std::size_t size = file.tellg();
file.seekg(0, std::ios::beg);
if (size > buffSize) {
oxTracef("ox::fs::PassThroughFS::read::error", "Read failed: Buffer too small: {}", path);
return OxError(1);
}
file.read(static_cast<char*>(buffer), buffSize);
} catch (const std::fstream::failure &f) {
oxTracef("ox::fs::PassThroughFS::read::error", "Read of {} failed: {}", path, f.what());
return OxError(2);
}
return OxError(0);
}
Result<const char*> PassThroughFS::directAccess(const char*) noexcept {
return OxError(1, "PassThroughFS::directAccess not supported");
}
Error PassThroughFS::read(uint64_t, void*, std::size_t) noexcept {
// unsupported
return OxError(1, "read(uint64_t, void*, std::size_t) is not supported by PassThroughFS");
}
Error PassThroughFS::read(uint64_t, std::size_t, std::size_t, void*, std::size_t*) noexcept {
// unsupported
return OxError(1, "read(uint64_t, std::size_t, std::size_t, void*, std::size_t*) is not supported by PassThroughFS");
}
Result<const char*> PassThroughFS::directAccess(uint64_t) noexcept {
return OxError(1, "PassThroughFS::directAccess not supported");
}
Result<Vector<String>> PassThroughFS::ls(const char *dir) const noexcept {
Vector<String> out; Vector<String> out;
std::error_code ec; std::error_code ec;
const auto di = std::filesystem::directory_iterator(m_path / stripSlash(dir), ec); const auto di = std::filesystem::directory_iterator(m_path / stripSlash(dir), ec);
oxReturnError(OxError(ec.value(), "PassThroughFS: ls failed")); oxReturnError(OxError(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: ls failed"));
for (const auto &p : di) { for (const auto &p : di) {
const auto u8p = p.path().filename().u8string(); const auto u8p = p.path().filename().u8string();
out.emplace_back(reinterpret_cast<const char*>(u8p.c_str())); out.emplace_back(reinterpret_cast<const char*>(u8p.c_str()));
@ -111,7 +75,7 @@ Result<Vector<String>> PassThroughFS::ls(const char *dir) const noexcept {
return out; return out;
} }
Error PassThroughFS::remove(const char *path, bool recursive) noexcept { Error PassThroughFS::remove(CRStringView path, bool recursive) noexcept {
if (recursive) { if (recursive) {
return OxError(std::filesystem::remove_all(m_path / stripSlash(path)) != 0); return OxError(std::filesystem::remove_all(m_path / stripSlash(path)) != 0);
} else { } else {
@ -124,38 +88,21 @@ Error PassThroughFS::resize(uint64_t, void*) noexcept {
return OxError(1, "resize is not supported by PassThroughFS"); return OxError(1, "resize is not supported by PassThroughFS");
} }
Error PassThroughFS::write(const char *path, const void *buffer, uint64_t size, FileType) noexcept { Result<FileStat> PassThroughFS::statInode(uint64_t) const noexcept {
const auto p = (m_path / stripSlash(path));
try {
std::ofstream f(p, std::ios::binary);
f.write(static_cast<const char*>(buffer), size);
} catch (const std::fstream::failure &f) {
oxTracef("ox::fs::PassThroughFS::read::error", "Write of {} failed: {}", path, f.what());
return OxError(1);
}
return OxError(0);
}
Error PassThroughFS::write(uint64_t, const void*, uint64_t, FileType) noexcept {
// unsupported // unsupported
return OxError(1, "write(uint64_t, void*, uint64_t, uint8_t) is not supported by PassThroughFS"); return OxError(1, "statInode(uint64_t) is not supported by PassThroughFS");
} }
Result<FileStat> PassThroughFS::stat(uint64_t) const noexcept { Result<FileStat> PassThroughFS::statPath(CRStringView path) const noexcept {
// unsupported
return OxError(1, "stat(uint64_t) is not supported by PassThroughFS");
}
Result<FileStat> PassThroughFS::stat(const char *path) const noexcept {
std::error_code ec; std::error_code ec;
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::stat", "{} {}", 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::stat", "{} {}", ec.message(), path); oxTracef("ox.fs.PassThroughFS.statInode", "{} {}", ec.message(), path);
oxTracef("ox::fs::PassThroughFS::stat::size", "{} {}", path, size); oxTracef("ox.fs.PassThroughFS.statInode.size", "{} {}", path, size);
oxReturnError(OxError(ec.value())); oxReturnError(OxError(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: stat failed"));
return FileStat{0, 0, size, type}; return FileStat{0, 0, size, type};
} }
@ -166,14 +113,14 @@ uint64_t PassThroughFS::spaceNeeded(uint64_t size) const noexcept {
Result<uint64_t> PassThroughFS::available() const noexcept { Result<uint64_t> PassThroughFS::available() const noexcept {
std::error_code ec; std::error_code ec;
const auto s = std::filesystem::space(m_path, ec); const auto s = std::filesystem::space(m_path, ec);
oxReturnError(OxError(ec.value(), "PassThroughFS: could not get FS size")); oxReturnError(OxError(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: could not get FS size"));
return s.available; return s.available;
} }
Result<uint64_t> PassThroughFS::size() const noexcept { Result<uint64_t> PassThroughFS::size() const noexcept {
std::error_code ec; std::error_code ec;
const auto s = std::filesystem::space(m_path, ec); const auto s = std::filesystem::space(m_path, ec);
oxReturnError(OxError(ec.value(), "PassThroughFS: could not get FS size")); oxReturnError(OxError(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: could not get FS size"));
return s.capacity; return s.capacity;
} }
@ -194,12 +141,56 @@ bool PassThroughFS::valid() const noexcept {
return false; return false;
} }
const char *PassThroughFS::stripSlash(const char *path) noexcept { Error PassThroughFS::readFilePath(CRStringView path, void *buffer, std::size_t buffSize) noexcept {
const auto pathLen = ox_strlen(path); try {
for (auto i = 0u; i < pathLen && path[0] == '/'; i++) { std::ifstream file((m_path / stripSlash(path)), std::ios::binary | std::ios::ate);
path++; const std::size_t size = static_cast<std::size_t>(file.tellg());
file.seekg(0, std::ios::beg);
if (size > buffSize) {
oxTracef("ox.fs.PassThroughFS.read.error", "Read failed: Buffer too small: {}", path);
return OxError(1);
} }
return path; file.read(static_cast<char*>(buffer), static_cast<std::streamsize>(buffSize));
} catch (const std::fstream::failure &f) {
oxTracef("ox.fs.PassThroughFS.read.error", "Read of {} failed: {}", path, f.what());
return OxError(2);
}
return OxError(0);
}
Error PassThroughFS::readFileInode(uint64_t, void*, std::size_t) noexcept {
// unsupported
return OxError(1, "readFileInode(uint64_t, void*, std::size_t) is not supported by PassThroughFS");
}
Error PassThroughFS::readFileInodeRange(uint64_t, std::size_t, std::size_t, void*, std::size_t*) noexcept {
// unsupported
return OxError(1, "read(uint64_t, std::size_t, std::size_t, void*, std::size_t*) is not supported by PassThroughFS");
}
Error PassThroughFS::writeFilePath(CRStringView path, const void *buffer, uint64_t size, FileType) noexcept {
const auto p = (m_path / stripSlash(path));
try {
std::ofstream f(p, std::ios::binary);
f.write(static_cast<const char*>(buffer), static_cast<std::streamsize>(size));
} catch (const std::fstream::failure &f) {
oxTracef("ox.fs.PassThroughFS.read.error", "Write of {} failed: {}", path, f.what());
return OxError(1);
}
return OxError(0);
}
Error PassThroughFS::writeFileInode(uint64_t, const void*, uint64_t, FileType) noexcept {
// unsupported
return OxError(1, "writeFileInode(uint64_t, void*, uint64_t, uint8_t) is not supported by PassThroughFS");
}
std::string_view PassThroughFS::stripSlash(StringView path) noexcept {
const auto pathLen = ox::strlen(path);
for (auto i = 0u; i < pathLen && path[0] == '/'; i++) {
path = substr(path, 1);
}
return {path.data(), path.bytes()};
} }
} }

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,7 +11,6 @@
#if __has_include(<filesystem>) && defined(OX_USE_STDLIB) #if __has_include(<filesystem>) && defined(OX_USE_STDLIB)
#include <filesystem> #include <filesystem>
#include <string>
#include <ox/std/bit.hpp> #include <ox/std/bit.hpp>
#include "filesystem.hpp" #include "filesystem.hpp"
@ -30,50 +29,38 @@ class PassThroughFS: public FileSystem {
std::filesystem::path m_path; std::filesystem::path m_path;
public: public:
explicit PassThroughFS(const char *dirPath); explicit PassThroughFS(CRStringView dirPath);
~PassThroughFS() noexcept override; ~PassThroughFS() noexcept override;
[[nodiscard]] [[nodiscard]]
String basePath() const noexcept; String basePath() const noexcept;
Error mkdir(const char *path, bool recursive = false) noexcept override; Error mkdir(CRStringView path, bool recursive) noexcept override;
Error move(const char *src, const char *dest) noexcept override; Error move(CRStringView src, CRStringView dest) noexcept override;
Error read(const char *path, void *buffer, std::size_t buffSize) noexcept override; Result<Vector<String>> ls(CRStringView dir) const noexcept override;
Result<const char*> directAccess(const char*) noexcept override;
Error read(uint64_t inode, void *buffer, std::size_t size) noexcept override;
Error read(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept override;
Result<const char*> directAccess(uint64_t) noexcept override;
Result<Vector<String>> ls(const char *dir) const noexcept override;
template<typename F> template<typename F>
Error ls(const char *dir, F cb) const noexcept; Error ls(CRStringView dir, F cb) const noexcept;
Error remove(const char *path, bool recursive = false) noexcept override; Error remove(CRStringView path, bool recursive) noexcept override;
Error resize(uint64_t size, void *buffer = nullptr) noexcept override; Error resize(uint64_t size, void *buffer) noexcept override;
Error write(const char *path, const void *buffer, uint64_t size, FileType fileType = FileType::NormalFile) noexcept override; Result<FileStat> statInode(uint64_t inode) const noexcept override;
Error write(uint64_t inode, const void *buffer, uint64_t size, FileType fileType = FileType::NormalFile) noexcept override; Result<FileStat> statPath(CRStringView path) const noexcept override;
Result<FileStat> stat(uint64_t inode) const noexcept override;
Result<FileStat> stat(const char *path) const noexcept override;
[[nodiscard]]
uint64_t spaceNeeded(uint64_t size) const noexcept override; uint64_t spaceNeeded(uint64_t size) const noexcept override;
Result<uint64_t> available() const noexcept override; Result<uint64_t> available() const noexcept override;
Result<uint64_t> size() const noexcept override; Result<uint64_t> size() const noexcept override;
[[nodiscard]]
char *buff() noexcept override; char *buff() noexcept override;
Error walk(Error(*cb)(uint8_t, uint64_t, uint64_t)) noexcept override; Error walk(Error(*cb)(uint8_t, uint64_t, uint64_t)) noexcept override;
@ -81,19 +68,31 @@ class PassThroughFS: public FileSystem {
[[nodiscard]] [[nodiscard]]
bool valid() const noexcept override; bool valid() const noexcept override;
protected:
Error readFilePath(CRStringView path, void *buffer, std::size_t buffSize) noexcept override;
Error readFileInode(uint64_t inode, void *buffer, std::size_t size) noexcept override;
Error readFileInodeRange(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept override;
Error writeFilePath(CRStringView path, const void *buffer, uint64_t size, FileType fileType) noexcept override;
Error writeFileInode(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept override;
private: private:
/** /**
* Strips the leading slashes from a string. * Strips the leading slashes from a string.
*/ */
static const char *stripSlash(const char *path) noexcept; [[nodiscard]]
static std::string_view stripSlash(StringView path) noexcept;
}; };
template<typename F> template<typename F>
Error PassThroughFS::ls(const char *dir, F cb) const noexcept { Error PassThroughFS::ls(CRStringView dir, F cb) const noexcept {
std::error_code ec; std::error_code ec;
const auto di = std::filesystem::directory_iterator(m_path / stripSlash(dir), ec); const auto di = std::filesystem::directory_iterator(m_path / stripSlash(dir), ec);
oxReturnError(OxError(ec.value(), "PassThroughFS: ls failed")); oxReturnError(OxError(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: ls failed"));
for (auto &p : di) { for (auto &p : di) {
oxReturnError(cb(p.path().filename().c_str(), 0)); oxReturnError(cb(p.path().filename().c_str(), 0));
} }

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/std/memops.hpp> #include <ox/std/memops.hpp>
@ -19,17 +19,20 @@ 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()) {
} }
/** /**
* @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) {
int idx = ox_lastIndexOf(m_path, '/', m_maxSize); const auto idx = ox::lastIndexOf(m_path, '/', m_maxSize);
std::size_t size = 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 {
@ -41,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 = 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 {
@ -58,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;
@ -73,90 +77,80 @@ 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);
} }
std::size_t end = 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++;
} }
std::size_t 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);
} }
std::size_t end = 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++;
} }
std::size_t 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);
} }
std::size_t end = substr - m_path; const auto end = static_cast<std::size_t>(substr - m_path);
size = end - start; size = end - start;
} }
it += size; it += size;
@ -165,18 +159,18 @@ 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);
} }
std::size_t end = substr - m_path; const auto end = static_cast<std::size_t>(substr - m_path);
size = end - start; size = end - start;
} }
return size > 0; return size > 0;
@ -189,22 +183,22 @@ 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++;
} }
std::size_t 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);
} }
std::size_t end = substr - m_path; const auto end = static_cast<std::size_t>(substr - m_path);
size = end - start; size = end - start;
} }
iterator += size; iterator += size;
return PathIterator(m_path, m_maxSize, iterator + 1); return {m_path, m_maxSize, iterator + 1};
} }
const char *PathIterator::fullPath() const { const char *PathIterator::fullPath() const {

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:
@ -26,6 +26,8 @@ class PathIterator {
PathIterator(const char *path); PathIterator(const char *path);
PathIterator(CRStringView path);
/** /**
* @return 0 if no error * @return 0 if no error
*/ */
@ -39,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 - 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
@ -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 {
@ -97,9 +97,9 @@ class OX_PACKED NodeBuffer {
Header m_header; Header m_header;
public: public:
NodeBuffer(const NodeBuffer &other, size_t size) noexcept; NodeBuffer(const NodeBuffer &other, std::size_t size) noexcept;
explicit NodeBuffer(size_t size) noexcept; explicit NodeBuffer(std::size_t size) noexcept;
[[nodiscard]] [[nodiscard]]
const Iterator iterator() const noexcept; const Iterator iterator() const noexcept;
@ -129,7 +129,7 @@ class OX_PACKED NodeBuffer {
ItemPtr ptr(size_t offset) noexcept; ItemPtr ptr(size_t offset) noexcept;
Result<ItemPtr> malloc(size_t size) noexcept; Result<ItemPtr> malloc(std::size_t size) noexcept;
Error free(ItemPtr item) noexcept; Error free(ItemPtr item) noexcept;
@ -139,7 +139,7 @@ class OX_PACKED NodeBuffer {
/** /**
* Set size, capacity. * Set size, capacity.
*/ */
Error setSize(size_t size) noexcept; Error setSize(std::size_t size) noexcept;
/** /**
* Get size, capacity. * Get size, capacity.
@ -159,7 +159,7 @@ class OX_PACKED NodeBuffer {
* bytes * bytes
*/ */
[[nodiscard]] [[nodiscard]]
static size_t spaceNeeded(size_t size) noexcept; static size_t spaceNeeded(std::size_t size) noexcept;
template<typename F> template<typename F>
Error compact(F cb = [](uint64_t, ItemPtr) {}) noexcept; Error compact(F cb = [](uint64_t, ItemPtr) {}) noexcept;
@ -171,17 +171,17 @@ class OX_PACKED NodeBuffer {
}; };
template<typename size_t, typename Item> template<typename size_t, typename Item>
NodeBuffer<size_t, Item>::NodeBuffer(size_t size) noexcept { NodeBuffer<size_t, Item>::NodeBuffer(std::size_t size) noexcept {
m_header.size = 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));
oxTrace("ox::NodeBuffer::constructor") << m_header.firstItem; 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, 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 {
oxTrace("ox::ptrarith::NodeBuffer::iterator::size") << m_header.size; oxTracef("ox.ptrarith.NodeBuffer.iterator.size", "{}", m_header.size.get());
return Iterator(this, firstItem()); return Iterator(this, firstItem());
} }
@ -265,9 +265,10 @@ 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(size_t size) noexcept { Result<typename NodeBuffer<size_t, Item>::ItemPtr> NodeBuffer<size_t, Item>::malloc(std::size_t size) noexcept {
oxTracef("ox::ptrarith::NodeBuffer::malloc", "Size: {}", size); const auto sz = static_cast<std::size_t>(size);
size_t fullSize = size + sizeof(Item); oxTracef("ox.ptrarith.NodeBuffer.malloc", "Size: {}", sz);
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();
size_t addr; size_t addr;
@ -276,23 +277,23 @@ 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 = 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(size); out->setSize(sz);
auto first = firstItem(); auto first = firstItem();
auto oldLast = last; auto oldLast = last;
@ -300,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.");
} }
@ -310,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()) {
@ -337,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);
} }
} }
@ -355,18 +356,18 @@ 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(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 = 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);
} }
} }
@ -387,8 +388,8 @@ size_t NodeBuffer<size_t, Item>::available() const noexcept {
} }
template<typename size_t, typename Item> template<typename size_t, typename Item>
size_t NodeBuffer<size_t, Item>::spaceNeeded(size_t size) noexcept { size_t NodeBuffer<size_t, Item>::spaceNeeded(std::size_t size) noexcept {
return sizeof(Item) + size; return static_cast<size_t>(sizeof(Item) + size);
} }
template<typename size_t, typename Item> template<typename size_t, typename Item>
@ -404,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);
@ -442,8 +443,8 @@ struct OX_PACKED Item {
return m_size; return m_size;
} }
void setSize(size_t size) { void setSize(std::size_t size) {
m_size = size; m_size = static_cast<size_t>(size);
} }
}; };

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
@ -29,7 +29,13 @@ class [[nodiscard]] Ptr {
constexpr Ptr(std::nullptr_t) noexcept; constexpr Ptr(std::nullptr_t) noexcept;
constexpr Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize = sizeof(T), size_t itemTypeSize = sizeof(T), bool prevalidated = false) noexcept; constexpr Ptr(
void *pDataStart,
std::size_t pDataSize,
std::size_t pItemStart,
std::size_t pItemSize = sizeof(T),
std::size_t pItemTypeSize = sizeof(T),
bool pPrevalidated = false) noexcept;
[[nodiscard]] [[nodiscard]]
constexpr bool valid() const noexcept; constexpr bool valid() const noexcept;
@ -86,17 +92,27 @@ constexpr Ptr<T, size_t, minOffset>::Ptr(std::nullptr_t) noexcept {
} }
template<typename T, typename size_t, size_t minOffset> template<typename T, typename size_t, size_t minOffset>
constexpr Ptr<T, size_t, minOffset>::Ptr(void *dataStart, size_t dataSize, size_t itemStart, size_t itemSize, size_t itemTypeSize, bool prevalidated) noexcept { constexpr Ptr<T, size_t, minOffset>::Ptr(
void *pDataStart,
std::size_t pDataSize,
std::size_t pItemStart,
std::size_t pItemSize,
std::size_t pItemTypeSize,
bool pPrevalidated) noexcept {
const auto dataSize = static_cast<size_t>(pDataSize);
const auto itemStart = static_cast<size_t>(pItemStart);
const auto itemSize = static_cast<size_t>(pItemSize);
const auto itemTypeSize = static_cast<size_t>(pItemTypeSize);
// do some sanity checks before assuming this is valid // do some sanity checks before assuming this is valid
if (itemSize >= itemTypeSize && if (itemSize >= itemTypeSize &&
dataStart && pDataStart &&
itemStart >= minOffset && itemStart >= minOffset &&
itemStart + itemSize <= dataSize) { itemStart + itemSize <= dataSize) {
m_dataStart = reinterpret_cast<uint8_t*>(dataStart); m_dataStart = reinterpret_cast<uint8_t*>(pDataStart);
m_dataSize = dataSize; m_dataSize = dataSize;
m_itemOffset = itemStart; m_itemOffset = itemStart;
m_itemSize = itemSize; m_itemSize = itemSize;
m_validated = prevalidated; m_validated = pPrevalidated;
} }
} }
@ -208,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);
} }
@ -221,8 +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); 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 - 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 <cstdio> #include <cstdio>
@ -26,7 +26,7 @@ static ox::Result<Buff> loadFsBuff(const char *path) noexcept {
const auto size = static_cast<std::size_t>(file.tellg()); const auto size = static_cast<std::size_t>(file.tellg());
file.seekg(0, std::ios::beg); file.seekg(0, std::ios::beg);
const auto buff = new char[size]; const auto buff = new char[size];
file.read(buff, size); file.read(buff, static_cast<std::streamsize>(size));
return Buff{buff, size}; return Buff{buff, size};
} catch (const std::ios_base::failure &e) { } catch (const std::ios_base::failure &e) {
oxErrorf("Could not read OxFS file: {}", e.what()); oxErrorf("Could not read OxFS file: {}", e.what());
@ -56,7 +56,7 @@ static ox::Error runRead(ox::FileSystem *fs, int argc, const char **argv) noexce
oxErr("Must provide a path to a file to read\n"); oxErr("Must provide a path to a file to read\n");
return OxError(1); return OxError(1);
} }
oxRequire(buff, fs->read(argv[1])); oxRequire(buff, fs->read(ox::StringView(argv[1])));
fwrite(buff.data(), sizeof(decltype(buff)::value_type), buff.size(), stdout); fwrite(buff.data(), sizeof(decltype(buff)::value_type), buff.size(), stdout);
return OxError(0); return OxError(0);
} }
@ -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);

40
deps/ox/src/ox/logconn/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,40 @@
cmake_minimum_required(VERSION 3.10)
add_library(
OxLogConn
logconn.cpp
)
set_property(
TARGET
OxLogConn
PROPERTY
POSITION_INDEPENDENT_CODE ON
)
if(NOT MSVC)
target_compile_options(OxLogConn PRIVATE -Wsign-conversion)
endif()
target_link_libraries(
OxLogConn PUBLIC
OxStd
OxMetalClaw
$<$<BOOL:${OX_OS_FREEBSD}>:pthread>
$<$<BOOL:${OX_OS_WINDOWS}>:ws2_32>
)
install(
FILES
circularbuff.hpp
logconn.hpp
DESTINATION
include/ox/logconn
)
install(
TARGETS
OxLogConn
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)

99
deps/ox/src/ox/logconn/circularbuff.hpp vendored Normal file
View File

@ -0,0 +1,99 @@
/*
* 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/.
*/
#pragma once
#include <ox/std/assert.hpp>
#include <ox/std/buffer.hpp>
#include <ox/std/units.hpp>
namespace ox::detail {
class CirculerBuffer {
private:
std::size_t m_readPt = 0;
std::size_t m_writePt = 0;
ox::Buffer m_buff = ox::Buffer(ox::units::MB);
private:
[[nodiscard]]
constexpr auto avail() const noexcept {
if (m_writePt >= m_readPt) {
return m_buff.size() - (m_writePt - m_readPt);
} else {
return (m_buff.size() - m_writePt) - (m_buff.size() - m_readPt);
}
}
public:
constexpr ox::Error put(char v) noexcept {
return write(&v, 1);
if (1 > avail()) {
return OxError(1, "Insufficient space in buffer");
}
m_buff[m_writePt] = v;
++m_writePt;
return {};
}
constexpr ox::Error write(const char *buff, std::size_t sz) noexcept {
if (sz > avail()) {
return OxError(1, "Insufficient space in buffer");
}
// write seg 1
const auto seg1Sz = ox::min(sz, m_buff.size() - m_writePt);
ox::listcpy(&m_buff[m_writePt], &buff[0], seg1Sz);
m_writePt += sz;
if (seg1Sz != sz) {
m_writePt -= m_buff.size();
// write seg 2
const auto seg2Sz = sz - seg1Sz;
ox::listcpy(&m_buff[0], &buff[seg1Sz], seg2Sz);
oxAssert(m_buff[0] == buff[seg1Sz], "break");
}
return {};
}
constexpr ox::Error seekp(std::size_t bytesFwd) noexcept {
if (bytesFwd > avail()) {
return OxError(1, "Insufficient space in buffer to seek that far ahead");
}
m_writePt += bytesFwd;
if (m_writePt > m_buff.size()) {
m_writePt -= m_buff.size();
}
return {};
}
constexpr ox::Error seekp(int, ios_base::seekdir) noexcept {
return OxError(1, "Unimplemented");
}
[[nodiscard]]
constexpr std::size_t tellp() const noexcept {
return m_buff.size() - avail();
}
[[nodiscard]]
constexpr std::size_t read(char *out, std::size_t outSize) noexcept {
const auto bytesRead = ox::min(outSize, m_buff.size() - avail());
// read seg 1
const auto seg1Sz = ox::min(bytesRead, m_buff.size() - m_readPt);
ox::listcpy(&out[0], &m_buff[m_readPt], seg1Sz);
m_readPt += bytesRead;
if (seg1Sz != bytesRead) {
m_readPt -= m_buff.size();
// read seg 2
const auto seg2Sz = bytesRead - seg1Sz;
ox::listcpy(&out[seg1Sz], &m_buff[0], seg2Sz);
}
return bytesRead;
}
};
}

27
deps/ox/src/ox/logconn/def.hpp vendored Normal file
View File

@ -0,0 +1,27 @@
/*
* 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/.
*/
#pragma once
#if defined(DEBUG) && !defined(OX_BARE_METAL)
#define OX_INIT_DEBUG_LOGGER(loggerName, appName) \
ox::LoggerConn loggerName; \
{ \
const auto loggerErr = (loggerName).initConn(appName); \
if (loggerErr) { \
oxErrf("Could not connect to logger: {} ({}:{})\n", toStr(loggerErr), loggerErr.file, loggerErr.line); \
} else { \
ox::trace::setLogger(&(loggerName)); \
} \
ox::trace::init(); \
}
#else
#define OX_INIT_DEBUG_LOGGER(loggerName, appName)
#endif

107
deps/ox/src/ox/logconn/logconn.cpp vendored Normal file
View File

@ -0,0 +1,107 @@
/*
* 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/.
*/
#ifdef OX_USE_STDLIB
#include <cstdio>
#include <sys/types.h>
#ifndef _WIN32
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <unistd.h>
#else
#include <winsock.h>
#undef interface
#undef min
#undef max
#endif
#include "logconn.hpp"
#include <ox/std/bit.hpp>
namespace ox {
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_running = false;
m_waitCond.notify_one();
m_netThread.join();
if (m_socket) {
closeSock(m_socket);
}
}
ox::Error LoggerConn::initConn(ox::CRStringView appName) noexcept {
sockaddr_in addr{};
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_port = htons(5590);
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
oxReturnError(OxError(static_cast<ox::ErrorCode>(connect(m_socket, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)))));
return sendInit({.appName = ox::BasicString<128>(appName)});
}
ox::Error LoggerConn::send(const char *buff, std::size_t len) const noexcept {
std::size_t totalSent = 0;
while (totalSent < len) {
//std::fprintf(stdout, "Sending %lu/%lu bytes on socket %d\n", len, totalSent, m_socket);
const auto sent = ::send(m_socket, buff, len, 0);
if (sent < 0) {
std::fprintf(stderr, "Could not send msg\n");
return OxError(1, "Could not send msg");
}
totalSent += static_cast<std::size_t>(sent);
}
return {};
}
ox::Error LoggerConn::send(const TraceMsg &msg) noexcept {
return send(MsgId::TraceEvent, msg);
}
ox::Error LoggerConn::sendInit(const InitTraceMsg &msg) noexcept {
return send(MsgId::Init, msg);
}
void LoggerConn::msgSend() noexcept {
while (true) {
std::unique_lock lk(m_waitMut);
m_waitCond.wait(lk);
if (!m_running) {
break;
}
std::lock_guard buffLk(m_buffMut);
while (true) {
ox::Array<char, ox::units::KB> tmp;
const auto read = m_buff.read(tmp.data(), tmp.size());
if (!read) {
break;
}
//std::printf("LoggerConn: sending %lu bytes\n", read);
std::ignore = send(tmp.data(), read);
}
}
}
}
#endif

78
deps/ox/src/ox/logconn/logconn.hpp vendored Normal file
View File

@ -0,0 +1,78 @@
/*
* 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/.
*/
#pragma once
#ifdef OX_USE_STDLIB
#include <condition_variable>
#include <mutex>
#include <thread>
#endif
#include <ox/mc/write.hpp>
#include <ox/std/trace.hpp>
#include "circularbuff.hpp"
namespace ox {
#ifdef OX_USE_STDLIB
class LoggerConn: public trace::Logger {
private:
int m_socket = 0;
detail::CirculerBuffer m_buff;
std::thread m_netThread;
std::condition_variable m_waitCond;
std::mutex m_waitMut;
std::mutex m_buffMut;
bool m_running = true;
public:
LoggerConn() noexcept;
LoggerConn(const LoggerConn&) noexcept = delete;
~LoggerConn() noexcept override;
LoggerConn &operator=(const LoggerConn&) noexcept = delete;
ox::Error send(const trace::TraceMsg&) noexcept final;
ox::Error sendInit(const trace::InitTraceMsg&) noexcept final;
ox::Error initConn(ox::CRStringView appName) noexcept;
ox::Error send(const char *buff, std::size_t len) const noexcept;
private:
void msgSend() noexcept;
ox::Error send(trace::MsgId msgId, const auto &msg) noexcept {
ox::Array<char, 10 * ox::units::KB> buff;
std::size_t sz = 0;
oxReturnError(ox::writeMC(&buff[0], buff.size(), msg, &sz));
//std::printf("sz: %lu\n", sz);
oxRequire(szBuff, serialize(static_cast<uint32_t>(sz)));
std::unique_lock buffLk(m_buffMut);
oxReturnError(m_buff.put(static_cast<char>(msgId)));
oxReturnError(m_buff.write(szBuff.data(), szBuff.size()));
oxReturnError(m_buff.write(buff.data(), sz));
buffLk.unlock();
m_waitCond.notify_one();
return {};
}
};
#else
class LoggerConn: public trace::Logger {
private:
public:
constexpr LoggerConn() noexcept = default;
LoggerConn(const LoggerConn&) noexcept = delete;
constexpr ~LoggerConn() noexcept override = default;
LoggerConn &operator=(const LoggerConn&) noexcept = delete;
ox::Error send(const trace::TraceMsg&) noexcept final { return {}; }
static ox::Error initConn() noexcept { return {}; }
static ox::Error send(const char*, std::size_t) noexcept { return {}; }
};
#endif
}

View File

@ -7,6 +7,7 @@ add_library(
if(NOT MSVC) if(NOT MSVC)
target_compile_options(OxMetalClaw PRIVATE -Wsign-conversion) target_compile_options(OxMetalClaw PRIVATE -Wsign-conversion)
target_compile_options(OxMetalClaw PRIVATE -Wconversion)
endif() endif()
target_link_libraries( target_link_libraries(
@ -38,8 +39,8 @@ install(
) )
install(TARGETS OxMetalClaw install(TARGETS OxMetalClaw
LIBRARY DESTINATION lib/ox LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/ox ARCHIVE DESTINATION lib
) )
if(OX_RUN_TESTS) if(OX_RUN_TESTS)

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,26 +1,86 @@
/* /*
* 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/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"
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 Result<bool> get(std::size_t i) const noexcept; constexpr Result<bool> get(std::size_t i) const noexcept;
@ -34,39 +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 Result<bool> FieldBitmapReader<T>::get(std::size_t i) const noexcept { constexpr auto FieldBitmapWriterBase<T>::setBuffer(T map, std::size_t maxLen) noexcept {
m_map = map;
m_mapLen = maxLen;
}
template<typename T>
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;
@ -75,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 {
@ -83,11 +150,11 @@ constexpr Error FieldBitmap::set(std::size_t i, bool on) noexcept {
if (on) { if (on) {
m_map[i / 8] |= 1 << (i % 8); m_map[i / 8] |= 1 << (i % 8);
} else { } else {
m_map[i / 8] &= ~(1 << (i % 8)); m_map[i / 8] &= ~static_cast<uint8_t>(1 << (i % 8));
} }
return OxError(0); 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 - 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
@ -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;
int m_fields = 0; std::size_t m_fields = 0;
int 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,18 +94,20 @@ 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 void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion, constexpr ox::Error setTypeInfo(
const Vector<String>& = {}, int fields = ModelFieldCount_v<T>) noexcept; const char *name = T::TypeName,
int version = T::TypeVersion,
const Vector<String>& = {},
std::size_t fields = ModelFieldCount_v<T>) noexcept;
/** /**
* 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.
@ -125,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 || 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 || 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();
handler.setTypeInfo("List", 0, {}, static_cast<int>(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 || 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();
handler.setTypeInfo("List", 0, {}, static_cast<int>(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, static_cast<int>(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));
} }
} }
} }
@ -268,72 +257,72 @@ 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 || 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());
}
oxReturnError(ox::resizeVector(*val, 0));
}
++m_field;
return {};
} else if constexpr(isArray_v<T>) {
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
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
oxRequire(len, arrayLength(name, false));
if (len > val->size()) {
return OxError(1, "Input array is too long");
}
} }
return field(name, val->data(), val->size()); return field(name, val->data(), val->size());
} }
++m_field; ++m_field;
return OxError(0); return {};
} else { } else {
if ((m_unionIdx == -1 || 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;
return OxError(0); return {};
} }
} }
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 || 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 || 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);
}
memcpy(data, &m_buff[m_buffIt], size);
data[size] = 0;
m_buffIt += size;
} else { } else {
*val = ""; *val = "";
} }
@ -342,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 || 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);
@ -425,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) {
@ -443,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 || 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;
} }
@ -462,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 || 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;
} }
@ -484,23 +465,18 @@ 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 || 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();
handler.setTypeInfo("List", 0, {}, static_cast<int>(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;
oxReturnError(handler.field("", &val)); oxReturnError(handler.field("", &val));
@ -512,48 +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 || 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 void MetalClawReaderTemplate<HandlerMaker>::setTypeInfo(const char*, int, const Vector<String>&, int fields) noexcept { constexpr ox::Error MetalClawReaderTemplate<Reader>::setTypeInfo(
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(fields); return m_reader.seekg(
m_fieldPresence.setMaxLen(static_cast<int>(m_buffIt)); static_cast<int>((fields / 8 + 1) - (fields % 8 == 0)),
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(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);
@ -562,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;
@ -61,7 +62,7 @@ struct TestStruct {
template<typename T> template<typename T>
constexpr ox::Error model(T *io, ox::CommonPtrWith<TestUnion> auto *obj) noexcept { constexpr ox::Error model(T *io, ox::CommonPtrWith<TestUnion> auto *obj) noexcept {
io->template setTypeInfo<TestUnion>(); oxReturnError(io->template setTypeInfo<TestUnion>());
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->fieldCString("CString", &obj->CString)); oxReturnError(io->fieldCString("CString", &obj->CString));
@ -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 {
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,27 @@ 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));
return OxError(0); return OxError(0);
} }
}, },
@ -122,26 +124,26 @@ std::map<ox::String, ox::Error(*)()> tests = {
"MetalClawReader", "MetalClawReader",
[] { [] {
// setup for tests // setup for tests
static constexpr size_t buffLen = 1024;
char buff[buffLen];
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
oxAssert(ox::writeMC(buff, buffLen, &testIn), "writeMC failed"); const auto [buff, err] = ox::writeMC(testIn);
oxAssert(ox::readMC(buff, buffLen, &testOut), "readMC failed"); oxAssert(err, "writeMC 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,44 +304,44 @@ 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");
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");
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
@ -15,4 +15,7 @@
namespace ox { namespace ox {
template class ModelHandlerInterface<MetalClawWriter<BufferWriter>>;
template class ModelHandlerInterface<MetalClawWriter<CharBuffWriter>>;
} }

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
@ -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>
@ -27,54 +28,45 @@
namespace ox { namespace ox {
template<Writer_c Writer>
class MetalClawWriter { class MetalClawWriter {
private: private:
ox::Vector<uint8_t, 16> m_presenceMapBuff{};
FieldBitmap m_fieldPresence; FieldBitmap m_fieldPresence;
int m_fields = 0;
int m_field = 0; int m_field = 0;
int m_unionIdx = -1; ox::Optional<int> m_unionIdx;
std::size_t m_buffIt = 0; std::size_t m_writerBeginP{};
std::size_t m_buffLen = 0; Writer &m_writer;
uint8_t *m_buff = nullptr;
public: public:
constexpr MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx = -1) noexcept; constexpr explicit MetalClawWriter(Writer &writer, ox::Optional<int> const&unionIdx = {}) noexcept;
constexpr ~MetalClawWriter() noexcept; 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,338 +76,331 @@ 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;
template<typename T = std::nullptr_t> template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion, constexpr ox::Error setTypeInfo(
const Vector<String>& = {}, int fields = ModelFieldCount_v<T>) noexcept; const char *name = T::TypeName,
int version = T::TypeVersion,
const Vector<String>& = {},
std::size_t fields = ModelFieldCount_v<T>) noexcept;
/**
* stringLength is not implemented in MetalClawWriter
*/
[[nodiscard]] [[nodiscard]]
constexpr std::size_t size() const noexcept; constexpr auto stringLength(const char*) noexcept {
return 0;
}
/**
* stringLength is not implemented in MetalClawWriter
*/
[[nodiscard]]
constexpr auto arrayLength(const char*, bool = true) noexcept {
return 0;
}
[[nodiscard]] [[nodiscard]]
static constexpr auto opType() noexcept { static constexpr auto opType() noexcept {
return OpType::Write; return OpType::Write;
} }
ox::Error finalize() noexcept;
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);
if (mi.length < m_buffLen) { oxReturnError(m_writer.write(reinterpret_cast<const char*>(mi.data), mi.length));
fieldSet = true; fieldSet = true;
ox_memcpy(&m_buff[m_buffIt], mi.data, mi.length);
m_buffIt += mi.length;
} else {
return OxError(MC_BUFFENDED);
}
} }
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 OxError(0);
} }
}; };
constexpr MetalClawWriter::MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx) noexcept: extern template class ModelHandlerInterface<MetalClawWriter<BufferWriter>>;
m_fieldPresence(buff, buffLen), extern template class ModelHandlerInterface<MetalClawWriter<CharBuffWriter>>;
template<Writer_c Writer>
constexpr MetalClawWriter<Writer>::MetalClawWriter(Writer &writer, ox::Optional<int> const&unionIdx) noexcept:
m_fieldPresence(m_presenceMapBuff.data(), m_presenceMapBuff.size()),
m_unionIdx(unionIdx), m_unionIdx(unionIdx),
m_buffLen(buffLen), m_writerBeginP(writer.tellp()),
m_buff(buff) { m_writer(writer) {
} }
constexpr MetalClawWriter::~MetalClawWriter() noexcept { template<Writer_c Writer>
if (m_field != m_fields) { constexpr Error MetalClawWriter<Writer>::field(const char*, const int8_t *val) noexcept {
oxTrace("ox::mc::MetalClawWriter::error") << "MetalClawReader: incorrect fields number given";
}
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int8_t> auto *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int16_t> auto *val) noexcept { template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, const int16_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int32_t> auto *val) noexcept { template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, const int32_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int64_t> auto *val) noexcept { template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, const int64_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
template<Writer_c Writer>
constexpr Error MetalClawWriter::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);
} }
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint16_t> auto *val) noexcept { template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, const uint16_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint32_t> auto *val) noexcept { template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, const uint32_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint64_t> auto *val) noexcept { template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, const uint64_t *val) noexcept {
return appendInteger(*val); return appendInteger(*val);
} }
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<bool> auto *val) noexcept { template<Writer_c Writer>
if (m_unionIdx == -1 || m_unionIdx == m_field) { constexpr Error MetalClawWriter<Writer>::field(const char*, const bool *val) noexcept {
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;
return OxError(0); return OxError(0);
} }
template<Writer_c Writer>
template<std::size_t SmallStringSize> template<std::size_t SmallStringSize>
constexpr Error MetalClawWriter::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());
if (m_buffIt + strLen.length + static_cast<std::size_t>(val->len()) < m_buffLen) { oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLen.data), strLen.length));
memcpy(&m_buff[m_buffIt], strLen.data, strLen.length);
m_buffIt += strLen.length;
// write the string // write the string
memcpy(&m_buff[m_buffIt], val->c_str(), static_cast<std::size_t>(val->len())); oxReturnError(m_writer.write(val->c_str(), static_cast<std::size_t>(val->len())));
m_buffIt += static_cast<std::size_t>(val->len());
fieldSet = true; fieldSet = true;
} else {
return OxError(MC_BUFFENDED);
}
} }
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 OxError(0);
} }
template<Writer_c Writer>
template<std::size_t L> template<std::size_t L>
constexpr Error MetalClawWriter::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<std::size_t SmallStringSize> template<Writer_c Writer>
constexpr Error MetalClawWriter::field(const char *name, BasicString<SmallStringSize> *val) noexcept { constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *const*val, std::size_t) noexcept {
return field(name, const_cast<const BasicString<SmallStringSize>*>(val));
}
template<std::size_t L>
constexpr Error MetalClawWriter::field(const char *name, BString<L> *val) noexcept {
return fieldCString(name, val->data(), val->cap());
}
constexpr Error MetalClawWriter::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);
if (m_buffIt + strLenBuff.length + static_cast<std::size_t>(strLen) < m_buffLen) { oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data), strLenBuff.length));
ox_memcpy(&m_buff[m_buffIt], strLenBuff.data, strLenBuff.length);
m_buffIt += strLenBuff.length;
// write the string // write the string
ox_memcpy(&m_buff[m_buffIt], *val, static_cast<std::size_t>(strLen)); oxReturnError(m_writer.write(*val, static_cast<std::size_t>(strLen)));
m_buffIt += static_cast<std::size_t>(strLen);
fieldSet = true; fieldSet = true;
} else {
return OxError(MC_BUFFENDED);
}
} }
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 OxError(0);
} }
constexpr Error MetalClawWriter::fieldCString(const char *name, const char **val) noexcept { template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(const char *name, const char **val) noexcept {
return fieldCString(name, val, {}); return fieldCString(name, val, {});
} }
constexpr Error MetalClawWriter::fieldCString(const char *name, const char *const*val) noexcept { template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(const char *name, const char *const*val) noexcept {
return fieldCString(name, val, {}); return fieldCString(name, val, {});
} }
constexpr Error MetalClawWriter::fieldCString(const char*, const char *val, std::size_t strLen) noexcept { template<Writer_c Writer>
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);
if (m_buffIt + strLenBuff.length + static_cast<std::size_t>(strLen) < m_buffLen) { oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data), strLenBuff.length));
ox_memcpy(&m_buff[m_buffIt], strLenBuff.data, strLenBuff.length);
m_buffIt += strLenBuff.length;
// write the string // write the string
ox_memcpy(&m_buff[m_buffIt], val, static_cast<std::size_t>(strLen)); oxReturnError(m_writer.write(val, static_cast<std::size_t>(strLen)));
m_buffIt += static_cast<std::size_t>(strLen);
fieldSet = true; fieldSet = true;
} else {
return OxError(MC_BUFFENDED);
}
} }
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 OxError(0);
} }
template<Writer_c Writer>
template<typename T> template<typename T>
constexpr Error MetalClawWriter::field(const char*, T *val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const T *val) noexcept {
if constexpr(isVector_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)) {
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt); auto const writeIdx = m_writer.tellp();
ModelHandlerInterface handler{&writer}; MetalClawWriter<Writer> writer(m_writer);
ModelHandlerInterface<MetalClawWriter<Writer>> handler{&writer};
oxReturnError(model(&handler, val)); oxReturnError(model(&handler, val));
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) { oxReturnError(writer.finalize());
m_buffIt += writer.m_buffIt; fieldSet = writeIdx != m_writer.tellp();
fieldSet = true;
} }
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return {};
}
}
template<Writer_c Writer>
template<typename U, bool force>
constexpr Error MetalClawWriter<Writer>::field(const char*, UnionView<U, force> val) noexcept {
bool fieldSet = false;
if (val.get() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
auto const writeIdx = m_writer.tellp();
MetalClawWriter<Writer> writer(m_writer, ox::Optional<int>(ox::in_place, val.idx()));
ModelHandlerInterface handler{&writer};
oxReturnError(model(&handler, val.get()));
oxReturnError(writer.finalize());
fieldSet = writeIdx != m_writer.tellp();
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return {};
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter<Writer>::field(const char*, const T *val, std::size_t len) noexcept {
bool fieldSet = false;
if (len && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
const auto arrLen = mc::encodeInteger(len);
oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data), arrLen.length));
auto const writeIdx = m_writer.tellp();
MetalClawWriter<Writer> writer(m_writer);
ModelHandlerInterface handler{&writer};
oxReturnError(handler.template setTypeInfo<T>("List", 0, {}, static_cast<std::size_t>(len)));
// write the array
for (std::size_t i = 0; i < len; ++i) {
oxReturnError(handler.field("", &val[i]));
}
oxReturnError(writer.finalize());
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 OxError(0);
} }
}
template<typename U, bool force>
constexpr Error MetalClawWriter::field(const char*, UnionView<U, force> val) noexcept {
bool fieldSet = false;
if (val.get() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt, val.idx());
ModelHandlerInterface handler{&writer};
oxReturnError(model(&handler, val.get()));
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) {
m_buffIt += writer.m_buffIt;
fieldSet = true;
}
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
return OxError(0);
}
template<Writer_c Writer>
template<typename T> template<typename T>
constexpr Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String, T> *val) noexcept {
bool fieldSet = false;
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) {
// write the length
const auto arrLen = mc::encodeInteger(len);
if (m_buffIt + arrLen.length < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], arrLen.data, arrLen.length);
m_buffIt += arrLen.length;
} else {
return OxError(MC_BUFFENDED);
}
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
ModelHandlerInterface handler{&writer};
handler.setTypeInfo<T>("List", 0, {}, len);
// write the array
for (std::size_t i = 0; i < len; i++) {
oxReturnError(handler.field("", &val[i]));
}
m_buffIt += writer.m_buffIt;
fieldSet = true;
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
return OxError(0);
}
template<typename T>
constexpr Error MetalClawWriter::field(const char*, const HashMap<String, T> *val) noexcept {
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);
if (m_buffIt + arrLen.length < m_buffLen) { oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data), arrLen.length));
ox_memcpy(&m_buff[m_buffIt], arrLen.data, arrLen.length); // write map
m_buffIt += arrLen.length; MetalClawWriter<Writer> writer(m_writer);
} else {
return OxError(MC_BUFFENDED);
}
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
ModelHandlerInterface handler{&writer}; ModelHandlerInterface handler{&writer};
// double len for both key and value // double len for both key and value
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));
} }
m_buffIt += writer.m_buffIt; oxReturnError(writer.finalize());
fieldSet = true; fieldSet = true;
} }
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 OxError(0);
} }
template<Writer_c Writer>
template<typename T> template<typename T>
constexpr Error MetalClawWriter::field(const char *name, HashMap<String, T> *val) noexcept { constexpr ox::Error MetalClawWriter<Writer>::setTypeInfo(
return field(name, const_cast<const HashMap<String, T>*>(val)); const char*,
int,
const Vector<String>&,
std::size_t fields) noexcept {
const auto fieldPresenceLen = (fields - 1) / 8 + 1;
oxReturnError(m_writer.write(nullptr, fieldPresenceLen));
m_presenceMapBuff.resize(fieldPresenceLen);
m_fieldPresence.setBuffer(m_presenceMapBuff.data(), m_presenceMapBuff.size());
m_fieldPresence.setFields(static_cast<int>(fields));
return {};
} }
template<typename T> template<Writer_c Writer>
constexpr void MetalClawWriter::setTypeInfo(const char*, int, const Vector<String>&, int fields) noexcept { ox::Error MetalClawWriter<Writer>::finalize() noexcept {
m_fields = fields; const auto end = m_writer.tellp();
m_fieldPresence.setFields(fields); oxReturnError(m_writer.seekp(m_writerBeginP));
m_buffIt = static_cast<std::size_t>(m_fieldPresence.getMaxLen()); oxReturnError(m_writer.write(
ox_memset(m_buff, 0, m_buffIt); reinterpret_cast<const char*>(m_presenceMapBuff.data()),
m_presenceMapBuff.size()));
oxReturnError(m_writer.seekp(end));
return {};
} }
constexpr std::size_t MetalClawWriter::size() const noexcept { Result<Buffer> writeMC(Writer_c auto &writer, const auto &val) noexcept {
return m_buffIt; MetalClawWriter mcWriter(writer);
ModelHandlerInterface handler{&mcWriter};
oxReturnError(model(&handler, &val));
oxReturnError(mcWriter.finalize());
return {};
} }
Result<Buffer> writeMC(auto *val) noexcept { Result<Buffer> writeMC(auto const&val, std::size_t buffReserveSz = 2 * units::KB) noexcept {
Buffer buff(10 * units::MB); Buffer buff(buffReserveSz);
MetalClawWriter writer(reinterpret_cast<uint8_t*>(buff.data()), buff.size()); BufferWriter bw(&buff, 0);
ModelHandlerInterface handler{&writer}; oxReturnError(writeMC(bw, val));
oxReturnError(model(&handler, val)); buff.resize(bw.tellp());
buff.resize(writer.size());
return buff; return buff;
} }
Error writeMC(char *buff, std::size_t buffLen, 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 {
MetalClawWriter writer(reinterpret_cast<uint8_t*>(buff), buffLen); CharBuffWriter bw(buff, buffLen);
ModelHandlerInterface handler(&writer); oxReturnError(writeMC(bw, val));
auto err = model(&handler, val);
if (sizeOut) { if (sizeOut) {
*sizeOut = writer.size(); *sizeOut = bw.tellp();
} }
return err; return {};
} }
} }

View File

@ -5,6 +5,11 @@ add_library(
modelvalue.cpp modelvalue.cpp
) )
if(NOT MSVC)
target_compile_options(OxModel PRIVATE -Wconversion)
target_compile_options(OxModel PRIVATE -Wsign-conversion)
endif()
target_link_libraries( target_link_libraries(
OxModel PUBLIC OxModel PUBLIC
OxStd OxStd
@ -40,8 +45,8 @@ install(
) )
install(TARGETS OxModel install(TARGETS OxModel
LIBRARY DESTINATION lib/ox LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib/ox ARCHIVE DESTINATION lib
) )
if(OX_RUN_TESTS) if(OX_RUN_TESTS)

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
@ -10,8 +10,8 @@
#include <ox/std/concepts.hpp> #include <ox/std/concepts.hpp>
#define oxModelBegin(modelName) constexpr ox::Error model(auto *io, ox::CommonPtrWith<modelName> auto *o) noexcept { 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

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