Compare commits

..

691 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
584 changed files with 21493 additions and 13645 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
.current_build
.conanbuild
.idea
.mypy_cache
.stfolder
.stignore
scripts/__pycache__
pyenv
CMakeLists.txt.user
ROM.oxfs
Session.vim
@ -13,8 +16,7 @@ compile_commands.json
dist
graph_info.json
imgui.ini
nostalgia.gba
nostalgia.sav
nostalgia_media.oxfs
*.gba
*.sav
studio_state.json
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:
- src
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)
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")
if(BUILDCORE_TARGET STREQUAL "gba")
set(NOSTALGIA_BUILD_STUDIO OFF)
set(NOSTALGIA_BUILD_TYPE "GBA")
include(deps/gbabuildcore/base.cmake)
else()
set(NOSTALGIA_BUILD_TYPE "Native")
set(CMAKE_POSITION_INDEPENDENT_CODE ON)
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)
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()
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(NOSTALGIA_DIST_BIN bin)
set(NOSTALGIA_DIST_LIB lib)
set(NOSTALGIA_DIST_MODULE lib/nostalgia/modules)
set(NOSTALGIA_DIST_RESOURCES share)
endif()
add_subdirectory(deps/ox)
include_directories(
deps/ox/src
)
add_subdirectory(deps/teagba)
if(BUILDCORE_TARGET STREQUAL "gba")
add_subdirectory(deps/gbastartup)
else()
if(NOT BUILDCORE_TARGET STREQUAL "gba")
include_directories(
SYSTEM
deps/glfw/deps
deps/glfw/include
deps/imgui
deps/imgui/backends
deps/nfde/src/include
/usr/local/include
)
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/glutils)
add_subdirectory(deps/imgui)
add_subdirectory(deps/lodepng)
add_subdirectory(deps/nfde)

View File

@ -31,7 +31,6 @@ RUN dnf install -y clang \
python3-pip \
libglvnd-devel \
gtk3-devel
RUN pip install conan
###############################################################################
# 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
VCPKG_PKGS=sdl2 jsoncpp
include ${BUILDCORE_PATH}/base.mk
ifeq ($(OS),darwin)
NOSTALGIA_STUDIO=./dist/${CURRENT_BUILD}/nostalgia-studio.app/Contents/MacOS/nostalgia-studio
ifeq ($(BC_VAR_OS),darwin)
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
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
endif
.PHONY: pkg-gba
pkg-gba: install
${ENV_RUN} ./scripts/pkg-gba sample_project
pkg-gba: build
${BC_CMD_ENVRUN} ${BC_PY3} ./scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME}
.PHONY: run
run: install
./dist/${CURRENT_BUILD}/bin/nostalgia sample_project
run: build
./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME} sample_project
.PHONY: run-studio
run-studio: install
run-studio: build
${NOSTALGIA_STUDIO}
.PHONY: gba-run
gba-run: pkg-gba
${MGBA} nostalgia.gba
${MGBA} ${BC_VAR_PROJECT_NAME}.gba
.PHONY: debug
debug: install
${DEBUGGER} ./dist/${CURRENT_BUILD}/bin/nostalgia sample_project
debug: build
${BC_CMD_HOST_DEBUGGER} ./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME} sample_project
.PHONY: debug-studio
debug-studio: install
${DEBUGGER} ${NOSTALGIA_STUDIO}
debug-studio: build
${BC_CMD_HOST_DEBUGGER} ${NOSTALGIA_STUDIO}
.PHONY: 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
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
* 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 options: release, debug, asan, gba, gba-debug

View File

@ -49,7 +49,8 @@ else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual")
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-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-variable")
# release build options

190
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
# License, v. 2.0. If a copy of the MPL was not distributed with this
@ -9,89 +9,99 @@
ifeq (${OS},Windows_NT)
SHELL := powershell.exe
.SHELLFLAGS := -NoProfile -Command
OS=windows
HOST_ENV=${OS}
BC_VAR_OS=windows
else
OS=$(shell uname | tr [:upper:] [:lower:])
HOST_ENV=${OS}-$(shell uname -m)
BC_VAR_OS=$(shell uname | tr [:upper:] [:lower:])
endif
DEVENV=devenv$(shell pwd | sed 's/\//-/g')
DEVENV_IMAGE=${PROJECT_NAME}-devenv
ifneq ($(shell which docker 2> /dev/null),)
ifeq ($(shell docker inspect --format="{{.State.Status}}" ${DEVENV} 2>&1),running)
ENV_RUN=docker exec -i -t --user $(shell id -u ${USER}) ${DEVENV}
ifneq ($(shell which python3 2> /dev/null),)
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
ifneq ($(shell ${ENV_RUN} which python3 2> /dev/null),)
PYTHON3=python3
else
ifeq ($(shell ${ENV_RUN} python -c 'import sys; print(sys.version_info[0])'),3)
PYTHON3=python
ifdef BC_VAR_USE_DOCKER_DEVENV
ifneq ($(shell which docker 2> /dev/null),)
BC_VAR_DEVENV=devenv$(shell pwd | sed 's/\//-/g')
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
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
SCRIPTS=${BUILDCORE_PATH}/scripts
SETUP_BUILD=${PYTHON3} ${SCRIPTS}/setup-build.py
PYBB=${PYTHON3} ${SCRIPTS}/pybb.py
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
ifdef USE_VCPKG
ifndef VCPKG_DIR_BASE
VCPKG_DIR_BASE=.vcpkg
endif
ifndef VCPKG_VERSION
VCPKG_VERSION=2020.06
endif
VCPKG_TOOLCHAIN=--toolchain=${VCPKG_DIR}/scripts/buildsystems/vcpkg.cmake
endif
ifeq ($(OS),darwin)
DEBUGGER=lldb --
else
DEBUGGER=gdb --args
endif
BC_VAR_SCRIPTS=${BUILDCORE_PATH}/scripts
BC_CMD_SETUP_BUILD=${BC_CMD_PY3} ${BC_VAR_SCRIPTS}/setup-build.py
BC_CMD_PYBB=${BC_CMD_PY3} ${BC_VAR_SCRIPTS}/pybb.py
BC_CMD_HOST_PYBB=${BC_CMD_HOST_PY3} ${BC_VAR_SCRIPTS}/pybb.py
BC_CMD_CMAKE_BUILD=${BC_CMD_PYBB} cmake-build
BC_CMD_GETENV=${BC_CMD_PYBB} getenv
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)
VCPKG_DIR=$(VCPKG_DIR_BASE)/$(VCPKG_VERSION)-$(HOST_ENV)
CURRENT_BUILD=$(HOST_ENV)-$(shell ${ENV_RUN} ${PYBB} cat .current_build)
ifdef BC_VAR_USE_VCPKG
ifndef BC_VAR_VCPKG_DIR_BASE
BC_VAR_VCPKG_DIR_BASE=.vcpkg
endif
ifndef BC_VAR_VCPKG_VERSION
BC_VAR_VCPKG_VERSION=2023.08.09
endif
endif
.PHONY: build
build:
${ENV_RUN} ${CMAKE_BUILD} ${BUILD_PATH}
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH}
.PHONY: install
install:
${ENV_RUN} ${CMAKE_BUILD} ${BUILD_PATH} install
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} install
.PHONY: clean
clean:
${ENV_RUN} ${CMAKE_BUILD} ${BUILD_PATH} clean
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} clean
.PHONY: purge
purge:
${ENV_RUN} ${RM_RF} .current_build
${ENV_RUN} ${RM_RF} ${BUILD_PATH}
${ENV_RUN} ${RM_RF} dist
${BC_CMD_RM_RF} .current_build
${BC_CMD_RM_RF} ${BC_VAR_BUILD_PATH}
${BC_CMD_RM_RF} dist
${BC_CMD_RM_RF} compile_commands.json
.PHONY: test
test: build
${ENV_RUN} mypy ${SCRIPTS}
${ENV_RUN} ${CMAKE_BUILD} ${BUILD_PATH} test
${BC_CMD_ENVRUN} ${BC_CMD_PY3} -m mypy ${BC_VAR_SCRIPTS}
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} test
.PHONY: test-verbose
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
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
devenv-image:
docker build . -t ${DEVENV_IMAGE}
docker build . -t ${BC_VAR_DEVENV_IMAGE}
.PHONY: devenv-create
devenv-create:
docker run -d \
@ -103,71 +113,77 @@ devenv-create:
-v $(shell pwd):/usr/src/project \
-v /dev/shm:/dev/shm \
--restart=always \
--name ${DEVENV} \
-t ${DEVENV_IMAGE} bash
--name ${BC_VAR_DEVENV} \
-t ${BC_VAR_DEVENV_IMAGE} bash
.PHONY: devenv-destroy
devenv-destroy:
docker rm -f ${DEVENV}
ifdef ENV_RUN
docker rm -f ${BC_VAR_DEVENV}
ifdef BC_CMD_ENVRUN
.PHONY: devenv-shell
devenv-shell:
${ENV_RUN} bash
${BC_CMD_ENVRUN} bash
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
vcpkg: ${VCPKG_DIR} vcpkg-install
vcpkg: ${BC_VAR_VCPKG_DIR} vcpkg-install
${VCPKG_DIR}:
${ENV_RUN} ${RM_RF} ${VCPKG_DIR}
${ENV_RUN} mkdir -p ${VCPKG_DIR_BASE}
${ENV_RUN} git clone -b release --depth 1 --branch ${VCPKG_VERSION} https://github.com/microsoft/vcpkg.git ${VCPKG_DIR}
ifneq (${OS},windows)
${ENV_RUN} ${VCPKG_DIR}/bootstrap-vcpkg.sh
${BC_VAR_VCPKG_DIR}:
${BC_CMD_RM_RF} ${BC_VAR_VCPKG_DIR}
${BC_CMD_PYBB} mkdir ${BC_VAR_VCPKG_DIR_BASE}
${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 (${BC_VAR_OS},windows)
${BC_CMD_ENVRUN} ${BC_VAR_VCPKG_DIR}/bootstrap-vcpkg.sh
else
${ENV_RUN} ${VCPKG_DIR}/bootstrap-vcpkg.bat
${BC_CMD_ENVRUN} ${BC_VAR_VCPKG_DIR}/bootstrap-vcpkg.bat
endif
.PHONY: vcpkg-install
vcpkg-install:
ifneq (${OS},windows)
${VCPKG_DIR}/vcpkg install ${VCPKG_PKGS}
ifneq (${BC_VAR_OS},windows)
${BC_CMD_ENVRUN} ${BC_VAR_VCPKG_DIR}/vcpkg install ${BC_VAR_VCPKG_PKGS}
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
else ifdef USE_CONAN # USE_VCPKG ################################################
else ifdef USE_CONAN # USE_VCPKG / USE_CONAN ####################################
.PHONY: setup-conan
conan-config:
${ENV_RUN} conan profile new ${PROJECT_NAME} --detect --force
ifeq ($(OS),linux)
${ENV_RUN} conan profile update settings.compiler.libcxx=libstdc++11 ${PROJECT_NAME}
${BC_CMD_ENVRUN} conan profile new ${BC_VAR_PROJECT_NAME} --detect --force
ifeq ($(BC_VAR_OS),linux)
${BC_CMD_ENVRUN} conan profile update settings.compiler.libcxx=libstdc++11 ${BC_VAR_PROJECT_NAME}
else
${ENV_RUN} conan profile update settings.compiler.cppstd=20 ${PROJECT_NAME}
ifeq ($(OS),windows)
${ENV_RUN} conan profile update settings.compiler.runtime=static ${PROJECT_NAME}
${BC_CMD_ENVRUN} conan profile update settings.compiler.cppstd=20 ${BC_VAR_PROJECT_NAME}
ifeq ($(BC_VAR_OS),windows)
${BC_CMD_ENVRUN} conan profile update settings.compiler.runtime=static ${BC_VAR_PROJECT_NAME}
endif
endif
.PHONY: conan
conan:
${ENV_RUN} ${PYBB} conan-install ${PROJECT_NAME}
endif # USE_VCPKG ###############################################
${BC_CMD_PYBB} conan-install ${BC_VAR_PROJECT_NAME}
endif # USE_CONAN ###############################################
ifeq (${BC_VAR_OS},darwin)
.PHONY: 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
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
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
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
from typing import List, Optional
def mkdir(path: str):
if not os.path.exists(path):
os.mkdir(path)
import util
# this exists because Windows is utterly incapable of providing a proper rm -rf
def rm(path: str):
if (os.path.exists(path) or os.path.islink(path)) and not os.path.isdir(path):
os.remove(path)
elif os.path.isdir(path):
shutil.rmtree(path)
def mkdir(path: str) -> int:
try:
util.mkdir_p(path)
except Exception:
return 1
return 0
def rm_multi(paths: List[str]):
for path in paths:
util.rm(path)
def ctest_all() -> int:
@ -52,7 +54,10 @@ def cmake_build(base_path: str, target: Optional[str]) -> int:
# nothing to build
return 0
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:
args.extend(['--target', target])
err = subprocess.run(args).returncode
@ -67,16 +72,13 @@ def conan() -> int:
err = 0
try:
mkdir(conan_dir)
except:
except Exception:
return 1
if err != 0:
return err
args = ['conan', 'install', '../', '--build=missing', '-pr', project_name]
os.chdir(conan_dir)
err = subprocess.run(args).returncode
if err != 0:
return err
return 0
return subprocess.run(args).returncode
def cat(paths: List[str]) -> int:
@ -84,48 +86,70 @@ def cat(paths: List[str]) -> int:
try:
with open(path) as f:
data = f.read()
sys.stdout.write(data)
print(data)
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
sys.stdout.write('\n')
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:
if var_name not in os.environ:
return 1
sys.stdout.write(os.environ[var_name])
print(os.environ[var_name])
return 0
def hostname() -> int:
sys.stdout.write(platform.node())
print(platform.node())
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:
err = 0
if sys.argv[1] == 'mkdir':
try:
mkdir(sys.argv[2])
except:
err = 1
err = mkdir(sys.argv[2])
elif sys.argv[1] == 'rm':
for i in range(2, len(sys.argv)):
rm(sys.argv[i])
rm_multi(sys.argv[2:])
elif sys.argv[1] == 'conan-install':
err = conan()
elif sys.argv[1] == 'ctest-all':
err = ctest_all()
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':
err = cat(sys.argv[2:])
elif sys.argv[1] == 'debug':
err = debug(sys.argv[2:])
elif sys.argv[1] == 'getenv':
err = get_env(sys.argv[2])
elif sys.argv[1] == 'hostname':
err = hostname()
elif sys.argv[1] == 'hostenv':
err = host_env()
else:
sys.stderr.write('Command not found\n')
err = 1

View File

@ -15,18 +15,35 @@ import shutil
import subprocess
import sys
from pybb import mkdir, rm
import util
def main() -> int:
parser = argparse.ArgumentParser()
parser.add_argument('--target', help='Platform target',
default='{:s}-{:s}'.format(sys.platform, platform.machine()))
parser.add_argument('--build_type', 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 of build directories (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)
parser.add_argument(
'--target',
help='Platform target',
default=f'{util.get_os()}-{util.get_arch()}')
parser.add_argument(
'--build_type',
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()
if args.build_type == 'asan':
@ -64,10 +81,10 @@ def main() -> int:
return 1
project_dir = os.getcwd()
build_dir = '{:s}/{:s}/{:s}'.format(project_dir, args.build_root, build_config)
rm(build_dir)
build_dir = f'{project_dir}/{args.build_root}/{build_config}'
util.rm(build_dir)
cmake_cmd = [
'cmake', '-S', project_dir, '-B', build_dir, build_tool,
'cmake', '-S', project_dir, '-B', build_dir,
'-DCMAKE_EXPORT_COMPILE_COMMANDS=ON',
'-DCMAKE_TOOLCHAIN_FILE={:s}'.format(args.toolchain),
'-DCMAKE_BUILD_TYPE={:s}'.format(build_type_arg),
@ -75,22 +92,27 @@ def main() -> int:
'-DBUILDCORE_BUILD_CONFIG={:s}'.format(build_config),
'-DBUILDCORE_TARGET={:s}'.format(args.target),
]
if build_tool != '':
cmake_cmd.append(build_tool)
if qt_path != '':
cmake_cmd.append(qt_path)
if platform.system() == 'Windows':
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:
cb = open('.current_build', 'w')
cb.write(args.build_type)
cb.close()
rm('compile_commands.json')
util.rm('compile_commands.json')
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

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)
macro(OBJCOPY_FILE EXE_NAME)
set(FO ${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME}.bin)
set(FI ${CMAKE_CURRENT_BINARY_DIR}/${EXE_NAME})
set(FO ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${EXE_NAME}.bin)
set(FI ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/${EXE_NAME})
message(STATUS ${FO})
# run objcopy

View File

@ -1,12 +0,0 @@
enable_language(CXX 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
@ -8,15 +8,18 @@
#include <glad/glad.h>
#include <ox/std/bounds.hpp>
#include <ox/std/cstringview.hpp>
#include <ox/std/error.hpp>
#include <ox/std/size.hpp>
#include <ox/std/string.hpp>
#include <ox/std/vector.hpp>
namespace nostalgia::glutils {
namespace glutils {
constexpr auto GlslVersion = "#version 330";
struct Empty {};
struct Empty {
virtual ~Empty() noexcept = default;
};
struct TextureBase {
@ -40,6 +43,8 @@ struct TextureBase {
return *this;
}
virtual ~TextureBase() noexcept = default;
};
@ -59,7 +64,7 @@ struct GLObject: public Base {
o.id = 0;
}
~GLObject() noexcept {
~GLObject() noexcept override {
del(id);
}
@ -106,7 +111,7 @@ extern template struct GLObject<deleteProgram>;
extern template struct GLObject<deleteShader>;
using GLBuffer = GLObject<deleteBuffer>;
using GLFrameBuffer = GLObject<deleteBuffer>;
using GLFrameBuffer = GLObject<deleteFrameBuffer>;
using GLRenderBuffer = GLObject<deleteRenderBuffer>;
using GLShader = GLObject<deleteShader>;
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;
@ -146,6 +191,15 @@ glutils::GLBuffer generateBuffer() noexcept;
[[nodiscard]]
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 {
glutils::GLVertexArray vao;
glutils::GLBuffer vbo;
@ -155,8 +209,10 @@ struct BufferSet {
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_opengl3.cpp
)
target_include_directories(
imgui SYSTEM PUBLIC
.
)

View File

@ -12,3 +12,11 @@ target_include_directories(
lodepng PUBLIC SYSTEM
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)
if(NOT MSVC)
@ -11,7 +11,7 @@ if(WIN32)
elseif(APPLE)
set(nfd_PLATFORM PLATFORM_MACOS)
elseif(UNIX AND NOT APPLE)
set(nfd_PLATFORM PLATFORM_LINUX)
set(nfd_PLATFORM PLATFORM_UNIX)
endif()
message("nfd Platform: ${nfd_PLATFORM}")

View File

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

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

@ -2,7 +2,7 @@
source:
- src
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
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)
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)
include(address_sanitizer)
@ -76,10 +76,11 @@ enable_testing()
include_directories(src)
install(FILES OxConfig.cmake DESTINATION lib/ox)
install(FILES OxConfig.cmake DESTINATION lib/cmake/ox)
if(OX_USE_STDLIB)
set(JSONCPP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/jsoncpp/include")
add_subdirectory(deps/jsoncpp)
endif()
add_subdirectory(deps/cityhash)
add_subdirectory(src)

View File

@ -1,15 +1,16 @@
if("${CMAKE_FIND_ROOT_PATH}" STREQUAL "")
set(Ox_INCLUDE_DIRS /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)
set(OX_PATH /usr/local/include/)
else("${CMAKE_FIND_ROOT_PATH}" STREQUAL "")
set(Ox_INCLUDE_DIRS ${CMAKE_FIND_ROOT_PATH}/include/)
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)
set(OX_PATH ${CMAKE_FIND_ROOT_PATH})
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)
add_subdirectory(oc)
endif()

View File

@ -12,6 +12,11 @@ set_property(
POSITION_INDEPENDENT_CODE ON
)
if(NOT MSVC)
target_compile_options(OxClArgs PRIVATE -Wsign-conversion)
target_compile_options(OxClArgs PRIVATE -Wconversion)
endif()
target_link_libraries(
OxClArgs PUBLIC
OxStd
@ -27,6 +32,6 @@ install(
install(
TARGETS
OxClArgs
LIBRARY DESTINATION lib/ox
ARCHIVE DESTINATION lib/ox
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)

View File

@ -1,9 +1,9 @@
/*
* Copyright 2015 - 2022 gary@drinkingtea.net
* Copyright 2015 - 2024 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* 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>
@ -12,25 +12,25 @@
namespace ox {
ClArgs::ClArgs(int argc, const char **args) noexcept {
for (int i = 0; i < argc; i++) {
String arg = args[i];
for (auto i = 0u; i < static_cast<unsigned>(argc); ++i) {
auto arg = String(args[i]);
if (arg[0] == '-') {
while (arg[0] == '-' && arg.len()) {
arg = arg.substr(1);
}
m_bools[arg] = true;
// parse additional arguments
if (i < argc && args[i + 1]) {
String val = args[i + 1];
if (i < static_cast<unsigned>(argc) && args[i + 1]) {
auto val = String(args[i + 1]);
if (val.len() && val[i] != '-') {
if (val == "false") {
m_bools[arg] = false;
}
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;
}
i++;
++i;
}
}
}
@ -42,9 +42,9 @@ bool ClArgs::getBool(ox::CRStringView arg, bool defaultValue) const noexcept {
return !err ? *value : defaultValue;
}
String ClArgs::getString(ox::CRStringView arg, const char *defaultValue) const noexcept {
String ClArgs::getString(ox::CRStringView arg, ox::StringView defaultValue) const noexcept {
auto [value, err] = m_strings.at(arg);
return !err ? *value : defaultValue;
return !err ? ox::String(*value) : ox::String(defaultValue);
}
int ClArgs::getInt(ox::CRStringView arg, int defaultValue) const noexcept {

View File

@ -1,9 +1,9 @@
/*
* Copyright 2015 - 2022 gary@drinkingtea.net
* Copyright 2015 - 2024 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* 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
@ -26,13 +26,15 @@ class ClArgs {
bool getBool(ox::CRStringView arg, bool defaultValue) const noexcept;
[[nodiscard]]
String getString(ox::CRStringView argName, const char *defaultArg) const noexcept;
String getString(ox::CRStringView argName, ox::StringView defaultValue) const noexcept;
[[nodiscard]]
int getInt(ox::CRStringView arg, int defaultValue) const noexcept;
[[nodiscard]]
Result<bool> getBool(ox::CRStringView arg) const noexcept;
[[nodiscard]]
Result<String> getString(ox::CRStringView argName) const noexcept;
Result<int> getInt(ox::CRStringView arg) const noexcept;

View File

@ -5,6 +5,10 @@ add_library(
write.cpp
)
if(NOT MSVC)
target_compile_options(OxClaw PRIVATE -Wsign-conversion)
target_compile_options(OxClaw PRIVATE -Wconversion)
endif()
target_link_libraries(
OxClaw PUBLIC
@ -12,6 +16,22 @@ target_link_libraries(
$<$<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)
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
* 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

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

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
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -12,34 +12,66 @@
namespace ox {
Result<ClawHeader> readClawHeader(const char *buff, std::size_t buffLen) noexcept {
const auto s1End = ox_strchr(buff, ';', buffLen);
ox::Result<ox::StringView> readClawTypeId(ox::BufferView buff) noexcept {
auto buffRaw = buff.data();
auto buffLen = buff.size();
size_t outSz{};
const auto s1End = ox::strchr(buffRaw, ';', buffLen);
if (!s1End) {
return OxError(1, "Could not read Claw header");
}
const auto s1Size = s1End - buff;
const String fmt(buff, s1Size);
buff += s1Size + 1;
buffLen -= s1Size + 1;
const auto s2End = ox_strchr(buff, ';', buffLen);
auto const fmtSz = static_cast<std::size_t>(s1End - buffRaw) + 1;
buffRaw += fmtSz;
buffLen -= fmtSz;
outSz += fmtSz;
auto const s2End = ox::strchr(buffRaw, ';', buffLen);
if (!s2End) {
return OxError(2, "Could not read Claw header");
}
const auto s2Size = s2End - buff;
const String typeName(buff, s2Size);
buff += s2Size + 1;
buffLen -= s2Size + 1;
const auto s3End = ox_strchr(buff, ';', buffLen);
auto const s2Size = static_cast<std::size_t>(s2End - buffRaw) + 1;
buffRaw += s2Size;
buffLen -= s2Size;
outSz += s2Size;
auto const s3End = ox::strchr(buffRaw, ';', buffLen) + 1;
if (!s3End) {
return OxError(3, "Could not read Claw header");
}
const auto s3Size = s3End - buff;
const String versionStr(buff, s3Size);
buff += s3Size + 1;
buffLen -= s3Size + 1;
auto const s3Size = static_cast<std::size_t>(s3End - buffRaw);
buffRaw += s3Size;
buffLen -= s3Size;
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;
if (fmt == "M2") {
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");
}
hdr.typeName = typeName;
if (auto r = ox_atoi(versionStr.c_str()); r.error == 0) {
hdr.typeVersion = r.value;
}
hdr.data = buff;
std::ignore = ox::atoi(versionStr).copyTo(hdr.typeVersion);
hdr.data = buffRaw;
hdr.dataSize = buffLen;
return hdr;
}
Result<ClawHeader> readClawHeader(const ox::Buffer &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 {
Result<BufferView> stripClawHeader(ox::BufferView buff) noexcept {
oxRequire(header, readClawHeader(buff));
oxRequire(t, ts->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;
oxReturnError(obj.setType(t));
switch (header.fmt) {
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);
oxReturnError(model(&handler, &obj));
return obj;
@ -88,7 +113,7 @@ Result<ModelObject> readClaw(TypeStore *ts, const Buffer &buff) noexcept {
case ClawFormat::Organic:
{
#ifdef OX_USE_STDLIB
OrganicClawReader reader(header.data, header.dataSize);
OrganicClawReader reader({header.data, header.dataSize});
ModelHandlerInterface handler(&reader);
oxReturnError(model(&handler, &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
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -8,6 +8,7 @@
#pragma once
#include <ox/std/span.hpp>
#include <ox/mc/read.hpp>
#ifdef OX_USE_STDLIB
#include <ox/oc/read.hpp>
@ -31,17 +32,15 @@ struct ClawHeader {
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<Buffer> stripClawHeader(const ox::Buffer &buff) noexcept;
Result<BufferView> stripClawHeader(ox::BufferView buff) noexcept;
template<typename T>
Error readClaw(const char *buff, std::size_t buffLen, T *val) {
oxRequire(header, readClawHeader(buff, buffLen));
Error readClaw(ox::BufferView buff, T &val) {
oxRequire(header, readClawHeader(buff));
if (header.typeName != getModelTypeName<T>()) {
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) {
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);
return model(&handler, val);
return model(&handler, &val);
}
case ClawFormat::Organic:
{
#ifdef OX_USE_STDLIB
OrganicClawReader reader(header.data, header.dataSize);
return model(&reader, val);
return model(&reader, &val);
#else
break;
#endif
@ -71,22 +71,12 @@ Error readClaw(const char *buff, std::size_t buffLen, T *val) {
}
template<typename T>
Result<T> readClaw(const char *buff, std::size_t buffLen) {
T val;
oxReturnError(readClaw(buff, buffLen, &val));
Result<T> readClaw(ox::BufferView buff) {
Result<T> val;
oxReturnError(readClaw(buff, val.value));
return val;
}
template<typename T>
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;
Result<ModelObject> readClaw(TypeStore &ts, BufferView 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
)
add_test("[ox/claw] ClawTest ClawHeaderReader" ClawTest ClawHeaderReader)
add_test("[ox/claw] ClawTest ClawHeaderReader2" ClawTest ClawHeaderReader2)
add_test("[ox/claw] ClawTest ClawWriter" ClawTest ClawWriter)
add_test("[ox/claw] ClawTest ClawReader" ClawTest ClawReader)
add_test("[ox/claw] ClawHeaderReader" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawHeaderReader)
add_test("[ox/claw] ClawHeaderReader2" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawHeaderReader2)
add_test("[ox/claw] ClawHeaderReadTypeId" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/ClawTest ClawHeaderReadTypeId)
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
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -8,11 +8,7 @@
#undef NDEBUG
#include <assert.h>
#include <iostream>
#include <map>
#include <memory>
#include <string>
#include <ox/claw/format.hpp>
#include <ox/claw/read.hpp>
#include <ox/claw/write.hpp>
@ -33,7 +29,7 @@ struct TestStructNest {
static constexpr auto TypeVersion = 1;
bool Bool = false;
uint32_t Int = 0;
ox::BString<32> String = "";
ox::IString<32> String = "";
};
struct TestStruct {
@ -51,7 +47,7 @@ struct TestStruct {
int32_t Int8 = 0;
int unionIdx = 1;
TestUnion Union;
ox::BString<32> String = "";
ox::IString<32> String = "";
uint32_t List[4] = {0, 0, 0, 0};
TestStructNest EmptyStruct;
TestStructNest Struct;
@ -66,7 +62,7 @@ struct TestStruct {
template<typename T>
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("Int", &obj->Int));
oxReturnError(io->fieldCString("String", &obj->String));
@ -75,7 +71,7 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith<TestUnion> auto *obj) {
template<typename T>
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("Int", &obj->Int));
oxReturnError(io->field("String", &obj->String));
@ -84,7 +80,7 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStructNest> auto *obj) {
template<typename T>
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("Int", &obj->Int));
oxReturnError(io->field("Int1", &obj->Int1));
@ -107,13 +103,13 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) {
return OxError(0);
}
static std::map<std::string_view, ox::Error(*)()> tests = {
static std::map<ox::StringView, ox::Error(*)()> tests = {
{
{
"ClawHeaderReader",
[] {
ox::String hdr = "O1;com.drinkingtea.ox.claw.test.Header;2;";
auto [ch, err] = ox::readClawHeader(hdr.c_str(), hdr.len() + 1);
constexpr auto hdr = ox::StringLiteral("O1;com.drinkingtea.ox.claw.test.Header;2;");
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.len() + 1});
oxAssert(err, "Error parsing header");
oxAssert(ch.fmt == ox::ClawFormat::Organic, "Format 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",
[] {
ox::String hdr = "M2;com.drinkingtea.ox.claw.test.Header2;3;";
auto [ch, err] = ox::readClawHeader(hdr.c_str(), hdr.len() + 1);
constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;");
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.len() + 1});
oxAssert(err, "Error parsing header");
oxAssert(ch.fmt == ox::ClawFormat::Metal, "Format 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);
}
},
{
"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",
[] {
// This test doesn't confirm much, but it does show that the writer
// doesn't segfault
TestStruct ts;
oxReturnError(ox::writeClaw(&ts, ox::ClawFormat::Metal));
oxReturnError(ox::writeClaw(ts, ox::ClawFormat::Metal));
return OxError(0);
}
},
@ -158,12 +164,10 @@ static std::map<std::string_view, ox::Error(*)()> tests = {
testIn.Struct.Bool = false;
testIn.Struct.Int = 300;
testIn.Struct.String = "Test String 2";
auto [buff, err] = ox::writeClaw(&testIn, ox::ClawFormat::Metal);
oxAssert(err, "writeMC failed");
oxAssert(ox::readClaw(buff.data(), buff.size(), &testOut), "readMC failed");
const auto [buff, err] = ox::writeMC(testIn);
oxAssert(err, "writeClaw failed");
oxAssert(ox::readMC(buff, testOut), "readClaw failed");
//std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n";
oxAssert(testIn.Bool == testOut.Bool, "Bool value mismatch");
oxAssert(testIn.Int == testOut.Int, "Int 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 retval = -1;
if (argc > 0) {
auto testName = args[1];
if (tests.find(testName) != tests.end()) {
retval = tests[testName]();
} else {
retval = 1;
}
if (argc < 2) {
oxError("Must specify test to run");
}
return retval;
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;
}

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
* 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"

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
* 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
@ -14,6 +14,7 @@
#endif
#include <ox/std/buffer.hpp>
#include <ox/std/string.hpp>
#include <ox/std/stringview.hpp>
#include "format.hpp"
@ -26,10 +27,15 @@ struct TypeInfoCatcher {
const char *name = nullptr;
int version = 0;
template<typename T = void>
constexpr void setTypeInfo(const char *name = T::TypeName, int v = T::TypeVersion, const Vector<String>& = {}, int = 0) noexcept {
this->name = name;
this->version = v;
template<typename T>
constexpr ox::Error setTypeInfo(
const char *pName = T::TypeName,
int pVersion = T::TypeVersion,
const Vector<String>& = {},
std::size_t = 0) noexcept {
this->name = pName;
this->version = pVersion;
return {};
}
constexpr Error field(...) noexcept {
@ -53,50 +59,64 @@ struct type_version<T, decltype((void) T::TypeVersion, -1)> {
};
template<typename T>
constexpr const char *getTypeName(T *t) noexcept {
constexpr const char *getTypeName(const T *t) noexcept {
TypeInfoCatcher tnc;
oxIgnoreError(model(&tnc, t));
std::ignore = model(&tnc, t);
return tnc.name;
}
template<typename T>
constexpr int getTypeVersion(T *t) noexcept {
constexpr int getTypeVersion(const T *t) noexcept {
TypeInfoCatcher tnc;
oxIgnoreError(model(&tnc, t));
std::ignore = model(&tnc, t);
return tnc.version;
}
template<typename T>
Result<String> writeClawHeader(T *t, ClawFormat fmt) noexcept {
String out;
ox::Error writeClawHeader(Writer_c auto &writer, const T *t, ClawFormat fmt) noexcept {
switch (fmt) {
case ClawFormat::Metal:
out += "M2;";
oxReturnError(write(writer, "M2;"));
break;
case ClawFormat::Organic:
out += "O1;";
oxReturnError(write(writer, "O1;"));
break;
default:
return OxError(1);
}
out += detail::getTypeName(t);
out += ";";
oxReturnError(write(writer, detail::getTypeName(t)));
oxReturnError(writer.put(';'));
const auto tn = detail::getTypeVersion(t);
if (tn > -1) {
out += tn;
oxReturnError(ox::writeItoa(tn, writer));
}
out += ";";
return out;
}
}
Result<Buffer> writeClaw(auto *t, ClawFormat fmt = ClawFormat::Metal) {
oxRequire(header, detail::writeClawHeader(t, fmt));
oxRequire(data, fmt == ClawFormat::Metal ? writeMC(t) : writeOC(t));
Buffer out(header.len() + data.size());
memcpy(out.data(), header.data(), header.len());
memcpy(out.data() + header.len(), data.data(), data.size());
oxReturnError(writer.put(';'));
return {};
}
}
Result<Buffer> writeClaw(
const auto &t,
ClawFormat fmt = ClawFormat::Metal,
std::size_t buffReserveSz = 2 * units::KB) noexcept {
Buffer out(buffReserveSz);
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;
}

View File

@ -5,6 +5,7 @@ add_library(
if(NOT MSVC)
target_compile_options(OxEvent PRIVATE -Wsign-conversion)
target_compile_options(OxEvent PRIVATE -Wconversion)
endif()
if(NOT OX_BARE_METAL)
@ -36,10 +37,10 @@ install(
)
install(TARGETS OxEvent
LIBRARY DESTINATION lib/ox
ARCHIVE DESTINATION lib/ox
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
if(OX_RUN_TESTS)
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
* 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

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
* 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"

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
* 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
@ -245,7 +245,7 @@ class Signal<Error(Args...)> {
}
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 {
return (m_receiver->*(m_methodPtr))(args...);
return (m_receiver->*(m_methodPtr))(ox::forward<Args>(args)...);
}
void cleanup(Signal *signal) noexcept final {
@ -286,7 +286,7 @@ class Signal<Error(Args...)> {
}
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 {
@ -391,14 +391,14 @@ Error Signal<Error(Args...)>::disconnectObject(const void *receiver) const noexc
template<class... Args>
void Signal<Error(Args...)>::emit(Args... args) const noexcept {
for (auto &f : m_slots) {
oxIgnoreError(f->call(args...));
std::ignore = f->call(ox::forward<Args>(args)...);
}
}
template<class... Args>
Error Signal<Error(Args...)>::emitCheckError(Args... args) const noexcept {
for (auto &f : m_slots) {
oxReturnError(f->call(args...));
oxReturnError(f->call(ox::forward<Args>(args)...));
}
return OxError(0);
}

View File

@ -7,4 +7,4 @@ add_executable(
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
* 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
@ -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",
[] {
@ -39,12 +39,14 @@ std::map<std::string, std::function<ox::Error()>> tests = {
};
int main(int argc, const char **args) {
if (argc > 1) {
auto testName = args[1];
if (tests.find(testName) != tests.end()) {
oxAssert(tests[testName](), "Test returned Error");
return 0;
}
if (argc < 2) {
oxError("Must specify test to run");
}
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;
}

View File

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

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
* 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
@ -75,25 +75,25 @@ class FileStoreTemplate {
public:
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
@ -106,11 +106,11 @@ class FileStoreTemplate {
* @return 0 if read is a success
*/
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 *size) const;
Result<StatInfo> stat(InodeId_t id) const;
Result<StatInfo> stat(uint64_t id) const;
Error resize();
@ -185,56 +185,56 @@ class FileStoreTemplate {
*/
ItemPtr rootInode();
bool canWrite(ItemPtr existing, size_t size);
bool canWrite(ItemPtr existing, std::size_t size);
};
template<typename size_t>
FileStoreTemplate<size_t>::FileStoreTemplate(void *buff, size_t buffSize) {
m_buffSize = buffSize;
FileStoreTemplate<size_t>::FileStoreTemplate(void *buff, std::size_t buffSize) {
m_buffSize = static_cast<size_t>(buffSize);
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_buffer = nullptr;
}
}
template<typename size_t>
Error FileStoreTemplate<size_t>::format(void *buffer, size_t bufferSize) {
auto nb = new (buffer) Buffer(bufferSize);
Error FileStoreTemplate<size_t>::format(void *buffer, std::size_t bufferSize) {
auto nb = new (buffer) Buffer(static_cast<size_t>(bufferSize));
auto fsData = nb->malloc(sizeof(FileStoreData)).value;
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");
}
auto data = nb->template dataOf<FileStoreData>(fsData);
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");
}
new (data) FileStoreData;
return OxError(0);
return {};
}
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) {
return m_buffer->setSize(size);
return m_buffer->setSize(static_cast<size_t>(size));
}
return OxError(1);
}
template<typename size_t>
Error FileStoreTemplate<size_t>::incLinks(InodeId_t id) {
oxRequireM(item, find(id).validate());
item->links++;
Error FileStoreTemplate<size_t>::incLinks(uint64_t id) {
oxRequireM(item, find(static_cast<size_t>(id)).validate());
++item->links;
return OxError(0);
}
template<typename size_t>
Error FileStoreTemplate<size_t>::decLinks(InodeId_t id) {
oxRequireM(item, find(id).validate());
item->links--;
Error FileStoreTemplate<size_t>::decLinks(uint64_t id) {
oxRequireM(item, find(static_cast<size_t>(id)).validate());
--item->links;
if (item->links == 0) {
oxReturnError(remove(item));
}
@ -242,8 +242,9 @@ Error FileStoreTemplate<size_t>::decLinks(InodeId_t id) {
}
template<typename size_t>
Error FileStoreTemplate<size_t>::write(InodeId_t id, const void *data, FsSize_t dataSize, uint8_t fileType) {
oxTracef("ox::fs::FileStoreTemplate::write", "Attempting to write to inode {}", id);
Error FileStoreTemplate<size_t>::write(uint64_t id64, const void *data, FsSize_t dataSize, uint8_t fileType) {
const auto id = static_cast<size_t>(id64);
oxTracef("ox.fs.FileStoreTemplate.write", "Attempting to write to inode {}", id);
auto existing = find(id);
if (!canWrite(existing, dataSize)) {
oxReturnError(compact());
@ -253,10 +254,10 @@ Error FileStoreTemplate<size_t>::write(InodeId_t id, const void *data, FsSize_t
if (canWrite(existing, dataSize)) {
// delete the old node if it exists
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);
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;
}
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;
// if first malloc failed, compact and try again
if (!dest.valid()) {
oxTrace("ox::fs::FileStoreTemplate::write", "Allocation failed, compacting");
oxTrace("ox.fs.FileStoreTemplate.write", "Allocation failed, compacting");
oxReturnError(compact());
dest = m_buffer->malloc(dataSize).value;
}
if (dest.valid()) {
oxTrace("ox::fs::FileStoreTemplate::write", "Memory allocated");
oxTrace("ox.fs.FileStoreTemplate.write", "Memory allocated");
dest->id = id;
dest->fileType = fileType;
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.");
// write data if any was provided
if (data != nullptr) {
ox_memcpy(destData, data, dest->size());
oxTrace("ox::fs::FileStoreTemplate::write", "Data written");
ox::memcpy(destData, data, dest->size());
oxTrace("ox.fs.FileStoreTemplate.write", "Data written");
}
auto fsData = fileStoreData();
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);
if (root.valid()) {
oxTracef("ox::fs::FileStoreTemplate::write",
oxTracef("ox.fs.FileStoreTemplate.write",
"Placing {} on {} at {}", dest->id.get(), root->id.get(), destData.offset());
return placeItem(dest);
} else {
oxTracef("ox::fs::FileStoreTemplate::write",
oxTracef("ox.fs.FileStoreTemplate.write",
"Initializing root inode: {} (offset: {}, data size: {})",
dest->id.get(), dest.offset(), destData.size());
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);
}
} 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>
Error FileStoreTemplate<size_t>::remove(InodeId_t id) {
return remove(find(id));
Error FileStoreTemplate<size_t>::remove(uint64_t id) {
return remove(find(static_cast<size_t>(id)));
}
template<typename size_t>
Error FileStoreTemplate<size_t>::read(InodeId_t id, void *out, FsSize_t outSize, FsSize_t *size) const {
oxTracef("ox::fs::FileStoreTemplate::read", "Attempting to read from inode {}", id);
auto src = find(id);
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);
auto src = find(static_cast<size_t>(id));
// error check
if (!src.valid()) {
oxTracef("ox::fs::FileStoreTemplate::read::fail", "Could not find requested item: {}", id);
return OxError(1);
oxTracef("ox.fs.FileStoreTemplate.read.fail", "Could not find requested item: {}", id);
return OxError(1, "Could not find requested item");
}
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());
oxTracef("ox::fs::FileStoreTemplate::read::outSize", "{} {} {}", srcData.offset(), srcData.size(), outSize);
oxTracef("ox.fs.FileStoreTemplate.read.outSize", "{} {} {}", srcData.offset(), srcData.size(), outSize);
// error check
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",
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(), outSize);
return OxError(1);
}
ox_memcpy(out, srcData, srcData.size());
ox::memcpy(out, srcData, srcData.size());
if (size) {
*size = src.size();
}
@ -344,29 +345,29 @@ Error FileStoreTemplate<size_t>::read(InodeId_t id, void *out, FsSize_t outSize,
}
template<typename size_t>
Error FileStoreTemplate<size_t>::read(InodeId_t id, FsSize_t readStart, FsSize_t readSize, void *out, FsSize_t *size) const {
oxTracef("ox::fs::FileStoreTemplate::read", "Attempting to read from inode {}", id);
auto src = find(id);
Error FileStoreTemplate<size_t>::read(uint64_t id, FsSize_t readStart, FsSize_t readSize, void *out, FsSize_t *size) const {
oxTracef("ox.fs.FileStoreTemplate.read", "Attempting to read from inode {}", id);
auto src = find(static_cast<size_t>(id));
// error check
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);
}
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());
oxTracef("ox::fs::FileStoreTemplate::read::readSize", "{} {} {}", srcData.offset(), srcData.size(), readSize);
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",
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);
ox::memcpy(out, srcData.get() + readStart, readSize);
if (size) {
*size = src.size();
}
@ -376,30 +377,30 @@ Error FileStoreTemplate<size_t>::read(InodeId_t id, FsSize_t readStart, FsSize_t
template<typename size_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 *out, FsSize_t *size) const {
oxTracef("ox::fs::FileStoreTemplate::read", "Attempting to read from inode {}", id);
auto src = find(id);
oxTracef("ox.fs.FileStoreTemplate.read", "Attempting to read from inode {}", id);
auto src = find(static_cast<size_t>(id));
// error check
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);
}
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());
oxTracef("ox::fs::FileStoreTemplate::read::readSize", "{} {} {}", srcData.offset(), srcData.size(), readSize);
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",
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);
ox::memcpy(out, srcData.get() + readStart, readSize);
if (size) {
*size = src.size();
}
@ -408,8 +409,8 @@ Error FileStoreTemplate<size_t>::read(InodeId_t id, FsSize_t readStart,
}
template<typename size_t>
ptrarith::Ptr<uint8_t, std::size_t> FileStoreTemplate<size_t>::read(InodeId_t id) const {
auto item = find(id);
ptrarith::Ptr<uint8_t, std::size_t> FileStoreTemplate<size_t>::read(uint64_t id) const {
auto item = find(static_cast<size_t>(id));
if (item.valid()) {
return item->data();
} else {
@ -420,10 +421,10 @@ ptrarith::Ptr<uint8_t, std::size_t> FileStoreTemplate<size_t>::read(InodeId_t id
template<typename size_t>
Error FileStoreTemplate<size_t>::resize() {
oxReturnError(compact());
const auto newSize = size() - available();
oxTracef("ox::fs::FileStoreTemplate::resize", "resize to: {}", newSize);
const auto newSize = static_cast<std::size_t>(size() - available());
oxTracef("ox.fs.FileStoreTemplate.resize", "resize to: {}", 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);
}
@ -432,17 +433,17 @@ Error FileStoreTemplate<size_t>::resize(std::size_t size, void *newBuff) {
if (m_buffer->size() > size) {
return OxError(1);
}
m_buffSize = size;
m_buffSize = static_cast<size_t>(size);
if (newBuff) {
m_buffer = reinterpret_cast<Buffer*>(newBuff);
oxReturnError(m_buffer->setSize(size));
oxReturnError(m_buffer->setSize(static_cast<size_t>(size)));
}
return OxError(0);
}
template<typename size_t>
Result<StatInfo> FileStoreTemplate<size_t>::stat(InodeId_t id) const {
oxRequire(inode, find(id).validate());
Result<StatInfo> FileStoreTemplate<size_t>::stat(uint64_t id) const {
oxRequire(inode, find(static_cast<size_t>(id)).validate());
return StatInfo {
id,
inode->links,
@ -486,8 +487,8 @@ Result<typename FileStoreTemplate<size_t>::InodeId_t> FileStoreTemplate<size_t>:
return OxError(1);
}
for (auto i = 0; i < 100; i++) {
auto inode = fsData->random.gen() % MaxValue<InodeId_t>;
if (inode > ReservedInodeEnd && !find(inode).valid()) {
auto inode = static_cast<typename FileStoreTemplate<size_t>::InodeId_t>(fsData->random.gen() % MaxValue<InodeId_t>);
if (inode > ReservedInodeEnd && !find(static_cast<size_t>(inode)).valid()) {
return inode;
}
}
@ -505,13 +506,13 @@ Error FileStoreTemplate<size_t>::compact() {
if (!item.valid()) {
return OxError(1);
}
oxTracef("ox::fs::FileStoreTemplate::compact::moveItem", "Moving Item: {} from {} to {}", item->id.get(), oldAddr, item.offset());
oxTracef("ox.fs.FileStoreTemplate.compact.moveItem", "Moving Item: {} from {} to {}", item->id.get(), oldAddr, item.offset());
// update rootInode if this is it
auto fsData = fileStoreData();
if (fsData && oldAddr == fsData->rootNode) {
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(),
"Parent inode not found for item that should have parent.");
if (parent.valid()) {
@ -548,7 +549,7 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr item) {
fsData->rootNode = item;
item->left = root->left;
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);
} else {
return placeItem(root, item);
@ -558,7 +559,7 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr item) {
template<typename size_t>
Error FileStoreTemplate<size_t>::placeItem(ItemPtr root, ItemPtr item, int depth) {
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);
}
if (item->id > root->id) {
@ -569,7 +570,7 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr root, ItemPtr item, int depth
item->left = right->left;
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);
} else {
return placeItem(right, item, depth + 1);
@ -582,13 +583,13 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr root, ItemPtr item, int depth
item->left = left->left;
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);
} else {
return placeItem(left, item, depth + 1);
}
} 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.");
}
}
@ -630,14 +631,14 @@ Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr item) {
template<typename size_t>
Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr root, ItemPtr item, int depth) {
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.");
}
if (item->id > root->id) {
auto right = m_buffer->ptr(root->right);
if (right->id == item->id) {
root->right = 0;
oxTracef("ox::fs::FileStoreTemplate::unplaceItem", "Unplaced Item: {}", item->id.get());
oxTracef("ox.fs.FileStoreTemplate.unplaceItem", "Unplaced Item: {}", item->id.get());
} else {
return unplaceItem(right, item, depth + 1);
}
@ -645,7 +646,7 @@ Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr root, ItemPtr item, int dep
auto left = m_buffer->ptr(root->left);
if (left->id == item->id) {
root->left = 0;
oxTracef("ox::fs::FileStoreTemplate::unplaceItem", "Unplaced Item: {}", item->id.get());
oxTracef("ox.fs.FileStoreTemplate.unplaceItem", "Unplaced Item: {}", item->id.get());
} else {
return unplaceItem(left, item, depth + 1);
}
@ -700,22 +701,22 @@ typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::findParen
template<typename size_t>
typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::find(ItemPtr item, InodeId_t id, int depth) const {
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;
}
if (!item.valid()) {
oxTrace("ox::fs::FileStoreTemplate::find::fail", "item invalid");
oxTrace("ox.fs.FileStoreTemplate.find.fail", "item invalid");
return nullptr;
}
// do search
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);
} 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);
} 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 nullptr;
@ -723,7 +724,7 @@ typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::find(Item
template<typename size_t>
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();
if (fsData) {
auto root = m_buffer->ptr(fsData->rootNode);
@ -731,10 +732,10 @@ typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::find(Inod
auto item = find(root, id);
return item;
} else {
oxTrace("ox::fs::FileStoreTemplate::find::fail", "No root node");
oxTrace("ox.fs.FileStoreTemplate.find.fail", "No root node");
}
} else {
oxTrace("ox::fs::FileStoreTemplate::find::fail", "No FileStore Data");
oxTrace("ox.fs.FileStoreTemplate.find.fail", "No FileStore Data");
}
return nullptr;
}
@ -753,8 +754,9 @@ typename FileStoreTemplate<size_t>::ItemPtr FileStoreTemplate<size_t>::rootInode
}
template<typename size_t>
bool FileStoreTemplate<size_t>::canWrite(ItemPtr existing, size_t size) {
return existing.size() >= size || m_buffer->spaceNeeded(size) <= m_buffer->available();
bool FileStoreTemplate<size_t>::canWrite(ItemPtr existing, std::size_t size) {
const auto sz = static_cast<size_t>(size);
return existing.size() >= sz || m_buffer->spaceNeeded(sz) <= m_buffer->available();
}
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
* 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"

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
* 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
@ -48,14 +48,14 @@ struct OX_PACKED DirectoryEntry {
auto d = data();
if (d.valid()) {
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(1);
}
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());
}
@ -69,10 +69,10 @@ struct OX_PACKED DirectoryEntry {
[[nodiscard]]
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
}
@ -94,9 +94,9 @@ class Directory {
FileStore m_fs;
public:
Directory() = default;
Directory() noexcept = default;
Directory(FileStore fs, InodeId_t inode);
Directory(FileStore fs, uint64_t inode) noexcept;
/**
* Initializes Directory.
@ -108,24 +108,26 @@ class Directory {
/**
* @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;
template<typename F>
Error ls(F cb) noexcept;
[[nodiscard]]
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;
};
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_inodeId = inodeId;
auto buff = m_fs.read(inodeId).template to<Buffer>();
m_inodeId = static_cast<InodeId_t>(inodeId);
auto buff = m_fs.read(static_cast<InodeId_t>(inodeId)).template to<Buffer>();
if (buff.valid()) {
m_size = buff.size();
}
@ -134,7 +136,7 @@ Directory<FileStore, InodeId_t>::Directory(FileStore fs, InodeId_t inodeId) {
template<typename FileStore, typename InodeId_t>
Error Directory<FileStore, InodeId_t>::init() noexcept {
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)));
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
if (!buff.valid()) {
@ -149,7 +151,7 @@ Error Directory<FileStore, InodeId_t>::init() noexcept {
template<typename FileStore, typename InodeId_t>
Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, FileName *nameBuff) {
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
if (nameBuff == nullptr) {
nameBuff = new (ox_alloca(sizeof(FileName))) FileName;
@ -157,7 +159,7 @@ Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, Fi
// determine if already exists
auto name = nameBuff;
oxReturnError(path.get(name));
oxReturnError(path.get(*name));
auto childInode = find(PathIterator(*name));
if (!childInode.ok()) {
// if this is not the last item in the path and parents is disabled,
@ -166,7 +168,7 @@ Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, Fi
return OxError(1);
}
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);
oxReturnError(childInode.error);
@ -192,7 +194,8 @@ Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents, Fi
}
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
if (nameBuff == nullptr) {
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;
if (path.next().hasNext()) { // not yet at target directory, recurse to next one
oxReturnError(path.get(name));
oxTracef("ox::fs::Directory::write", "Attempting to write to next sub-Directory: {} of {}",
oxReturnError(path.get(*name));
oxTracef("ox.fs.Directory.write", "Attempting to write to next sub-Directory: {} of {}",
*name, path.fullPath());
oxRequire(nextChild, findEntry(*name));
oxTracef("ox::fs::Directory::write", "{}: {}", *name, nextChild);
oxTracef("ox.fs.Directory.write", "{}: {}", *name, nextChild);
if (nextChild) {
// reuse name because it is a rather large variable and will not be used again
// be attentive that this remains true
name = nullptr;
return Directory(m_fs, nextChild).write(path.next(), inode, nameBuff);
} else {
oxTracef("ox::fs::Directory::write", "{} not found and not allowed to create it.", *name);
oxTracef("ox.fs.Directory.write", "{} not found and not allowed to create it.", *name);
return OxError(1, "File not found and not allowed to create it.");
}
} else {
oxTrace("ox::fs::Directory::write", path.fullPath());
oxTrace("ox.fs.Directory.write", path.fullPath());
// insert the new entry on this directory
// get the name
oxReturnError(path.next(name));
oxReturnError(path.next(*name));
// 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));
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>();
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");
}
@ -236,20 +239,20 @@ Error Directory<FileStore, InodeId_t>::write(PathIterator path, InodeId_t inode,
const auto newSize = oldStat.size + Buffer::spaceNeeded(entryDataSize);
auto cpy = ox_malloca(newSize, Buffer, *old, oldStat.size);
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");
}
oxReturnError(cpy->setSize(newSize));
auto val = cpy->malloc(entryDataSize).value;
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");
}
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()));
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;
}
auto &name = *nameBuff;
oxReturnError(path.get(&name));
oxReturnError(path.get(name));
oxTrace("ox::fs::Directory::remove", name);
oxTrace("ox.fs.Directory.remove", name);
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
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()) {
auto data = i->data();
if (data.valid()) {
if (data->name == name) {
if (name == data->name) {
oxReturnError(buff->free(i));
}
} else {
oxTrace("ox::fs::Directory::remove", "INVALID DIRECTORY ENTRY");
oxTrace("ox.fs.Directory.remove", "INVALID DIRECTORY ENTRY");
}
}
} 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(0);
@ -286,20 +289,20 @@ Error Directory<FileStore, InodeId_t>::remove(PathIterator path, FileName *nameB
template<typename FileStore, typename InodeId_t>
template<typename F>
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>();
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");
}
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()) {
auto data = i->data();
if (data.valid()) {
oxReturnError(cb(data->name, data->inode));
} 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>
Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::findEntry(const FileName &name) const noexcept {
oxTrace("ox::fs::Directory::findEntry", name);
oxTrace("ox.fs.Directory.findEntry", name);
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
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");
}
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()) {
auto data = i->data();
if (data.valid()) {
oxTracef("ox::fs::Directory::findEntry", "Comparing \"{}\" to \"{}\"", name, data->name);
if (data->name == name) {
oxTracef("ox::fs::Directory::findEntry", "\"{}\" match found.", name);
oxTracef("ox.fs.Directory.findEntry", "Comparing \"{}\" to \"{}\"", name, data->name);
if (name == data->name) {
oxTracef("ox.fs.Directory.findEntry", "\"{}\" match found.", name);
return static_cast<InodeId_t>(data->inode);
}
} 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");
}
@ -340,7 +343,7 @@ Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::find(Path
// determine if already exists
auto name = nameBuff;
oxReturnError(path.get(name));
oxReturnError(path.get(*name));
oxRequire(v, findEntry(*name));
// recurse if not at end of path

View File

@ -1,9 +1,9 @@
/*
* Copyright 2015 - 2022 gary@drinkingtea.net
* Copyright 2015 - 2024 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* 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>
@ -36,13 +36,6 @@ FileAddress::FileAddress(ox::CRStringView path) noexcept {
m_type = FileAddressType::Path;
}
FileAddress::FileAddress(char *path) noexcept {
auto pathSize = ox_strlen(path) + 1;
m_data.path = new char[pathSize];
memcpy(m_data.path, path, pathSize);
m_type = FileAddressType::Path;
}
FileAddress &FileAddress::operator=(const FileAddress &other) noexcept {
if (this == &other) {
return *this;
@ -52,9 +45,14 @@ FileAddress &FileAddress::operator=(const FileAddress &other) noexcept {
switch (m_type) {
case FileAddressType::Path:
{
auto strSize = ox_strlen(other.m_data.path) + 1;
m_data.path = new char[strSize];
ox_memcpy(m_data.path, other.m_data.path, strSize);
if (other.m_data.path) {
auto strSize = ox::strlen(other.m_data.path) + 1;
m_data.path = new char[strSize];
ox::memcpy(m_data.path, other.m_data.path, strSize);
} else {
m_data.constPath = "";
m_type = FileAddressType::ConstPath;
}
break;
}
case FileAddressType::ConstPath:
@ -90,6 +88,32 @@ FileAddress &FileAddress::operator=(FileAddress &&other) noexcept {
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 {
auto [p, err] = getPath();
if (err) {

View File

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

View File

@ -1,9 +1,9 @@
/*
* Copyright 2015 - 2022 gary@drinkingtea.net
* 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 http://mozilla.org/MPL/2.0/.
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#include <ox/std/error.hpp>
@ -13,7 +13,7 @@
namespace ox {
Result<const char*> MemFS::directAccess(const FileAddress &addr) noexcept {
Result<const char*> MemFS::directAccess(const FileAddress &addr) const noexcept {
switch (addr.type()) {
case FileAddressType::Inode:
return directAccess(addr.getInode().value);
@ -39,14 +39,14 @@ Error FileSystem::read(const FileAddress &addr, void *buffer, std::size_t size)
Result<Buffer> FileSystem::read(const FileAddress &addr) noexcept {
oxRequire(s, stat(addr));
Buffer buff(s.size);
Buffer buff(static_cast<std::size_t>(s.size));
oxReturnError(read(addr, buff.data(), buff.size()));
return buff;
}
Result<Buffer> FileSystem::read(CRStringView path) noexcept {
oxRequire(s, statPath(path));
Buffer buff(s.size);
Buffer buff(static_cast<std::size_t>(s.size));
oxReturnError(readFilePath(path, buff.data(), buff.size()));
return buff;
}

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
* 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
#include <ox/std/buffer.hpp>
#include <ox/std/span.hpp>
#include <ox/fs/filestore/filestoretemplate.hpp>
#include <ox/fs/filesystem/filelocation.hpp>
@ -66,10 +67,18 @@ class FileSystem {
return writeFilePath(path, buffer, size, FileType::NormalFile);
}
Error write(CRStringView path, ox::Span<char> const&buff) noexcept {
return write(path, buff.data(), buff.size(), FileType::NormalFile);
}
Error write(uint64_t inode, const void *buffer, uint64_t size) noexcept {
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;
inline Error write(CRStringView path, const void *buffer, uint64_t size, FileType fileType) noexcept {
@ -126,20 +135,20 @@ class FileSystem {
class MemFS: public FileSystem {
public:
Result<const char*> directAccess(const FileAddress &addr) noexcept;
Result<const char*> directAccess(const FileAddress &addr) const noexcept;
inline Result<const char*> directAccess(CRStringView path) noexcept {
inline Result<const char*> directAccess(CRStringView path) const noexcept {
return directAccessPath(path);
}
inline Result<const char*> directAccess(uint64_t inode) noexcept {
inline Result<const char*> directAccess(uint64_t inode) const noexcept {
return directAccessInode(inode);
}
protected:
virtual Result<const char*> directAccessPath(CRStringView path) noexcept = 0;
virtual Result<const char*> directAccessPath(CRStringView path) const noexcept = 0;
virtual Result<const char*> directAccessInode(uint64_t inode) noexcept = 0;
virtual Result<const char*> directAccessInode(uint64_t inode) const noexcept = 0;
};
/**
@ -165,6 +174,8 @@ class FileSystemTemplate: public MemFS {
FileSystemTemplate(void *buffer, uint64_t bufferSize, void(*freeBuffer)(char*) = detail::fsBuffFree) noexcept;
explicit FileSystemTemplate(ox::Buffer &buffer) noexcept;
explicit FileSystemTemplate(FileStore fs) noexcept;
~FileSystemTemplate() noexcept override;
@ -177,13 +188,13 @@ class FileSystemTemplate: public MemFS {
Error readFilePath(CRStringView path, void *buffer, std::size_t buffSize) noexcept override;
Result<const char*> directAccessPath(CRStringView) noexcept override;
Result<const char*> directAccessPath(CRStringView) const 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;
Result<const char*> directAccessInode(uint64_t) noexcept override;
Result<const char*> directAccessInode(uint64_t) const noexcept override;
Result<Vector<String>> ls(CRStringView dir) const noexcept override;
@ -238,9 +249,14 @@ FileSystemTemplate<FileStore, Directory>::FileSystemTemplate(FileStore fs) noexc
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>
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) {
}
@ -253,8 +269,8 @@ FileSystemTemplate<FileStore, Directory>::~FileSystemTemplate() noexcept {
template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::format(void *buff, uint64_t buffSize) noexcept {
oxReturnError(FileStore::format(buff, buffSize));
FileStore fs(buff, buffSize);
oxReturnError(FileStore::format(buff, static_cast<size_t>(buffSize)));
FileStore fs(buff, static_cast<size_t>(buffSize));
constexpr auto rootDirInode = MaxValue<typename FileStore::InodeId_t> / 2;
Directory rootDir(fs, rootDirInode);
@ -262,11 +278,11 @@ Error FileSystemTemplate<FileStore, Directory>::format(void *buff, uint64_t buff
FileSystemData fd;
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)));
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);
}
@ -275,7 +291,7 @@ Error FileSystemTemplate<FileStore, Directory>::format(void *buff, uint64_t buff
template<typename FileStore, typename Directory>
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());
return rootDir.mkdir(path, recursive);
}
@ -298,11 +314,11 @@ Error FileSystemTemplate<FileStore, Directory>::readFilePath(CRStringView path,
if (s.size > buffSize) {
return OxError(1, "Buffer to small to load file");
}
return readFileInodeRange(s.inode, 0, s.size, buffer, &buffSize);
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) noexcept {
Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccessPath(CRStringView path) const noexcept {
oxRequire(fd, fileSystemData());
Directory rootDir(m_fs, fd.rootDirInode);
oxRequire(inode, rootDir.find(path));
@ -315,7 +331,7 @@ Error FileSystemTemplate<FileStore, Directory>::readFileInode(uint64_t inode, vo
if (s.size > buffSize) {
return OxError(1, "Buffer to small to load file");
}
return readFileInodeRange(inode, 0, s.size, buffer, &buffSize);
return readFileInodeRange(inode, 0, static_cast<size_t>(s.size), buffer, &buffSize);
}
template<typename FileStore, typename Directory>
@ -324,7 +340,7 @@ Error FileSystemTemplate<FileStore, Directory>::readFileInodeRange(uint64_t inod
}
template<typename FileStore, typename Directory>
Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccessInode(uint64_t inode) noexcept {
Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccessInode(uint64_t inode) const noexcept {
auto data = m_fs.read(inode);
if (!data.valid()) {
return OxError(1, "Data not valid");
@ -345,7 +361,7 @@ Result<Vector<String>> FileSystemTemplate<FileStore, Directory>::ls(CRStringView
template<typename FileStore, typename Directory>
template<typename F>
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));
Directory dir(m_fs, s.inode);
return dir.ls(cb);
@ -364,7 +380,7 @@ Error FileSystemTemplate<FileStore, Directory>::remove(CRStringView path, bool r
return err;
}
} 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(0);
@ -377,7 +393,7 @@ Error FileSystemTemplate<FileStore, Directory>::resize() noexcept {
template<typename FileStore, typename Directory>
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);
}
@ -396,7 +412,7 @@ Error FileSystemTemplate<FileStore, Directory>::writeFilePath(CRStringView path,
template<typename FileStore, typename Directory>
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>
@ -418,7 +434,7 @@ Result<FileStat> FileSystemTemplate<FileStore, Directory>::statPath(CRStringView
template<typename FileStore, typename Directory>
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>

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
* 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>
@ -24,14 +24,14 @@ PassThroughFS::PassThroughFS(CRStringView dirPath) {
PassThroughFS::~PassThroughFS() noexcept = default;
String PassThroughFS::basePath() const noexcept {
return m_path.string().c_str();
return ox::String(m_path.string().c_str());
}
Error PassThroughFS::mkdir(CRStringView path, bool recursive) noexcept {
bool success = false;
const auto p = m_path / stripSlash(path);
const auto u8p = p.u8string();
oxTrace("ox::fs::PassThroughFS::mkdir", std::bit_cast<const char*>(u8p.c_str()));
oxTrace("ox.fs.PassThroughFS.mkdir", std::bit_cast<const char*>(u8p.c_str()));
if (recursive) {
std::error_code ec;
const auto isDir = std::filesystem::is_directory(p, ec);
@ -39,7 +39,7 @@ Error PassThroughFS::mkdir(CRStringView path, bool recursive) noexcept {
success = true;
} else {
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 {
std::error_code ec;
@ -48,7 +48,7 @@ Error PassThroughFS::mkdir(CRStringView path, bool recursive) noexcept {
success = true;
} else {
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);
@ -67,7 +67,7 @@ Result<Vector<String>> PassThroughFS::ls(CRStringView dir) const noexcept {
Vector<String> out;
std::error_code 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) {
const auto u8p = p.path().filename().u8string();
out.emplace_back(reinterpret_cast<const char*>(u8p.c_str()));
@ -98,11 +98,11 @@ Result<FileStat> PassThroughFS::statPath(CRStringView path) const noexcept {
const auto p = m_path / stripSlash(path);
const FileType type = std::filesystem::is_directory(p, ec) ?
FileType::Directory : FileType::NormalFile;
oxTracef("ox::fs::PassThroughFS::statInode", "{} {}", ec.message(), path);
oxTracef("ox.fs.PassThroughFS.statInode", "{} {}", ec.message(), path);
const uint64_t size = type == FileType::Directory ? 0 : std::filesystem::file_size(p, ec);
oxTracef("ox::fs::PassThroughFS::statInode", "{} {}", ec.message(), path);
oxTracef("ox::fs::PassThroughFS::statInode::size", "{} {}", path, size);
oxReturnError(OxError(ec.value()));
oxTracef("ox.fs.PassThroughFS.statInode", "{} {}", ec.message(), path);
oxTracef("ox.fs.PassThroughFS.statInode.size", "{} {}", path, size);
oxReturnError(OxError(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: stat failed"));
return FileStat{0, 0, size, type};
}
@ -113,14 +113,14 @@ uint64_t PassThroughFS::spaceNeeded(uint64_t size) const noexcept {
Result<uint64_t> PassThroughFS::available() const noexcept {
std::error_code 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;
}
Result<uint64_t> PassThroughFS::size() const noexcept {
std::error_code 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;
}
@ -144,15 +144,15 @@ bool PassThroughFS::valid() const noexcept {
Error PassThroughFS::readFilePath(CRStringView path, void *buffer, std::size_t buffSize) noexcept {
try {
std::ifstream file((m_path / stripSlash(path)), std::ios::binary | std::ios::ate);
const std::size_t size = file.tellg();
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);
oxTracef("ox.fs.PassThroughFS.read.error", "Read failed: Buffer too small: {}", path);
return OxError(1);
}
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());
oxTracef("ox.fs.PassThroughFS.read.error", "Read of {} failed: {}", path, f.what());
return OxError(2);
}
return OxError(0);
@ -174,7 +174,7 @@ Error PassThroughFS::writeFilePath(CRStringView path, const void *buffer, uint64
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());
oxTracef("ox.fs.PassThroughFS.read.error", "Write of {} failed: {}", path, f.what());
return OxError(1);
}
return OxError(0);
@ -186,9 +186,9 @@ Error PassThroughFS::writeFileInode(uint64_t, const void*, uint64_t, FileType) n
}
std::string_view PassThroughFS::stripSlash(StringView path) noexcept {
const auto pathLen = ox_strlen(path);
const auto pathLen = ox::strlen(path);
for (auto i = 0u; i < pathLen && path[0] == '/'; i++) {
path = path.substr(1);
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
* 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
@ -92,7 +92,7 @@ template<typename F>
Error PassThroughFS::ls(CRStringView dir, F cb) const noexcept {
std::error_code 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) {
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
* 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>
@ -19,7 +19,7 @@ PathIterator::PathIterator(const char *path, std::size_t maxSize, std::size_t it
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()) {
@ -29,10 +29,10 @@ PathIterator::PathIterator(CRStringView path): PathIterator(path.data(), path.by
* @return 0 if no error
*/
Error PathIterator::dirPath(char *out, std::size_t outSize) {
int idx = ox_lastIndexOf(m_path, '/', m_maxSize);
std::size_t size = idx + 1;
const auto idx = ox::lastIndexOf(m_path, '/', m_maxSize);
const auto size = static_cast<std::size_t>(idx + 1);
if (idx >= 0 && size < outSize) {
ox_memcpy(out, m_path, size);
ox::memcpy(out, m_path, size);
out[size] = 0;
return OxError(0);
} else {
@ -44,12 +44,12 @@ Error PathIterator::dirPath(char *out, std::size_t outSize) {
* @return 0 if no error
*/
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) {
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) {
ox_memcpy(out, &m_path[idx], fileNameSize);
ox::memcpy(out, &m_path[idx], fileNameSize);
out[fileNameSize] = 0;
return OxError(0);
} else {
@ -61,14 +61,15 @@ Error PathIterator::fileName(char *out, std::size_t outSize) {
}
// 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::ignore = fileName.resize(MaxFileNameLength);
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);
}
if (!ox_strlen(&m_path[m_iterator])) {
oxTrace("ox::fs::PathIterator::get", "!ox_strlen(&m_path[m_iterator])");
if (!ox::strlen(&m_path[m_iterator])) {
oxTrace("ox.fs.PathIterator.get", "!ox::strlen(&m_path[m_iterator])");
return OxError(1);
}
auto start = m_iterator;
@ -76,90 +77,80 @@ Error PathIterator::get(char *pathOut, std::size_t pathOutSize) {
start++;
}
// 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 /
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;
// cannot fit the output in the output parameter
if (size >= pathOutSize || size == 0) {
if (size >= MaxFileNameLength || size == 0) {
return OxError(1);
}
ox_memcpy(pathOut, &m_path[start], size);
ox::memcpy(fileName.data(), &m_path[start], size);
// truncate trailing /
if (size && pathOut[size - 1] == '/') {
if (size && fileName[size - 1] == '/') {
size--;
}
pathOut[size] = 0; // end with null terminator
return OxError(0);
oxReturnError(fileName.resize(size));
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;
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);
if (m_path[m_iterator] == '/') {
m_iterator++;
}
std::size_t start = m_iterator;
const auto start = m_iterator;
// 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 /
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;
// cannot fit the output in the output parameter
if (size >= pathOutSize) {
if (size >= MaxFileNameLength) {
return OxError(1);
}
ox_memcpy(pathOut, &m_path[start], size);
ox::memcpy(fileName.data(), &m_path[start], size);
}
// truncate trailing /
if (size && pathOut[size - 1] == '/') {
if (size && fileName[size - 1] == '/') {
size--;
}
pathOut[size] = 0; // end with null terminator
fileName[size] = 0; // end with null terminator
oxReturnError(fileName.resize(size));
m_iterator += size;
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 {
std::size_t size = 0;
auto retval = OxError(1);
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);
if (m_path[it] == '/') {
it++;
}
std::size_t start = it;
const auto start = it;
// 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 /
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;
}
it += size;
@ -168,18 +159,18 @@ Result<std::size_t> PathIterator::nextSize() const {
bool PathIterator::hasNext() const {
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;
if (m_path[start] == '/') {
start++;
}
// 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 /
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;
}
return size > 0;
@ -192,22 +183,22 @@ bool PathIterator::valid() const {
PathIterator PathIterator::next() const {
std::size_t size = 0;
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] == '/') {
iterator++;
}
std::size_t start = iterator;
const auto start = iterator;
// 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 /
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;
}
iterator += size;
return PathIterator(m_path, m_maxSize, iterator + 1);
return {m_path, m_maxSize, iterator + 1};
}
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
* 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
@ -13,7 +13,7 @@
namespace ox {
constexpr std::size_t MaxFileNameLength = 255;
using FileName = BString<MaxFileNameLength>;
using FileName = IString<MaxFileNameLength>;
class PathIterator {
private:
@ -41,22 +41,12 @@ class PathIterator {
/**
* @return 0 if no error
*/
Error next(char *pathOut, std::size_t pathOutSize);
Error next(FileName &fileName);
/**
* @return 0 if no error
*/
Error get(char *pathOut, std::size_t pathOutSize);
/**
* @return 0 if no error
*/
Error next(FileName *fileName);
/**
* @return 0 if no error
*/
Error get(FileName *fileName);
Error get(FileName &fileName);
/**
* @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
* 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

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

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
* 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
@ -37,7 +37,7 @@ class OX_PACKED NodeBuffer {
Iterator(NodeBuffer *buffer, ItemPtr current) noexcept {
m_buffer = buffer;
m_current = current;
oxTrace("ox::ptrarith::Iterator::start") << current.offset();
oxTrace("ox.ptrarith.Iterator.start") << current.offset();
}
operator const Item*() const noexcept {
@ -77,7 +77,7 @@ class OX_PACKED NodeBuffer {
[[nodiscard]]
bool hasNext() noexcept {
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);
return next.valid() && m_buffer->firstItem() != next;
}
@ -85,7 +85,7 @@ class OX_PACKED NodeBuffer {
}
void next() noexcept {
oxTrace("ox::ptrarith::NodeBuffer::Iterator::next") << m_it++;
oxTrace("ox.ptrarith.NodeBuffer.Iterator.next") << m_it++;
if (hasNext()) {
m_current = m_buffer->next(m_current);
} else {
@ -97,9 +97,9 @@ class OX_PACKED NodeBuffer {
Header m_header;
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]]
const Iterator iterator() const noexcept;
@ -129,7 +129,7 @@ class OX_PACKED NodeBuffer {
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;
@ -139,7 +139,7 @@ class OX_PACKED NodeBuffer {
/**
* Set size, capacity.
*/
Error setSize(size_t size) noexcept;
Error setSize(std::size_t size) noexcept;
/**
* Get size, capacity.
@ -159,7 +159,7 @@ class OX_PACKED NodeBuffer {
* bytes
*/
[[nodiscard]]
static size_t spaceNeeded(size_t size) noexcept;
static size_t spaceNeeded(std::size_t size) noexcept;
template<typename F>
Error compact(F cb = [](uint64_t, ItemPtr) {}) noexcept;
@ -171,17 +171,17 @@ class OX_PACKED NodeBuffer {
};
template<typename size_t, typename Item>
NodeBuffer<size_t, Item>::NodeBuffer(size_t size) noexcept {
m_header.size = size;
ox_memset(this + 1, 0, size - sizeof(*this));
oxTrace("ox::NodeBuffer::constructor") << m_header.firstItem;
NodeBuffer<size_t, Item>::NodeBuffer(std::size_t size) noexcept {
m_header.size = static_cast<size_t>(size);
ox::memset(this + 1, 0, size - sizeof(*this));
oxTracef("ox.NodeBuffer.constructor", "{}", m_header.firstItem.get());
}
template<typename size_t, typename Item>
NodeBuffer<size_t, Item>::NodeBuffer(const NodeBuffer &other, size_t size) noexcept {
oxTracef("ox::ptrarith::NodeBuffer::copy", "other.m_header.firstItem: {}", other.m_header.firstItem.get());
ox_memset(this + 1, 0, size - sizeof(*this));
ox_memcpy(this, &other, size);
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());
ox::memset(this + 1, 0, size - sizeof(*this));
ox::memcpy(this, &other, size);
}
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>
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());
}
@ -265,9 +265,10 @@ typename NodeBuffer<size_t, Item>::ItemPtr NodeBuffer<size_t, Item>::ptr(size_t
}
template<typename size_t, typename Item>
Result<typename NodeBuffer<size_t, Item>::ItemPtr> NodeBuffer<size_t, Item>::malloc(size_t size) noexcept {
oxTracef("ox::ptrarith::NodeBuffer::malloc", "Size: {}", size);
size_t fullSize = size + sizeof(Item);
Result<typename NodeBuffer<size_t, Item>::ItemPtr> NodeBuffer<size_t, Item>::malloc(std::size_t size) noexcept {
const auto sz = static_cast<std::size_t>(size);
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) {
auto last = lastItem();
size_t addr;
@ -276,23 +277,23 @@ Result<typename NodeBuffer<size_t, Item>::ItemPtr> NodeBuffer<size_t, Item>::mal
} else {
// there is no first item, so this must be the first item
if (!m_header.firstItem) {
oxTrace("ox::ptrarith::NodeBuffer::malloc", "No first item, initializing.");
m_header.firstItem = sizeof(m_header);
oxTrace("ox.ptrarith.NodeBuffer.malloc", "No first item, initializing.");
m_header.firstItem = static_cast<size_t>(sizeof(m_header));
addr = m_header.firstItem;
} 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.");
}
}
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);
if (!out.valid()) {
oxTrace("ox::ptrarith::NodeBuffer::malloc::fail", "Unknown");
oxTrace("ox.ptrarith.NodeBuffer.malloc.fail", "Unknown");
return OxError(1, "NodeBuffer::malloc: unknown failure");
}
ox_memset(out, 0, fullSize);
ox::memset(out, 0, fullSize);
new (out) Item;
out->setSize(size);
out->setSize(sz);
auto first = firstItem();
auto oldLast = last;
@ -300,7 +301,7 @@ Result<typename NodeBuffer<size_t, Item>::ItemPtr> NodeBuffer<size_t, Item>::mal
if (first.valid()) {
first->prev = out.offset();
} 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.");
}
@ -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
if (out.offset() != first.offset()) {
// 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.");
}
out->prev = out.offset();
}
m_header.bytesUsed += out.size();
oxTracef("ox::ptrarith::NodeBuffer::malloc", "Offset: {}", out.offset());
oxTracef("ox.ptrarith.NodeBuffer.malloc", "Offset: {}", out.offset());
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);
}
template<typename size_t, typename Item>
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 next = this->next(item);
if (prev.valid() && next.valid()) {
@ -337,16 +338,16 @@ Error NodeBuffer<size_t, Item>::free(ItemPtr item) noexcept {
}
} else {
// 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;
}
} else {
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);
}
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);
}
}
@ -355,18 +356,18 @@ Error NodeBuffer<size_t, Item>::free(ItemPtr item) noexcept {
}
template<typename size_t, typename Item>
Error NodeBuffer<size_t, Item>::setSize(size_t size) noexcept {
oxTracef("ox::ptrarith::NodeBuffer::setSize", "{} to {}", m_header.size.get(), size);
Error NodeBuffer<size_t, Item>::setSize(std::size_t size) noexcept {
oxTracef("ox.ptrarith.NodeBuffer.setSize", "{} to {}", m_header.size.get(), size);
auto last = lastItem();
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) {
// resizing to less than buffer size
return OxError(1);
} else {
m_header.size = size;
m_header.size = static_cast<size_t>(size);
auto data = reinterpret_cast<uint8_t*>(this) + end;
ox_memset(data, 0, size - end);
ox::memset(data, 0, size - end);
return OxError(0);
}
}
@ -387,8 +388,8 @@ size_t NodeBuffer<size_t, Item>::available() const noexcept {
}
template<typename size_t, typename Item>
size_t NodeBuffer<size_t, Item>::spaceNeeded(size_t size) noexcept {
return sizeof(Item) + size;
size_t NodeBuffer<size_t, Item>::spaceNeeded(std::size_t size) noexcept {
return static_cast<size_t>(sizeof(Item) + size);
}
template<typename size_t, typename Item>
@ -404,7 +405,7 @@ Error NodeBuffer<size_t, Item>::compact(F cb) noexcept {
return OxError(2);
}
// move node
ox_memcpy(dest, src, src->fullSize());
ox::memcpy(dest, src, src->fullSize());
oxReturnError(cb(src, dest));
// update surrounding nodes
auto prev = ptr(dest->prev);
@ -442,8 +443,8 @@ struct OX_PACKED Item {
return m_size;
}
void setSize(size_t size) {
m_size = size;
void setSize(std::size_t 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
* 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
@ -29,7 +29,13 @@ class [[nodiscard]] Ptr {
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]]
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>
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
if (itemSize >= itemTypeSize &&
dataStart &&
pDataStart &&
itemStart >= minOffset &&
itemStart + itemSize <= dataSize) {
m_dataStart = reinterpret_cast<uint8_t*>(dataStart);
m_dataStart = reinterpret_cast<uint8_t*>(pDataStart);
m_dataSize = dataSize;
m_itemOffset = itemStart;
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 SubT>
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);
}
@ -221,7 +237,7 @@ constexpr Ptr<SubT, size_t, sizeof(T)> Ptr<T, size_t, minOffset>::subPtr(size_t
template<typename T, typename size_t, size_t minOffset>
template<typename SubT>
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);
}

View File

@ -6,24 +6,23 @@ add_executable(
target_link_libraries(
FSTests
OxFS
OxStd
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::next2" FSTests PathIterator::next2)
add_test("[ox/fs] PathIterator::next3" FSTests PathIterator::next3)
add_test("[ox/fs] PathIterator::next4" FSTests PathIterator::next4)
add_test("[ox/fs] PathIterator::next5" FSTests PathIterator::next5)
add_test("[ox/fs] PathIterator::hasNext" FSTests PathIterator::hasNext)
add_test("[ox/fs] PathIterator::next1" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::next1)
add_test("[ox/fs] PathIterator::next2" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::next2)
add_test("[ox/fs] PathIterator::next3" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::next3)
add_test("[ox/fs] PathIterator::next4" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::next4)
add_test("[ox/fs] PathIterator::next5" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::next5)
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::fileName" FSTests PathIterator::fileName)
add_test("[ox/fs] PathIterator::dirPath" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests PathIterator::dirPath)
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] FileStore::readWrite" FSTests "FileStore::readWrite")
add_test("[ox/fs] NodeBuffer::insert" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests "NodeBuffer::insert")
add_test("[ox/fs] FileStore::readWrite" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests "FileStore::readWrite")
add_test("[ox/fs] Directory" FSTests "Directory")
add_test("[ox/fs] FileSystem" FSTests "FileSystem")
add_test("[ox/fs] Directory" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/FSTests "Directory")
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
* 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
@ -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",
[](std::string_view) {
[](ox::StringView) {
using BuffPtr_t = uint32_t;
ox::Vector<char> buff(5 * ox::units::MB);
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 a2 = buffer->malloc(sizeof(String)).value;
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",
[](std::string_view) {
ox::String path = "/usr/share/charset.gbag";
[](ox::StringView) {
auto const path = ox::String("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.next(buff, path.len()) == 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, path.len()) == 0 && ox_strcmp(buff, "charset.gbag") == 0, "PathIterator shows wrong next");
ox::FileName buff;
oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && buff == "charset.gbag", "PathIterator shows wrong next");
return OxError(0);
}
},
{
"PathIterator::next2",
[](std::string_view) {
ox::String path = "/usr/share/";
[](ox::StringView) {
auto const path = ox::String("/usr/share/");
ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.next(buff, path.len()) == 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");
ox::FileName buff;
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next");
return OxError(0);
}
},
{
"PathIterator::next3",
[](std::string_view) {
ox::String path = "/";
[](ox::StringView) {
auto const path = ox::String("/");
ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.next(buff, path.len()) == 0 && ox_strcmp(buff, "\0") == 0, "PathIterator shows wrong next");
ox::FileName buff;
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "\0") == 0, "PathIterator shows wrong next");
return OxError(0);
}
},
{
"PathIterator::next4",
[](std::string_view) {
ox::String path = "usr/share/charset.gbag";
[](ox::StringView) {
auto const path = ox::String("usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.next(buff, path.len()) == 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, path.len()) == 0 && ox_strcmp(buff, "charset.gbag") == 0, "PathIterator shows wrong next");
ox::FileName buff;
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "charset.gbag") == 0, "PathIterator shows wrong next");
return OxError(0);
}
},
{
"PathIterator::next5",
[](std::string_view) {
ox::String path = "usr/share/";
[](ox::StringView) {
auto const path = ox::String("usr/share/");
ox::PathIterator it(path.c_str(), path.len());
auto buff = static_cast<char*>(ox_alloca(path.len() + 1));
oxAssert(it.next(buff, path.len()) == 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");
ox::FileName buff;
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "usr") == 0, "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && ox::strcmp(buff, "share") == 0, "PathIterator shows wrong next");
return OxError(0);
}
},
{
"PathIterator::dirPath",
[] (std::string_view) {
ox::String path = "/usr/share/charset.gbag";
[] (ox::StringView) {
auto const path = ox::String("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len());
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);
}
},
{
"PathIterator::fileName",
[](std::string_view) {
ox::String path = "/usr/share/charset.gbag";
[](ox::StringView) {
auto const path = ox::String("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len());
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);
}
},
{
"PathIterator::hasNext",
[](std::string_view) {
[](ox::StringView) {
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.next().hasNext(), "PathIterator shows incorrect hasNext");
return OxError(0);
@ -143,7 +143,7 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
},
{
"Ptr::subPtr",
[](std::string_view) {
[](ox::StringView) {
constexpr auto buffLen = 5000;
ox::ptrarith::Ptr<uint8_t, uint32_t> p(ox_alloca(buffLen), buffLen, 500, 500);
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",
[](std::string_view) {
[](ox::StringView) {
constexpr auto buffLen = 5000;
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");
@ -168,12 +168,12 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
},
{
"FileStore::readWrite",
[](std::string_view) {
[](ox::StringView) {
constexpr auto buffLen = 5000;
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 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);
oxAssert(ox::FileStore32::format(list, buffLen), "FileStore::format failed.");
ox::FileStore32 fileStore(list, buffLen);
@ -189,26 +189,26 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
},
{
"Directory",
[](std::string_view) {
[](ox::StringView) {
ox::Vector<uint8_t> fsBuff(5000);
oxAssert(ox::FileStore32::format(fsBuff.data(), fsBuff.size()), "FS format failed");
ox::FileStore32 fileStore(fsBuff.data(), fsBuff.size());
ox::Directory32 dir(fileStore, 105);
oxTrace("ox::fs::test::Directory") << "Init";
oxTrace("ox.fs.test.Directory") << "Init";
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");
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").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");
oxTrace("ox::fs::test::Directory") << "write 3";
oxTrace("ox.fs.test.Directory") << "write 3";
oxAssert(dir.write("/file2", 2), "Directory write of file2 failed");
return OxError(0);
@ -216,13 +216,13 @@ const std::map<std::string_view, std::function<ox::Error(std::string_view)>> tes
},
{
"FileSystem",
[](std::string_view) {
[](ox::StringView) {
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");
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.stat("/dir").error, "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 retval = -1;
if (argc > 1) {
std::string_view testName = args[1];
std::string_view testArg;
if (args[2]) {
testArg = args[2];
}
if (tests.find(testName) != tests.end()) {
retval = static_cast<int>(tests.at(testName)(testArg));
}
if (argc < 2) {
oxError("Must specify test to run");
return -1;
}
return retval;
ox::StringView const testName = args[1];
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;
}

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
* 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>
@ -26,7 +26,7 @@ static ox::Result<Buff> loadFsBuff(const char *path) noexcept {
const auto size = static_cast<std::size_t>(file.tellg());
file.seekg(0, std::ios::beg);
const auto buff = new char[size];
file.read(buff, size);
file.read(buff, static_cast<std::streamsize>(size));
return Buff{buff, size};
} catch (const std::ios_base::failure &e) {
oxErrorf("Could not read OxFS file: {}", e.what());
@ -67,7 +67,7 @@ static ox::Error run(int argc, const char **argv) noexcept {
return OxError(1);
}
const auto fsPath = argv[1];
ox::String subCmd = argv[2];
ox::String subCmd(argv[2]);
oxRequire(fs, loadFs(fsPath));
if (subCmd == "ls") {
return runLs(fs.get(), argc - 2, argv + 2);

View File

@ -12,10 +12,16 @@ set_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(
@ -29,6 +35,6 @@ install(
install(
TARGETS
OxLogConn
LIBRARY DESTINATION lib/ox
ARCHIVE DESTINATION lib/ox
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)

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
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -47,13 +47,13 @@ class CirculerBuffer {
}
// write seg 1
const auto seg1Sz = ox::min(sz, m_buff.size() - m_writePt);
ox_memcpy(&m_buff[m_writePt], &buff[0], seg1Sz);
ox::listcpy(&m_buff[m_writePt], &buff[0], seg1Sz);
m_writePt += sz;
if (seg1Sz != sz) {
m_writePt -= m_buff.size();
// write seg 2
const auto seg2Sz = sz - seg1Sz;
ox_memcpy(&m_buff[0], &buff[seg1Sz], seg2Sz);
ox::listcpy(&m_buff[0], &buff[seg1Sz], seg2Sz);
oxAssert(m_buff[0] == buff[seg1Sz], "break");
}
return {};
@ -70,7 +70,7 @@ class CirculerBuffer {
return {};
}
constexpr ox::Error seekp(int, ios_base::seekdir) {
constexpr ox::Error seekp(int, ios_base::seekdir) noexcept {
return OxError(1, "Unimplemented");
}
@ -84,13 +84,13 @@ class CirculerBuffer {
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_memcpy(&out[0], &m_buff[m_readPt], seg1Sz);
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_memcpy(&out[seg1Sz], &m_buff[0], seg2Sz);
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

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
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -7,21 +7,38 @@
*/
#ifdef OX_USE_STDLIB
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstdio>
#include <ox/std/bit.hpp>
#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();}) {
}
@ -30,18 +47,18 @@ LoggerConn::~LoggerConn() noexcept {
m_waitCond.notify_one();
m_netThread.join();
if (m_socket) {
close(m_socket);
closeSock(m_socket);
}
}
ox::Error LoggerConn::initConn(const char *appName) noexcept {
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(connect(m_socket, reinterpret_cast<sockaddr*>(&addr), sizeof(addr))));
return sendInit({.appName = appName});
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 {
@ -81,7 +98,7 @@ void LoggerConn::msgSend() noexcept {
break;
}
//std::printf("LoggerConn: sending %lu bytes\n", read);
oxIgnoreError(send(tmp.data(), read));
std::ignore = send(tmp.data(), read);
}
}
}

View File

@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2022 gary@drinkingtea.net
* Copyright 2015 - 2024 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -17,7 +17,7 @@
#include <ox/mc/write.hpp>
#include <ox/std/trace.hpp>
#include "circularbuff.hpp"
#include "circularbuff.hpp"
namespace ox {
@ -38,14 +38,14 @@ class LoggerConn: public trace::Logger {
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(const char *appName = "") noexcept;
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));
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);

View File

@ -7,6 +7,7 @@ add_library(
if(NOT MSVC)
target_compile_options(OxMetalClaw PRIVATE -Wsign-conversion)
target_compile_options(OxMetalClaw PRIVATE -Wconversion)
endif()
target_link_libraries(
@ -38,8 +39,8 @@ install(
)
install(TARGETS OxMetalClaw
LIBRARY DESTINATION lib/ox
ARCHIVE DESTINATION lib/ox
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
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
* 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
@ -11,9 +11,9 @@
namespace ox {
enum {
MC_PRESENCEMASKOUTBOUNDS = 1,
MC_BUFFENDED = 2,
MC_OUTBUFFENDED = 4
McPresenceMapOverflow = 1,
McBuffEnded = 2,
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
* 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
@ -14,6 +14,7 @@
#include <ox/std/byteswap.hpp>
#include <ox/std/math.hpp>
#include <ox/std/memops.hpp>
#include <ox/std/reader.hpp>
namespace ox::mc {
@ -34,7 +35,7 @@ constexpr std::size_t highestBit(I val) noexcept {
if constexpr(is_signed_v<I>) {
--shiftStart;
}
for (auto i = shiftStart; i < MaxValue<decltype(i)>; --i) {
for (auto i = shiftStart; i > 0; --i) {
const auto bitValue = (val >> i) & 1;
if (bitValue) {
highestBit = i;
@ -63,13 +64,14 @@ struct McInt {
template<typename I>
[[nodiscard]]
constexpr McInt encodeInteger(I input) noexcept {
constexpr McInt encodeInteger(I pInput) noexcept {
auto const input = ox::ResizedInt_t<I, 64>{pInput};
McInt out;
const auto inputNegative = is_signed_v<I> && input < 0;
// move input to uint64_t to allow consistent bit manipulation, and to avoid
// overflow concerns
uint64_t val = 0;
ox_memcpy(&val, &input, sizeof(I));
ox::memcpy(&val, &input, sizeof(input));
if (val) {
// bits needed to represent number factoring in space possibly
// needed for signed bit
@ -92,7 +94,7 @@ constexpr McInt encodeInteger(I input) noexcept {
}
if (bytes == 9) {
out.data[0] = bytesIndicator;
ox_memcpy(&out.data[1], &leVal, sizeof(I));
ox::memcpy(&out.data[1], &leVal, 8);
if (inputNegative) {
out.data[1] |= 0b1000'0000;
}
@ -102,7 +104,7 @@ constexpr McInt encodeInteger(I input) noexcept {
auto intermediate =
static_cast<uint64_t>(leVal.raw() | (negBit << (valBits - 1))) << bytes |
static_cast<uint64_t>(bytesIndicator);
ox_memcpy(out.data, &intermediate, sizeof(intermediate));
ox::memcpy(out.data, &intermediate, sizeof(intermediate));
}
out.length = bytes;
}
@ -114,7 +116,7 @@ constexpr McInt encodeInteger(I input) noexcept {
* length integer.
*/
[[nodiscard]]
static constexpr std::size_t countBytes(unsigned b) noexcept {
constexpr std::size_t countBytes(unsigned b) noexcept {
std::size_t i = 0;
while ((b >> i) & 1) ++i;
return i + 1;
@ -131,55 +133,60 @@ static_assert(countBytes(0b0111'1111) == 8);
static_assert(countBytes(0b1111'1111) == 9);
template<typename I>
constexpr Result<I> decodeInteger(const uint8_t buff[9], std::size_t buffLen, std::size_t *bytesRead) noexcept {
const auto bytes = countBytes(buff[0]);
constexpr Result<I> decodeInteger(Reader_c auto&rdr, std::size_t *bytesRead) noexcept {
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) {
*bytesRead = bytes;
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);
} else if (buffLen >= bytes) {
*bytesRead = bytes;
uint64_t decoded = 0;
ox_memcpy(&decoded, &buff[0], bytes);
decoded >>= bytes;
// move sign bit
if constexpr(is_signed_v<I>) {
const auto negBit = bytes * 8 - bytes - 1;
// move sign
const auto negative = (decoded >> negBit) == 1;
if (negative) {
// 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
ox::Array<uint32_t, 2> d = {};
ox_memcpy(d.data(), &decoded, sizeof(decoded));
auto bit = negBit;
for (; bit < ox::min<std::size_t>(Bits<I>, 32); ++bit) {
d[0] |= 1 << bit;
}
bit -= 32;
for (; bit < Bits<I>; ++bit) {
d[1] |= 1 << bit;
}
I out = 0;
if constexpr(ox::defines::BigEndian) {
const auto d0Tmp = d[0];
d[0] = d[1];
d[1] = d0Tmp;
}
ox_memcpy(&out, d.data(), sizeof(out));
return out;
}
}
return static_cast<I>(decoded);
}
return OxError(1);
*bytesRead = bytes;
uint64_t decoded = 0;
oxReturnError(rdr.read(&decoded, bytes));
decoded >>= bytes;
// move sign bit
if constexpr(is_signed_v<I>) {
const auto negBit = bytes * 8 - bytes - 1;
// move sign
const auto negative = (decoded >> negBit) == 1;
if (negative) {
// 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
ox::Array<uint32_t, 2> d = {};
//d[0] = decoded & 0xffff'ffff;
//d[1] = decoded >> 32;
ox::memcpy(d.data(), &decoded, sizeof(decoded));
auto bit = negBit;
for (; bit < ox::min<std::size_t>(Bits<I>, 32); ++bit) {
d[0] |= 1 << bit;
}
bit -= 32;
for (; bit < Bits<I>; ++bit) {
d[1] |= 1 << bit;
}
I out = 0;
if constexpr(ox::defines::BigEndian) {
const auto d0Tmp = d[0];
d[0] = d[1];
d[1] = d0Tmp;
}
ox::memcpy(&out, d.data(), sizeof(out));
return out;
}
}
return static_cast<I>(decoded);
}
template<typename I>
constexpr Result<I> decodeInteger(McInt m) noexcept {
std::size_t bytesRead;
return decodeInteger<I>(m.data, 9, &bytesRead);
Result<I> decodeInteger(McInt m) noexcept {
std::size_t 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
* 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

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
* 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"
@ -11,7 +11,7 @@
namespace ox {
template class FieldBitmapReader<uint8_t*>;
template class FieldBitmapReader<const uint8_t*>;
template class FieldBitmapWriterBase<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
* 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
#include <ox/std/array.hpp>
#include <ox/std/bit.hpp>
#include <ox/std/error.hpp>
#include <ox/std/types.hpp>
#include <ox/std/reader.hpp>
#include "err.hpp"
namespace ox {
template<typename T>
template<Reader_c Reader>
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:
T m_map = nullptr;
std::size_t m_mapLen = 0;
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;
@ -34,39 +94,45 @@ class FieldBitmapReader {
};
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_mapLen = maxLen;
}
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) {
return (m_map[i / 8] >> (i % 8)) & 1;
} else {
return OxError(MC_PRESENCEMASKOUTBOUNDS);
return OxError(McPresenceMapOverflow);
}
}
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));
}
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);
}
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);
}
extern template class FieldBitmapReader<uint8_t*>;
extern template class FieldBitmapReader<const uint8_t*>;
extern template class FieldBitmapWriterBase<uint8_t*>;
extern template class FieldBitmapWriterBase<const uint8_t*>;
class FieldBitmap: public FieldBitmapReader<uint8_t*> {
class FieldBitmap: public FieldBitmapWriterBase<uint8_t*> {
public:
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 {
@ -83,11 +150,11 @@ constexpr Error FieldBitmap::set(std::size_t i, bool on) noexcept {
if (on) {
m_map[i / 8] |= 1 << (i % 8);
} else {
m_map[i / 8] &= ~(1 << (i % 8));
m_map[i / 8] &= ~static_cast<uint8_t>(1 << (i % 8));
}
return OxError(0);
return {};
} 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
* 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 <ox/model/modelhandleradaptor.hpp>
#include <ox/std/buffer.hpp>
#include <ox/std/reader.hpp>
#include "read.hpp"
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
* 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/std/buffer.hpp>
#include <ox/std/byteswap.hpp>
#include <ox/std/optional.hpp>
#include <ox/std/string.hpp>
#include <ox/std/trace.hpp>
#include <ox/std/vector.hpp>
@ -26,22 +27,20 @@
namespace ox {
template<auto HandlerMaker>
class MetalClawReaderTemplate {
template<Reader_c Reader>
class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<Reader>, ox::OpType::Read> {
private:
FieldBitmapReader<const uint8_t*> m_fieldPresence;
int m_fields = 0;
int m_field = 0;
int m_unionIdx = -1;
std::size_t m_buffIt = 0;
std::size_t m_buffLen = 0;
const uint8_t *m_buff = nullptr;
MetalClawReaderTemplate<HandlerMaker> *m_parent = nullptr;
FieldBitmapReader<Reader> m_fieldPresence;
std::size_t m_fields = 0;
std::size_t m_field = 0;
ox::Optional<int> m_unionIdx;
Reader &m_reader;
public:
constexpr MetalClawReaderTemplate(const uint8_t *buff, std::size_t buffLen, int unionIdx = -1,
MetalClawReaderTemplate<HandlerMaker> *parent = nullptr) noexcept;
explicit constexpr MetalClawReaderTemplate(
Reader &reader,
ox::Optional<int> const&unionIdx = {}) noexcept;
constexpr ~MetalClawReaderTemplate() noexcept;
@ -78,7 +77,7 @@ class MetalClawReaderTemplate {
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 field(const char*, IString<L> *val) 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.
*/
[[nodiscard]]
constexpr StringLength stringLength(const char *name) noexcept;
constexpr Result<StringLength> stringLength(const char *name) noexcept;
template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion,
const Vector<String>& = {}, int fields = ModelFieldCount_v<T>) noexcept;
constexpr ox::Error setTypeInfo(
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.
*/
[[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.
@ -125,142 +126,130 @@ class MetalClawReaderTemplate {
constexpr void nextField() noexcept;
[[nodiscard]]
static constexpr auto opType() noexcept {
return OpType::Read;
}
private:
template<typename I>
constexpr Error readInteger(I *val) noexcept;
};
template<auto HandlerMaker>
constexpr MetalClawReaderTemplate<HandlerMaker>::MetalClawReaderTemplate(const uint8_t *buff, std::size_t buffLen,
int unionIdx,
MetalClawReaderTemplate *parent) noexcept:
m_fieldPresence(buff, buffLen),
template<Reader_c Reader>
constexpr MetalClawReaderTemplate<Reader>::MetalClawReaderTemplate(
Reader &reader,
ox::Optional<int> const&unionIdx) noexcept:
m_fieldPresence(reader),
m_unionIdx(unionIdx),
m_buffLen(buffLen),
m_buff(buff),
m_parent(parent) {
m_reader(reader) {
}
template<auto HandlerMaker>
constexpr MetalClawReaderTemplate<HandlerMaker>::~MetalClawReaderTemplate() noexcept {
if (m_parent) {
m_parent->m_buffIt += m_buffIt;
}
template<Reader_c Reader>
constexpr MetalClawReaderTemplate<Reader>::~MetalClawReaderTemplate() noexcept {
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>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int8_t *val) noexcept {
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int8_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int16_t *val) noexcept {
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int16_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int32_t *val) noexcept {
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int32_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, int64_t *val) noexcept {
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, int64_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint8_t *val) noexcept {
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint8_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint16_t *val) noexcept {
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint16_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint32_t *val) noexcept {
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint32_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, uint64_t *val) noexcept {
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, uint64_t *val) noexcept {
return readInteger(val);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, bool *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
auto valErr = m_fieldPresence.get(static_cast<std::size_t>(m_field));
*val = valErr.value;
oxReturnError(valErr.error);
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, bool *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) {
auto const result = m_fieldPresence.get(static_cast<std::size_t>(m_field));
*val = result.value;
oxReturnError(result);
}
++m_field;
return OxError(0);
}
// array handler
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char *name, auto *val, std::size_t valLen) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, auto *val, std::size_t valLen) 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
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
oxRequire(len, mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead));
m_buffIt += bytesRead;
oxRequire(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
// read the list
if (valLen >= len) {
auto reader = child("");
auto handler = HandlerMaker(&reader);
handler.setTypeInfo("List", 0, {}, static_cast<int>(len));
auto reader = child({});
auto &handler = *reader.interface();
oxReturnError(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len)));
for (std::size_t i = 0; i < len; ++i) {
oxReturnError(handler.field("", &val[i]));
oxReturnError(handler.field({}, &val[i]));
}
} else {
oxTrace("ox::mc::read::field(T)") << name << ", size:" << valLen;
return OxError(MC_OUTBUFFENDED);
oxTracef("ox.mc.read.field(T)", "{}, length: {}", name, valLen);
return OxError(McOutputBuffEnded);
}
}
}
++m_field;
return OxError(0);
return {};
}
template<auto HandlerMaker>
template<Reader_c Reader>
template<typename T>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, HashMap<String, T> *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, HashMap<String, T> *val) 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
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
oxRequire(g, m_reader.tellg());
std::size_t bytesRead = 0;
oxRequire(len, mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead));
m_buffIt += bytesRead;
oxRequire(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
oxReturnError(m_reader.seekg(g));
// read the list
auto reader = child("");
auto handler = HandlerMaker(&reader);
handler.setTypeInfo("List", 0, {}, static_cast<int>(len));
for (std::size_t i = 0; i < len; ++i) {
const auto keyLen = handler.stringLength(nullptr);
auto &handler = *reader.interface();
oxReturnError(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len)));
// this loop body needs to be in a lambda because of the potential alloca call
constexpr auto loopBody = [](auto &handler, auto &val) {
oxRequire(keyLen, handler.stringLength(nullptr));
auto wkey = ox_malloca(keyLen + 1, char, 0);
auto wkeyPtr = wkey.get();
oxReturnError(handler.fieldCString("", &wkeyPtr, static_cast<int>(keyLen + 1)));
oxReturnError(handler.field("", &val->operator[](wkey.get())));
oxReturnError(handler.fieldCString("", &wkeyPtr, keyLen + 1));
return handler.field("", &val[wkeyPtr]);
};
for (std::size_t i = 0; i < len; ++i) {
oxReturnError(loopBody(handler, *val));
}
}
}
@ -268,71 +257,72 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, HashMa
return OxError(0);
}
template<auto HandlerMaker>
template<Reader_c Reader>
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 (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
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
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());
}
++m_field;
return OxError(0);
return {};
} 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))) {
auto reader = child("");
auto handler = HandlerMaker(&reader);
oxReturnError(model(&handler, val));
oxReturnError(model(reader.interface(), val));
}
}
++m_field;
return OxError(0);
return {};
}
}
template<auto HandlerMaker>
template<Reader_c Reader>
template<typename U, bool force>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, UnionView<U, force> val) noexcept {
if ((m_unionIdx == -1 || m_unionIdx == m_field) && val.get()) {
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, UnionView<U, force> val) noexcept {
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))) {
auto reader = child("", val.idx());
auto handler = HandlerMaker(&reader);
oxReturnError(model(&handler, val.get()));
auto reader = child("", ox::Optional<int>(ox::in_place, val.idx()));
oxReturnError(model(reader.interface(), val.get()));
}
}
++m_field;
return OxError(0);
return {};
}
template<auto HandlerMaker>
template<Reader_c Reader>
template<std::size_t SmallStringSize>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, BasicString<SmallStringSize> *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, BasicString<SmallStringSize> *val) 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
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
oxRequire(size, mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead));
m_buffIt += bytesRead;
oxRequire(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
const auto cap = size;
*val = BasicString<SmallStringSize>(cap);
auto data = val->data();
// read the string
if (static_cast<StringLength>(cap) < size) {
return OxError(MC_OUTBUFFENDED);
}
if (m_buffIt + size > m_buffLen) {
return OxError(MC_BUFFENDED);
}
ox_strncpy(data, &m_buff[m_buffIt], size);
m_buffIt += size;
oxReturnError(m_reader.read(data, size));
} else {
*val = "";
}
@ -341,81 +331,71 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, BasicS
return OxError(0);
}
template<auto HandlerMaker>
template<Reader_c Reader>
template<std::size_t L>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char *name, BString<L> *val) noexcept {
return fieldCString(name, val->data(), val->cap());
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, IString<L> *val) 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;
oxRequire(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
*val = IString<L>();
oxReturnError(val->resize(size));
auto const data = val->data();
// read the string
oxReturnError(m_reader.read(data, size));
} else {
*val = "";
}
}
++m_field;
return {};
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::fieldCString(const char*, char *val, std::size_t buffLen) noexcept {
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
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
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) {
return OxError(MC_OUTBUFFENDED);
return OxError(McOutputBuffEnded);
}
m_buffIt += bytesRead;
oxReturnError(err);
// re-allocate in case too small
auto data = val;
// read the string
if (m_buffIt + size <= m_buffLen) {
ox_memcpy(data, &m_buff[m_buffIt], size);
data[size] = 0;
m_buffIt += size;
} else {
return OxError(MC_BUFFENDED);
}
oxReturnError(m_reader.read(data, size));
data[size] = 0;
}
++m_field;
return OxError(0);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::fieldCString(const char*, char **val) noexcept {
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char **val) noexcept {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
// read the length
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
m_buffIt += bytesRead;
oxReturnError(err);
oxRequire(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
// re-allocate in case too small
safeDelete(*val);
*val = new char[size + 1];
auto data = *val;
// read the string
if (m_buffIt + size <= m_buffLen) {
ox_memcpy(data, &m_buff[m_buffIt], size);
data[size] = 0;
m_buffIt += size;
} else {
return OxError(MC_BUFFENDED);
}
oxReturnError(m_reader.read(data, size));
data[size] = 0;
}
++m_field;
return OxError(0);
}
template<auto HandlerMaker>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::fieldCString(const char*, char **val, std::size_t buffLen) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(const char*, char **val, std::size_t buffLen) 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
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto [size, err] = mc::decodeInteger<StringLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
m_buffIt += bytesRead;
oxReturnError(err);
oxRequire(size, mc::decodeInteger<StringLength>(m_reader, &bytesRead));
// re-allocate if too small
if (buffLen < size + 1) {
safeDelete(*val);
@ -424,13 +404,8 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::fieldCString(const char*,
}
auto data = *val;
// read the string
if (m_buffIt + size <= m_buffLen) {
ox_memcpy(data, &m_buff[m_buffIt], size);
data[size] = 0;
m_buffIt += size;
} else {
return OxError(MC_BUFFENDED);
}
oxReturnError(m_reader.read(data, size));
data[size] = 0;
} else {
auto data = *val;
if (data) {
@ -442,18 +417,16 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::fieldCString(const char*,
return OxError(0);
}
template<auto HandlerMaker>
constexpr Result<ArrayLength> MetalClawReaderTemplate<HandlerMaker>::arrayLength(const char*, bool pass) noexcept {
if ((m_unionIdx == -1 || m_unionIdx == m_field)) {
template<Reader_c Reader>
constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(const char*, bool pass) 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
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
auto out = mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead).value;
if (pass) {
m_buffIt += bytesRead;
oxRequire(g, m_reader.tellg());
oxRequire(out, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
if (!pass) {
oxReturnError(m_reader.seekg(g));
}
return out;
}
@ -461,20 +434,29 @@ constexpr Result<ArrayLength> MetalClawReaderTemplate<HandlerMaker>::arrayLength
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>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::readInteger(I *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
constexpr Error MetalClawReaderTemplate<Reader>::readInteger(I *val) 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))) {
std::size_t bytesRead = 0;
if (m_buffIt >= m_buffLen) {
oxTrace("ox::MetalClaw::readInteger") << "Buffer ended";
return OxError(MC_BUFFENDED);
}
auto valErr = mc::decodeInteger<I>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead);
m_buffIt += bytesRead;
oxReturnError(valErr.error);
*val = valErr.value;
auto const result = mc::decodeInteger<I>(m_reader, &bytesRead);
oxReturnError(result);
*val = result.value;
} else {
*val = 0;
}
@ -483,23 +465,18 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::readInteger(I *val) noexc
return OxError(0);
}
template<auto HandlerMaker>
template<Reader_c Reader>
template<typename T, typename CB>
constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, CB cb) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, CB cb) 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
if (m_buffIt >= m_buffLen) {
return OxError(MC_BUFFENDED);
}
std::size_t bytesRead = 0;
oxRequire(len, mc::decodeInteger<ArrayLength>(&m_buff[m_buffIt], m_buffLen - m_buffIt, &bytesRead));
m_buffIt += bytesRead;
oxRequire(len, mc::decodeInteger<ArrayLength>(m_reader, &bytesRead));
// read the list
auto reader = child("");
auto handler = HandlerMaker(&reader);
handler.setTypeInfo("List", 0, {}, static_cast<int>(len));
auto &handler = *reader.interface();
oxReturnError(handler.setTypeInfo("List", 0, {}, static_cast<std::size_t>(len)));
for (std::size_t i = 0; i < len; ++i) {
T val;
oxReturnError(handler.field("", &val));
@ -511,48 +488,38 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, CB cb)
return OxError(0);
}
template<auto HandlerMaker>
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<Reader_c Reader>
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_buffIt = static_cast<std::size_t>((fields / 8 + 1) - (fields % 8 == 0));
m_fieldPresence.setFields(fields);
m_fieldPresence.setMaxLen(static_cast<int>(m_buffIt));
// Warning: narrow-conv
return m_reader.seekg(
static_cast<int>((fields / 8 + 1) - (fields % 8 == 0)),
ox::ios_base::cur);
}
template<auto HandlerMaker>
constexpr MetalClawReaderTemplate<HandlerMaker> MetalClawReaderTemplate<HandlerMaker>::child(const char*, int unionIdx) noexcept {
return MetalClawReaderTemplate<HandlerMaker>(m_buff + m_buffIt, m_buffLen - m_buffIt, unionIdx, this);
template<Reader_c Reader>
constexpr MetalClawReaderTemplate<Reader> MetalClawReaderTemplate<Reader>::child(
const char*,
ox::Optional<int> unionIdx) noexcept {
return MetalClawReaderTemplate<Reader>(m_reader, unionIdx);
}
template<auto HandlerMaker>
constexpr bool MetalClawReaderTemplate<HandlerMaker>::fieldPresent(const char*) const noexcept {
template<Reader_c Reader>
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(const char*) const noexcept {
return m_fieldPresence.get(static_cast<std::size_t>(m_field)).value;
}
template<auto HandlerMaker>
constexpr bool MetalClawReaderTemplate<HandlerMaker>::fieldPresent(int fieldNo) const noexcept {
template<Reader_c Reader>
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(int fieldNo) const noexcept {
return m_fieldPresence.get(static_cast<std::size_t>(fieldNo)).value;
}
template<auto HandlerMaker>
template<Reader_c Reader>
[[nodiscard]]
constexpr int MetalClawReaderTemplate<HandlerMaker>::whichFieldPresent(const char*, const ModelUnion &u) const noexcept {
FieldBitmapReader<const uint8_t*> p(m_buff + m_buffIt, m_buffLen - m_buffIt);
p.setFields(u.fieldCount());
constexpr int MetalClawReaderTemplate<Reader>::whichFieldPresent(const char*, const ModelUnion &u) const noexcept {
FieldBitmapReader<Reader> p(m_reader);
for (auto i = 0u; i < u.fieldCount(); ++i) {
if (p.get(i)) {
return static_cast<int>(i);
@ -561,32 +528,28 @@ constexpr int MetalClawReaderTemplate<HandlerMaker>::whichFieldPresent(const cha
return -1;
}
template<auto HandlerMaker>
constexpr void MetalClawReaderTemplate<HandlerMaker>::nextField() noexcept {
template<Reader_c Reader>
constexpr void MetalClawReaderTemplate<Reader>::nextField() noexcept {
++m_field;
}
using MetalClawReader = MetalClawReaderTemplate<[](auto r) {
return ModelHandlerInterface{r};
}>;
using MetalClawReader = MetalClawReaderTemplate<ox::BufferReader>;
template<typename T>
Error readMC(const char *buff, std::size_t buffLen, T *val) noexcept {
MetalClawReader reader(reinterpret_cast<const uint8_t*>(buff), buffLen);
ModelHandlerInterface handler(&reader);
return model(&handler, val);
Error readMC(ox::BufferView buff, T &val) noexcept {
BufferReader br(buff);
MetalClawReader reader(br);
ModelHandlerInterface<MetalClawReader, ox::OpType::Read> handler(&reader);
return model(&handler, &val);
}
template<typename T>
Result<T> readMC(const char *buff, std::size_t buffLen) noexcept {
T val;
oxReturnError(readMC(buff, buffLen, &val));
Result<T> readMC(ox::BufferView buff) noexcept {
Result<T> val;
oxReturnError(readMC(buff, val.value));
return val;
}
template<typename T>
Result<T> readMC(const Buffer &buff) noexcept {
return readMC<T>(buff.data(), buff.size());
}
extern template class ModelHandlerInterface<MetalClawReaderTemplate<BufferReader>>;
}

View File

@ -8,9 +8,9 @@ target_link_libraries(
OxMetalClaw
)
add_test("[ox/mc] McTest Writer" McTest MetalClawWriter)
add_test("[ox/mc] McTest Reader" McTest MetalClawReader)
#add_test("[ox/mc] McTest MetalClawDef" McTest MetalClawDef)
add_test("[ox/mc] McTest MetalClawModelValue" McTest MetalClawModelValue)
add_test("[ox/mc] McTest encodeInteger" McTest encodeInteger)
add_test("[ox/mc] McTest decodeInteger" McTest decodeInteger)
add_test("[ox/mc] Writer" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/McTest MetalClawWriter)
add_test("[ox/mc] Reader" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/McTest MetalClawReader)
#add_test("[ox/mc] MetalClawDef" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/McTest MetalClawDef)
add_test("[ox/mc] MetalClawModelValue" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/McTest MetalClawModelValue)
add_test("[ox/mc] encodeInteger" ${CMAKE_RUNTIME_OUTPUT_DIRECTORY}/McTest encodeInteger)
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
* 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 TypeVersion = 1;
bool Bool;
uint32_t Int = 5;
char *CString;
uint32_t Int;
char *CString{};
};
struct TestStructNest {
@ -27,7 +27,7 @@ struct TestStructNest {
static constexpr auto TypeVersion = 1;
bool Bool = false;
uint32_t Int = 0;
ox::BString<32> BString = "";
ox::IString<32> IString = "";
};
struct TestStruct {
@ -45,10 +45,11 @@ struct TestStruct {
int32_t Int8 = 0;
int unionIdx = 1;
TestUnion Union;
ox::String String = "";
ox::BString<32> BString = "";
ox::String String;
ox::IString<32> IString = "";
uint32_t List[4] = {0, 0, 0, 0};
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;
TestStructNest EmptyStruct;
TestStructNest Struct;
@ -61,7 +62,7 @@ struct TestStruct {
template<typename T>
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("Int", &obj->Int));
oxReturnError(io->fieldCString("CString", &obj->CString));
@ -71,13 +72,12 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith<TestUnion> auto *obj) noexcep
oxModelBegin(TestStructNest)
oxModelField(Bool)
oxModelField(Int)
oxModelField(BString)
oxModelField(IString)
oxModelEnd()
template<typename T>
constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) noexcept {
io->template setTypeInfo<TestStruct>();
oxReturnError(io->field("Vector", &obj->Vector));
oxReturnError(io->template setTypeInfo<TestStruct>());
oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int));
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("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("Vector", &obj->Vector));
oxReturnError(io->field("Vector2", &obj->Vector2));
oxReturnError(io->field("Map", &obj->Map));
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));
oxReturnError(io->field("Struct", &obj->Struct));
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));
return OxError(0);
}
std::map<ox::String, ox::Error(*)()> tests = {
std::map<ox::StringView, ox::Error(*)()> tests = {
{
{
"MetalClawWriter",
[] {
// This test doesn't confirm much, but it does show that the writer
// doesn't segfault
static constexpr size_t buffLen = 1024;
char buff[buffLen];
ox::Array<char, 1024> buff;
TestStruct ts;
oxReturnError(ox::writeMC(buff, buffLen, &ts));
oxReturnError(ox::writeMC(buff.data(), buff.size(), ts));
oxReturnError(ox::writeMC(ts));
return OxError(0);
}
},
@ -122,26 +124,26 @@ std::map<ox::String, ox::Error(*)()> tests = {
"MetalClawReader",
[] {
// setup for tests
static constexpr size_t buffLen = 1024;
char buff[buffLen];
TestStruct testIn, testOut;
testIn.Bool = true;
testIn.Int = 42;
testIn.Union.Int = 42;
testIn.String = "Test String 0";
testIn.BString = "Test String 1";
testIn.IString = "Test String 1";
testIn.String = "Test String 2";
testIn.Vector = { 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, };
testIn.Vector2 = {};
testIn.List[0] = 1;
testIn.List[1] = 2;
testIn.List[2] = 3;
testIn.List[3] = 4;
testIn.Map["asdf"] = 93;
testIn.Map["aoeu"] = 94;
testIn.Struct.Bool = false;
testIn.Struct.Bool = true;
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
oxAssert(ox::writeMC(buff, buffLen, &testIn), "writeMC failed");
oxAssert(ox::readMC(buff, buffLen, &testOut), "readMC failed");
const auto [buff, err] = ox::writeMC(testIn);
oxAssert(err, "writeMC failed");
oxAssert(ox::readMC(buff, testOut), "readMC failed");
//std::cout << testIn.Union.Int << "|" << testOut.Union.Int << "|\n";
oxAssert(testIn.Bool == testOut.Bool, "Bool 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.Union.Int == testOut.Union.Int, "Union.Int 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[1] == testOut.List[1], "List[1] 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.Vector[0] == testOut.Vector[0], "Vector[0] value mismatch");
oxAssert(testIn.Vector[1] == testOut.Vector[1], "Vector[1] value mismatch");
oxAssert(testIn.Vector[2] == testOut.Vector[2], "Vector[2] value mismatch");
oxAssert(testIn.Vector[3] == testOut.Vector[3], "Vector[3] value mismatch");
oxAssert(testIn.Vector.size() == testOut.Vector.size(), "Vector size mismatch");
for (auto i = 0u; i < testIn.Vector.size(); ++i) {
oxAssert(testIn.Vector[i] == testOut.Vector[i], ox::sfmt("Vector[{}] value mismatch", i));
}
oxAssert(testIn.Vector2.size() == testOut.Vector2.size(), "Vector2 size 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.EmptyStruct.Bool == testOut.EmptyStruct.Bool, "EmptyStruct.Bool 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.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");
return OxError(0);
}
@ -264,6 +268,9 @@ std::map<ox::String, ox::Error(*)()> tests = {
return OxError(0);
};
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(-2)), "Decode of -2 failed.");
oxAssert(check(int64_t(-127)), "Decode of -127 failed.");
@ -297,44 +304,44 @@ std::map<ox::String, ox::Error(*)()> tests = {
TestStruct testIn;
testIn.Bool = true;
testIn.Int = 42;
testIn.BString = "Test String 1";
testIn.IString = "Test String 1";
testIn.List[0] = 1;
testIn.List[1] = 2;
testIn.List[2] = 3;
testIn.List[3] = 4;
testIn.Struct.Bool = true;
testIn.Struct.Int = 300;
testIn.Struct.BString = "Test String 2";
testIn.Struct.IString = "Test String 2";
testIn.unionIdx = 1;
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;
const auto [type, typeErr] = ox::buildTypeDef(&typeStore, &testIn);
oxAssert(typeErr, "Descriptor write failed");
ox::ModelObject testOut;
oxReturnError(testOut.setType(type));
oxAssert(ox::readMC(dataBuff.data(), dataBuff.size(), &testOut), "Data read failed");
oxAssert(testOut["Int"].get<int>() == testIn.Int, "testOut.Int failed");
oxAssert(testOut["Bool"].get<bool>() == testIn.Bool, "testOut.Bool failed");
oxAssert(testOut["BString"].get<ox::String>() == testIn.BString.c_str(), "testOut.String failed");
oxAssert(testOut["String"].get<ox::String>() == testIn.String, "testOut.String failed");
auto &testOutStruct = testOut["Struct"].get<ox::ModelObject>();
auto &testOutUnion = testOut["Union"].get<ox::ModelUnion>();
auto &testOutList = testOut["List"].get<ox::ModelValueVector>();
auto testOutStructCopy = testOut["Struct"].get<ox::ModelObject>();
auto testOutUnionCopy = testOut["Union"].get<ox::ModelUnion>();
auto testOutListCopy = testOut["List"].get<ox::ModelValueVector>();
oxAssert(ox::readMC(dataBuff, testOut), "Data read failed");
oxAssert(testOut.at("Int").unwrap()->get<int>() == testIn.Int, "testOut.Int failed");
oxAssert(testOut.at("Bool").unwrap()->get<bool>() == testIn.Bool, "testOut.Bool failed");
oxAssert(testOut.at("IString").unwrap()->get<ox::String>() == testIn.IString.c_str(), "testOut.String failed");
oxAssert(testOut.at("String").unwrap()->get<ox::String>() == testIn.String, "testOut.String failed");
auto &testOutStruct = testOut.at("Struct").unwrap()->get<ox::ModelObject>();
auto &testOutUnion = testOut.at("Union").unwrap()->get<ox::ModelUnion>();
auto &testOutList = testOut.at("List").unwrap()->get<ox::ModelValueVector>();
auto testOutStructCopy = testOut.at("Struct").unwrap()->get<ox::ModelObject>();
auto testOutUnionCopy = testOut.at("Union").unwrap()->get<ox::ModelUnion>();
auto testOutListCopy = testOut.at("List").unwrap()->get<ox::ModelValueVector>();
oxAssert(testOutStruct.typeName() == TestStructNest::TypeName, "ModelObject TypeName failed");
oxAssert(testOutStruct.typeVersion() == TestStructNest::TypeVersion, "ModelObject TypeVersion failed");
oxAssert(testOutStruct["Bool"].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(testOut["unionIdx"].get<int>() == testIn.unionIdx, "testOut.unionIdx failed");
oxAssert(testOutStruct.at("Bool").unwrap()->get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool failed");
oxAssert(testOutStruct.at("IString").unwrap()->get<ox::String>() == testIn.Struct.IString.c_str(), "testOut.Struct.IString failed");
oxAssert(testOut.at("unionIdx").unwrap()->get<int>() == testIn.unionIdx, "testOut.unionIdx failed");
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[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["BString"].get<ox::String>() == testIn.Struct.BString.c_str(), "testOut.Struct.BString (copy) failed");
oxAssert(testOutStructCopy.at("Bool").unwrap()->get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool (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[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] (copy) failed");
return OxError(0);
@ -351,19 +358,20 @@ std::map<ox::String, ox::Error(*)()> tests = {
TestStruct testIn, testOut;
testIn.Bool = true;
testIn.Int = 42;
testIn.BString = "Test String 1";
testIn.IString = "Test String 1";
testIn.List[0] = 1;
testIn.List[1] = 2;
testIn.List[2] = 3;
testIn.List[3] = 4;
testIn.Struct.Bool = false;
testIn.Struct.Int = 300;
testIn.Struct.BString = "Test String 2";
oxAssert(ox::writeMC(dataBuff, dataBuffLen, &testIn), "Data generation failed");
testIn.Struct.IString = "Test String 2";
oxAssert(ox::writeMC(dataBuff, dataBuffLen, testIn), "Data generation failed");
ox::TypeStore typeStore;
const auto [type, typeErr] = ox::buildTypeDef(&typeStore, &testIn);
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 {
//std::cout << f.fieldName.c_str() << '\n';
auto fieldName = f.fieldName.c_str();
@ -456,11 +464,14 @@ std::map<ox::String, ox::Error(*)()> tests = {
};
int main(int argc, const char **args) {
if (argc > 0) {
auto testName = args[1];
if (tests.find(testName) != tests.end()) {
oxAssert(tests[testName](), "Test failed...");
}
if (argc < 2) {
oxError("Must specify test to run");
}
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;
}

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
* 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
@ -14,7 +14,7 @@
namespace ox {
using StringLength = uint32_t;
using ArrayLength = uint32_t;
using StringLength = std::size_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
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -15,6 +15,7 @@
namespace ox {
template class ModelHandlerInterface<MetalClawWriter>;
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
* 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/byteswap.hpp>
#include <ox/std/hashmap.hpp>
#include <ox/std/optional.hpp>
#include <ox/std/string.hpp>
#include <ox/std/types.hpp>
#include <ox/std/units.hpp>
@ -27,54 +28,45 @@
namespace ox {
template<Writer_c Writer>
class MetalClawWriter {
private:
ox::Vector<uint8_t, 16> m_presenceMapBuff{};
FieldBitmap m_fieldPresence;
int m_fields = 0;
int m_field = 0;
int m_unionIdx = -1;
std::size_t m_buffIt = 0;
std::size_t m_buffLen = 0;
uint8_t *m_buff = nullptr;
ox::Optional<int> m_unionIdx;
std::size_t m_writerBeginP{};
Writer &m_writer;
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 = default;
constexpr Error field(const char*, CommonPtrWith<int8_t> auto *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<int16_t> auto *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<int32_t> auto *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<int64_t> auto *val) noexcept;
constexpr Error field(const char*, const int8_t *val) noexcept;
constexpr Error field(const char*, const int16_t *val) noexcept;
constexpr Error field(const char*, const int32_t *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*, CommonPtrWith<uint16_t> auto *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<uint32_t> auto *val) noexcept;
constexpr Error field(const char*, CommonPtrWith<uint64_t> auto *val) noexcept;
constexpr Error field(const char*, const uint8_t *val) noexcept;
constexpr Error field(const char*, const uint16_t *val) noexcept;
constexpr Error field(const char*, const uint32_t *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>
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>
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>
constexpr Error field(const char*, const BasicString<SmallStringSize> *val) noexcept;
template<std::size_t L>
constexpr Error field(const char*, const BString<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 field(const char*, const IString<L> *val) noexcept;
constexpr Error fieldCString(const char *name, const char *const*val, std::size_t buffLen) noexcept;
@ -84,27 +76,18 @@ class MetalClawWriter {
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>
constexpr Error field(const char*, T *val) noexcept;
constexpr Error field(const char*, const T *val) noexcept;
template<typename U, bool force = false>
constexpr Error field(const char*, UnionView<U, force> val) noexcept;
template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion,
const Vector<String>& = {}, int fields = ModelFieldCount_v<T>) noexcept;
constexpr ox::Error setTypeInfo(
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
@ -122,312 +105,302 @@ class MetalClawWriter {
return 0;
}
[[nodiscard]]
constexpr std::size_t size() const noexcept;
[[nodiscard]]
static constexpr auto opType() noexcept {
return OpType::Write;
}
ox::Error finalize() noexcept;
private:
constexpr Error appendInteger(Integer_c auto val) noexcept {
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);
if (mi.length < m_buffLen) {
fieldSet = true;
ox_memcpy(&m_buff[m_buffIt], mi.data, mi.length);
m_buffIt += mi.length;
} else {
return OxError(MC_BUFFENDED);
}
oxReturnError(m_writer.write(reinterpret_cast<const char*>(mi.data), mi.length));
fieldSet = true;
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
++m_field;
return OxError(0);
}
};
extern template class ModelHandlerInterface<MetalClawWriter>;
extern template class ModelHandlerInterface<MetalClawWriter<BufferWriter>>;
extern template class ModelHandlerInterface<MetalClawWriter<CharBuffWriter>>;
constexpr MetalClawWriter::MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx) noexcept:
m_fieldPresence(buff, buffLen),
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_buffLen(buffLen),
m_buff(buff) {
m_writerBeginP(writer.tellp()),
m_writer(writer) {
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<int8_t> auto *val) noexcept {
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, const int8_t *val) noexcept {
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);
}
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);
}
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);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<uint8_t> auto *val) noexcept {
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(const char*, const uint8_t *val) noexcept {
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);
}
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);
}
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);
}
constexpr Error MetalClawWriter::field(const char*, CommonPtrWith<bool> auto *val) noexcept {
if (m_unionIdx == -1 || m_unionIdx == m_field) {
template<Writer_c Writer>
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));
}
++m_field;
return OxError(0);
}
template<Writer_c Writer>
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;
if (val->len() && (m_unionIdx == -1 || m_unionIdx == m_field)) {
if (val->len() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
const auto strLen = mc::encodeInteger(val->len());
if (m_buffIt + strLen.length + static_cast<std::size_t>(val->len()) < m_buffLen) {
memcpy(&m_buff[m_buffIt], strLen.data, strLen.length);
m_buffIt += strLen.length;
// write the string
memcpy(&m_buff[m_buffIt], val->c_str(), static_cast<std::size_t>(val->len()));
m_buffIt += static_cast<std::size_t>(val->len());
fieldSet = true;
} else {
return OxError(MC_BUFFENDED);
}
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLen.data), strLen.length));
// write the string
oxReturnError(m_writer.write(val->c_str(), static_cast<std::size_t>(val->len())));
fieldSet = true;
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return OxError(0);
}
template<Writer_c Writer>
template<std::size_t L>
constexpr Error MetalClawWriter::field(const char *name, const BString<L> *val) noexcept {
return fieldCString(name, val->data(), val->cap());
constexpr Error MetalClawWriter<Writer>::field(const char *name, const IString<L> *val) noexcept {
return fieldCString(name, val->data(), val->len());
}
template<std::size_t SmallStringSize>
constexpr Error MetalClawWriter::field(const char *name, BasicString<SmallStringSize> *val) 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 {
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(const char*, const char *const*val, std::size_t) noexcept {
bool fieldSet = false;
if (m_unionIdx == -1 || m_unionIdx == m_field) {
const auto strLen = *val ? ox_strlen(*val) : 0;
if (!m_unionIdx.has_value() || *m_unionIdx == m_field) {
const auto strLen = *val ? ox::strlen(*val) : 0;
// write the length
const auto strLenBuff = mc::encodeInteger(strLen);
if (m_buffIt + strLenBuff.length + static_cast<std::size_t>(strLen) < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], strLenBuff.data, strLenBuff.length);
m_buffIt += strLenBuff.length;
// write the string
ox_memcpy(&m_buff[m_buffIt], *val, static_cast<std::size_t>(strLen));
m_buffIt += static_cast<std::size_t>(strLen);
fieldSet = true;
} else {
return OxError(MC_BUFFENDED);
}
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data), strLenBuff.length));
// write the string
oxReturnError(m_writer.write(*val, static_cast<std::size_t>(strLen)));
fieldSet = true;
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
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, {});
}
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, {});
}
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;
if (strLen && (m_unionIdx == -1 || m_unionIdx == m_field)) {
if (strLen && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
const auto strLenBuff = mc::encodeInteger(strLen);
if (m_buffIt + strLenBuff.length + static_cast<std::size_t>(strLen) < m_buffLen) {
ox_memcpy(&m_buff[m_buffIt], strLenBuff.data, strLenBuff.length);
m_buffIt += strLenBuff.length;
// write the string
ox_memcpy(&m_buff[m_buffIt], val, static_cast<std::size_t>(strLen));
m_buffIt += static_cast<std::size_t>(strLen);
fieldSet = true;
} else {
return OxError(MC_BUFFENDED);
}
oxReturnError(m_writer.write(reinterpret_cast<const char*>(strLenBuff.data), strLenBuff.length));
// write the string
oxReturnError(m_writer.write(val, static_cast<std::size_t>(strLen)));
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>
constexpr Error MetalClawWriter::field(const char*, T *val) noexcept {
if constexpr(isVector_v<T>) {
constexpr Error MetalClawWriter<Writer>::field(const char*, const T *val) noexcept {
if constexpr(isVector_v<T> || isArray_v<T>) {
return field(nullptr, val->data(), val->size());
} else {
bool fieldSet = false;
if (val && (m_unionIdx == -1 || m_unionIdx == m_field)) {
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
ModelHandlerInterface<MetalClawWriter> handler{&writer};
if (val && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
auto const writeIdx = m_writer.tellp();
MetalClawWriter<Writer> writer(m_writer);
ModelHandlerInterface<MetalClawWriter<Writer>> handler{&writer};
oxReturnError(model(&handler, val));
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) {
m_buffIt += writer.m_buffIt;
fieldSet = true;
}
oxReturnError(writer.finalize());
fieldSet = writeIdx != m_writer.tellp();
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field;
return OxError(0);
return {};
}
}
template<Writer_c Writer>
template<typename U, bool force>
constexpr Error MetalClawWriter::field(const char*, UnionView<U, force> val) noexcept {
constexpr Error MetalClawWriter<Writer>::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());
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()));
if (static_cast<std::size_t>(writer.m_fieldPresence.getMaxLen()) < writer.m_buffIt) {
m_buffIt += writer.m_buffIt;
fieldSet = true;
}
oxReturnError(writer.finalize());
fieldSet = writeIdx != m_writer.tellp();
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
return OxError(0);
++m_field;
return {};
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter::field(const char*, T *val, std::size_t len) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, const T *val, std::size_t len) noexcept {
bool fieldSet = false;
if (len && (m_unionIdx == -1 || m_unionIdx == m_field)) {
if (len && (!m_unionIdx.has_value() || *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);
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};
handler.setTypeInfo<T>("List", 0, {}, len);
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++) {
for (std::size_t i = 0; i < len; ++i) {
oxReturnError(handler.field("", &val[i]));
}
m_buffIt += writer.m_buffIt;
fieldSet = true;
oxReturnError(writer.finalize());
fieldSet = writeIdx != m_writer.tellp();
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
++m_field;
return OxError(0);
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter::field(const char*, const HashMap<String, T> *val) noexcept {
constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String, T> *val) noexcept {
const auto &keys = val->keys();
const auto len = keys.size();
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
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);
oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data), arrLen.length));
// write map
MetalClawWriter<Writer> writer(m_writer);
ModelHandlerInterface handler{&writer};
// double len for both key and value
handler.setTypeInfo("Map", 0, {}, len * 2);
// write the array
for (std::size_t i = 0; i < len; i++) {
const auto &key = keys[i];
const auto keyLen = ox_strlen(key);
oxReturnError(handler.setTypeInfo("Map", 0, {}, len * 2));
// this loop body needs to be in a lambda because of the potential alloca call
constexpr auto loopBody = [](auto &handler, auto const&key, auto const&val) -> ox::Error {
const auto keyLen = key.len();
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));
oxRequireM(value, val->at(key));
oxReturnError(handler.field("", value));
oxRequireM(value, val.at(key));
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;
}
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
m_field++;
++m_field;
return OxError(0);
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter::field(const char *name, HashMap<String, T> *val) noexcept {
return field(name, const_cast<const HashMap<String, T>*>(val));
constexpr ox::Error MetalClawWriter<Writer>::setTypeInfo(
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>
constexpr void MetalClawWriter::setTypeInfo(const char*, int, const Vector<String>&, int fields) noexcept {
m_fields = fields;
m_fieldPresence.setFields(fields);
m_buffIt = static_cast<std::size_t>(m_fieldPresence.getMaxLen());
ox_memset(m_buff, 0, m_buffIt);
template<Writer_c Writer>
ox::Error MetalClawWriter<Writer>::finalize() noexcept {
const auto end = m_writer.tellp();
oxReturnError(m_writer.seekp(m_writerBeginP));
oxReturnError(m_writer.write(
reinterpret_cast<const char*>(m_presenceMapBuff.data()),
m_presenceMapBuff.size()));
oxReturnError(m_writer.seekp(end));
return {};
}
constexpr std::size_t MetalClawWriter::size() const noexcept {
return m_buffIt;
Result<Buffer> writeMC(Writer_c auto &writer, const auto &val) noexcept {
MetalClawWriter mcWriter(writer);
ModelHandlerInterface handler{&mcWriter};
oxReturnError(model(&handler, &val));
oxReturnError(mcWriter.finalize());
return {};
}
Result<Buffer> writeMC(auto *val) noexcept {
Buffer buff(10 * units::MB);
MetalClawWriter writer(reinterpret_cast<uint8_t*>(buff.data()), buff.size());
ModelHandlerInterface handler{&writer};
oxReturnError(model(&handler, val));
buff.resize(writer.size());
Result<Buffer> writeMC(auto const&val, std::size_t buffReserveSz = 2 * units::KB) noexcept {
Buffer buff(buffReserveSz);
BufferWriter bw(&buff, 0);
oxReturnError(writeMC(bw, val));
buff.resize(bw.tellp());
return buff;
}
Error writeMC(char *buff, std::size_t buffLen, auto *val, std::size_t *sizeOut = nullptr) noexcept {
MetalClawWriter writer(reinterpret_cast<uint8_t*>(buff), buffLen);
ModelHandlerInterface handler(&writer);
auto err = model(&handler, val);
Error writeMC(char *buff, std::size_t buffLen, auto const&val, std::size_t *sizeOut = nullptr) noexcept {
CharBuffWriter bw(buff, buffLen);
oxReturnError(writeMC(bw, val));
if (sizeOut) {
*sizeOut = writer.size();
*sizeOut = bw.tellp();
}
return err;
return {};
}
}

View File

@ -5,6 +5,11 @@ add_library(
modelvalue.cpp
)
if(NOT MSVC)
target_compile_options(OxModel PRIVATE -Wconversion)
target_compile_options(OxModel PRIVATE -Wsign-conversion)
endif()
target_link_libraries(
OxModel PUBLIC
OxStd
@ -40,8 +45,8 @@ install(
)
install(TARGETS OxModel
LIBRARY DESTINATION lib/ox
ARCHIVE DESTINATION lib/ox
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
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
* License, v. 2.0. If a copy of the MPL was not distributed with this
@ -10,8 +10,8 @@
#include <ox/std/concepts.hpp>
#define oxModelBegin(modelName) constexpr ox::Error model(auto *io, [[maybe_unused]] 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 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

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