Compare commits

..

626 Commits

Author SHA1 Message Date
gary 10830fb412 Merge commit 'cc499028fb6b9a2138538c771d4de8fbf41a7835' as 'deps/ox'
Build / build (push) Failing after 5s
2026-05-06 01:15:12 -05:00
gary cc499028fb Squashed 'deps/ox/' content from commit d4807cd2
git-subtree-dir: deps/ox
git-subtree-split: d4807cd2a0cd64843824959c24479e1ba54459f0
2026-05-06 01:15:12 -05:00
gary 572b8b2c78 [ox] Remove Ox 2026-05-06 01:15:07 -05:00
gary 88e901e214 [keel] Cleanup
Build / build (push) Successful in 1m9s
2026-04-29 01:55:32 -05:00
gary d42e10fcbe [olympic] Cleanup pkg-gba 2026-04-29 01:52:59 -05:00
gary bc88333a59 [studio/modlib] Update ImGui drag/drop, other cleanup 2026-04-29 01:50:39 -05:00
gary 4048753205 [ox/std] Add call and logCatch for safe calling of throwing functions 2026-04-29 01:47:15 -05:00
gary 5c146c6660 [ox/std] Add call and logCatch for safe calling of throwing functions 2026-04-29 01:45:56 -05:00
gary 0885919dbd [ox/std] Cleanup 2026-04-29 01:44:43 -05:00
gary 8c7d8cd08b [ox/model] Cleanup TypeNameCatcher and TypeInfoCatcher 2026-04-29 01:42:53 -05:00
gary 110d4a2e6a [keel] Cleanup
Build / build (push) Successful in 1m16s
2026-02-07 15:29:53 -06:00
gary e29a50d0dc [ox] Rename UniquePtr to UPtr 2026-02-07 14:17:55 -06:00
gary 93d16cafb2 [ox/std] Add Error::throwException() 2026-02-07 14:15:15 -06:00
gary 54d7c706eb [studio] Make FileInfo free resources on close
Build / build (push) Successful in 1m15s
2026-02-06 21:36:39 -06:00
gary c9cb186462 [studio] Cleanup useless complexity
Build / build (push) Successful in 1m16s
2026-02-06 21:28:46 -06:00
gary f204d01a3d [studio] FileInfo: reset file info when opening
Build / build (push) Successful in 1m12s
2026-02-05 22:22:07 -06:00
gary 62337bd29e [studio] FileInfo: Rename ID to Asset ID, allow for no value of fields
Build / build (push) Successful in 1m12s
2026-02-05 22:15:00 -06:00
gary 7b24b33849 [nostalgia] Update release notes
Build / build (push) Successful in 1m11s
2026-02-05 21:40:10 -06:00
gary 86c2c26d8d [studio] Fix warning
Build / build (push) Successful in 1m11s
2026-02-05 21:35:39 -06:00
gary f8b2700ea7 [studio] Add Get Info file dialog
Build / build (push) Failing after 1m9s
2026-02-05 21:32:36 -06:00
gary 7848cbbbff [nostalgia/gfx/keel] Cleanup
Build / build (push) Successful in 1m9s
2026-02-03 02:22:58 -06:00
gary 96c5223e44 [ox/std] Fix possible false positive in HashMap::operator==
Build / build (push) Successful in 1m13s
2026-01-30 21:03:58 -06:00
gary d19b848427 [ox/std] Reduce AnyPtr to 2/3 the size
Build / build (push) Successful in 1m13s
2026-01-30 20:54:17 -06:00
gary c812051ec0 [nostalgia/gfx/studio] Cleanup
Build / build (push) Successful in 1m11s
2026-01-30 00:31:19 -06:00
gary 3c07eb2df7 [nostalgia/gfx/studio] Cleanup
Build / build (push) Successful in 1m7s
2026-01-29 19:30:32 -06:00
gary ca851e1059 [ox] Cleanup some expensive headers
Build / build (push) Successful in 1m7s
2026-01-28 22:55:26 -06:00
gary 11e75cb6ca [ox/std] Add Error::reoriginate
Build / build (push) Successful in 1m13s
2026-01-28 00:46:55 -06:00
gary 8c4add57e4 [ox/std] Fix build
Build / build (push) Successful in 1m17s
2026-01-28 00:45:26 -06:00
gary 5e1698a321 [ox/std] Cleanup serialize code
Build / build (push) Failing after 52s
2026-01-27 23:15:53 -06:00
gary 3e95bc0842 [ox/model] Update style for ModelHandlerAdaptor 2026-01-27 23:09:53 -06:00
gary 58e19fad48 [ox] Cleanup MetalClawWriter and FieldBitmapWriter 2026-01-27 23:05:03 -06:00
gary a3a56b24e8 [ox/std] Fix is_integer_v 2026-01-27 23:03:07 -06:00
gary 7681830ca6 [ox] Remove some unnecessary const_casts 2026-01-27 23:01:36 -06:00
gary 46a7331754 [ox/mc] Cleanup, fix possible overflow bug
Build / build (push) Successful in 1m8s
2026-01-26 00:55:55 -06:00
gary 56c19ad2a6 [ox/std] Add remove_pointer_t alias 2026-01-26 00:46:12 -06:00
gary c6ecadf9a8 [ox/mc] Cleanup
Build / build (push) Successful in 1m10s
2026-01-26 00:21:16 -06:00
gary 2ed469f2dd [ox] Cleanup
Build / build (push) Successful in 1m11s
2026-01-25 23:58:46 -06:00
gary 53aea9731d [ox] Cleanup
Build / build (push) Successful in 1m9s
2026-01-25 23:46:54 -06:00
gary 0e028ff653 [ox] Cleanup
Build / build (push) Successful in 1m10s
2026-01-25 22:05:49 -06:00
gary 07688a2c29 [ox] Remove oxExpect macro
Build / build (push) Successful in 1m9s
2026-01-25 21:52:26 -06:00
gary 9ce4d3f8c7 [keel,nostalgia/gfx] Minor cleanup of tests 2026-01-25 21:51:10 -06:00
gary 4aa8255c55 [ox] Update formatting in recently edited files
Build / build (push) Successful in 1m11s
2026-01-25 21:26:44 -06:00
gary bfdfc10425 [nostalgia/gfx] Update panic
Build / build (push) Successful in 1m11s
2026-01-25 21:11:54 -06:00
gary cdd574d873 [ox] Change panic and assert to use std::source_location 2026-01-25 21:11:22 -06:00
gary bc05bd12e5 [ox/model] Rename and fix isBString helpers
Build / build (push) Successful in 1m8s
2026-01-25 02:06:14 -06:00
gary b754c66cf5 [ox] Remove enable_if
Build / build (push) Successful in 1m8s
2026-01-23 01:38:53 -06:00
gary 6a42303239 [ox/std] Slight optimization 2026-01-23 01:38:31 -06:00
gary 7477ede222 [ox/std] Cleanup some enable_ifs
Build / build (push) Successful in 1m7s
2026-01-21 23:35:19 -06:00
gary 65e3153dda [ox/std] Add Union_c concept 2026-01-21 23:35:02 -06:00
gary 53a224cf8f [ox/std] Cleanup 2026-01-21 23:34:36 -06:00
gary 592e641ba9 [ox/std] Fix writeItoa to work with max length 64 bit ints
Build / build (push) Successful in 1m8s
2026-01-21 23:28:13 -06:00
gary 689da4a019 [ox] Update docs
Build / build (push) Successful in 1m10s
2026-01-21 21:04:17 -06:00
gary bdf7755ee2 [nostalgia/developer-handbook] Update developer handbook 2026-01-21 21:03:47 -06:00
gary 63f627377d [ox/std] Remove excess char from intToStr return
Build / build (push) Successful in 1m9s
2026-01-20 01:29:37 -06:00
gary ff9002ad9a [nostalgia/developer-handbook] Update error handling section
Build / build (push) Successful in 1m8s
2026-01-20 01:22:05 -06:00
gary 4d0da022cf [ox] Update error handling docs
Build / build (push) Successful in 1m8s
2026-01-20 00:47:51 -06:00
gary 02332d99b5 [ox] Fix issues in String Types section of docs
Build / build (push) Successful in 1m8s
2026-01-20 00:26:38 -06:00
gary a566ed2a8b [ox/std] Fix writeItoa to work with negatives
Build / build (push) Successful in 1m9s
2026-01-19 23:00:16 -06:00
gary 815c3d19bf [ox/std] Make StringLiteral constructors non-explicit
Build / build (push) Successful in 1m8s
2026-01-19 21:00:58 -06:00
gary 522bb14f18 [ox/std] Fix intToStr to have room for negatives 2026-01-19 21:00:12 -06:00
gary f40d5515f9 [ox] Add strings section to docs
Build / build (push) Successful in 1m11s
2026-01-18 19:00:24 -06:00
gary 941d1d90dc [ox/std] Add Vector::reserveResize
Build / build (push) Successful in 1m15s
2026-01-07 21:48:04 -06:00
gary 3e880dcdcc [nostalgia/gfx/studio] Remove unused EBO management
Build / build (push) Successful in 1m16s
2026-01-07 21:33:16 -06:00
gary 03328ac10f [turbine/glfw] Fix to handle null click handler
Build / build (push) Successful in 1m9s
2025-12-03 20:44:01 -06:00
gary 63d0abaa3c [nostalgia/gfx/gba] Remove teagba scroll bg function call
Build / build (push) Successful in 1m15s
2025-11-22 23:53:18 -06:00
gary ef2a8cda77 [teagba] Remove bg scroll, cleanup 2025-11-22 23:53:04 -06:00
gary 671fa54f6f [ox/std] Make ox::Vector::push_back comply with std::vector::push_back
Build / build (push) Successful in 1m12s
2025-09-10 23:47:36 -05:00
gary 517432679b [nostalgia/gfx/studio] Cleanup includes
Build / build (push) Successful in 1m15s
2025-09-04 22:40:58 -05:00
gary b31c01f724 [keel,studio] Cleanup 2025-09-04 22:37:01 -05:00
gary f41213f13f [ox/std] Fix channel format for oxLogError
Build / build (push) Successful in 1m8s
2025-09-04 21:11:52 -05:00
gary 28be7c4650 [ox/fs] Fix write functions to take SpanViews 2025-09-04 21:11:52 -05:00
gary 2f340b13b2 [ox/std] Fix Windows GCC build
Build / build (push) Successful in 1m15s
2025-09-04 01:21:13 -05:00
gary 312c818866 [nostalgia/gfx/studio] Remove unused variable
Build / build (push) Successful in 1m10s
2025-08-29 22:18:37 -05:00
gary 0d69d0c4a2 [ox/std] Remove oxDebug line
Build / build (push) Successful in 1m18s
2025-08-19 21:02:13 -05:00
gary 81a0b8c820 [ox/mc] Remove an oxDebug line
Build / build (push) Failing after 22s
2025-08-19 20:59:51 -05:00
gary 172b5aee90 [ox/oc] Remove an oxDebug line
Build / build (push) Failing after 17s
2025-08-19 20:58:32 -05:00
gary 2b5338a9df [nostalgia] Improve Makefile dependency handling
Build / build (push) Failing after 9s
2025-08-17 14:10:45 -05:00
gary 8a430faf4c [keel] Cleanup
Build / build (push) Successful in 1m19s
2025-08-12 22:57:13 -05:00
gary e59382dd60 [keel] Address undefined behavior 2025-08-12 22:39:08 -05:00
gary 3006e77ef3 [ox/std] Add and integrate std::launder
Build / build (push) Successful in 1m30s
2025-08-12 22:37:21 -05:00
gary 59c112a69c [studio] Fix navigate back not to iterate on the first item twice
Build / build (push) Successful in 1m55s
2025-08-09 15:15:34 -05:00
gary 31b39982c5 [keel] Fix AssetRef to call incRef on initial creation of ref, not just copy
Build / build (push) Successful in 1m18s
2025-07-31 22:06:52 -05:00
gary 5476417be2 [nostalgia] Add release notes for d2025.07.0
Build / build (push) Successful in 1m18s
2025-07-31 01:05:29 -05:00
gary e03be694c2 Merge commit 'b67b95767b7bfcd5f618ebc8e14ddbc83edcbe36'
Build / build (push) Successful in 1m37s
2025-07-31 00:41:06 -05:00
gary 490c0368bc [nostalgia/gfx] Add lists for file extensions 2025-07-31 00:39:55 -05:00
gary a24fc407c5 [ox/std] Fix MSVC build 2025-07-31 00:38:26 -05:00
gary e38b85b4f4 [studio] Eliminate redundant serialization and deserialization
Build / build (push) Successful in 1m42s
2025-07-30 21:48:44 -05:00
gary f7c3c02c4c Merge commit '1bfb7f99c215e2c74556bd3281f44962b8faaa96'
Build / build (push) Successful in 1m35s
2025-07-30 00:42:42 -05:00
gary 8f0f1fea39 [nostalgia/gfx/studio] Make editors use Project::loadObj for their primary assets 2025-07-30 00:37:59 -05:00
gary 2f36a3f6f0 [studio] Add File -> Reload Project menu item 2025-07-30 00:37:23 -05:00
gary 07e5bf9054 [keel] Make keel attempt to delete all existing assets when FS is changed 2025-07-30 00:36:56 -05:00
gary aacff3daf9 [ox/std] Fix UPtr::reset to conform to unique_ptr::reset 2025-07-30 00:29:34 -05:00
gary e27eee50f0 [teagba] Add set and scroll background offset functions
Build / build (push) Successful in 1m15s
2025-07-29 00:34:41 -05:00
gary fd610454d6 [nostalgia/gfx] Fix compiler warning
Build / build (push) Failing after 24s
2025-07-29 00:30:17 -05:00
gary e61d4647b5 [nostalgia/gfx] Fix BG tilesheet loading, add background offset functions
Build / build (push) Failing after 20s
2025-07-28 21:54:50 -05:00
gary c275c5f5e6 [hull] Disable building hull for now
Build / build (push) Successful in 1m22s
2025-07-26 18:33:24 -05:00
gary fbf49ba511 [ox/std] Add pre- and post-increment operators to Span
Build / build (push) Failing after 8s
2025-07-26 18:31:55 -05:00
gary 92f74b27d1 [ox/std] Add null check for deallocating in consteval context Vector 2025-07-26 18:31:41 -05:00
gary 934f0c9232 [ox/std] Add beginsWith and endsWith variants that that cingle chars 2025-07-26 18:31:03 -05:00
gary ee9a3e1152 [ox/std] Cleanup 2025-07-26 18:30:12 -05:00
gary 16886cdf1c [hull] Add start on command interpreter 2025-07-26 18:29:51 -05:00
gary 08b9508d83 [ox/std] Give std::ignore a named type 2025-07-26 15:09:10 -05:00
gary 69bd968f98 [nostalgia/player] Fix build
Build / build (push) Successful in 1m28s
2025-07-25 22:54:43 -05:00
gary 4e7dc66610 [nostalgia,olympic] Rename string len() functions to size() 2025-07-25 22:48:08 -05:00
gary bea0cf5a0c [ox/std] Rename string len() functions to size() 2025-07-25 22:47:56 -05:00
gary c7bc2a954f [nostalgia/gfx] Style update
Build / build (push) Successful in 1m15s
2025-07-24 21:35:21 -05:00
gary 7372036a0a [nostalgia/gfx] Add function missing from header
Build / build (push) Successful in 1m14s
2025-07-24 21:25:26 -05:00
gary 7461d832b6 [nostalgia/gfx/studio,studio] Fix CLI tool output to only show usage if no args given
Build / build (push) Successful in 1m19s
2025-07-24 21:17:58 -05:00
gary 6052798fea Merge commit 'dceeaaa9302b7e9ce85fa773fc187bc593f3c93c'
Build / build (push) Successful in 1m16s
2025-07-24 01:58:27 -05:00
gary fae1e73e54 [nostalgia/gfx] Make getSubSheet check root subsheet name
Build / build (push) Successful in 1m17s
2025-07-24 01:54:06 -05:00
gary 51f2905c9c [nostalgia/gfx/studio] Make TileSheetEditor use export-tilesheet functions for export, fix exporting Root subsheet
Build / build (push) Successful in 1m18s
2025-07-24 01:45:27 -05:00
gary 0c866d1b96 [studio,nostalgia/gfx] Add system for adding sub-commands in Modules, add export-tilesheet command
Build / build (push) Successful in 1m16s
2025-07-24 01:29:09 -05:00
gary fdf39d1a25 [ox/std] Add Result::transformError 2025-07-24 01:24:11 -05:00
gary a523a75e4b [ox/std] Add missing include to StringParam 2025-07-24 01:23:58 -05:00
gary cdaa64ed3f [ox/clargs] Fix arg parsing for first '-' 2025-07-24 01:23:31 -05:00
gary 801d35c823 [keel] Make type converters work with functions that take const src arg 2025-07-23 00:41:33 -05:00
gary 37b5fcc0f7 [teagba] Put parentheses around all registers
Build / build (push) Successful in 1m18s
2025-07-07 23:36:34 -05:00
gary f5f2c3bee6 [studio/applib] Make Studio remove files unable to be opened from open file list in config 2025-07-07 23:35:28 -05:00
gary f6ef2b5acb [turbine,nostalgia] Make memory regions cast to bounded ox::Arrays
Build / build (push) Successful in 1m16s
2025-06-29 23:32:36 -05:00
gary bf958a4a6e [teagba] Make memory regions cast to bounded ox::Arrays 2025-06-29 23:32:11 -05:00
gary 6a70e478a6 [nostalgia/gfx] Cleanup 2025-06-29 17:46:13 -05:00
gary 671b8edaad [ox/std] Make StringLiteral constructors consteval
Build / build (push) Successful in 1m29s
2025-06-27 23:05:42 -05:00
gary 952637a1ea Merge commit 'cbf4414fcaf00c00a2abf73b5c04a055180ad980'
Build / build (push) Successful in 1m37s
2025-06-25 21:33:16 -05:00
gary 7569698e95 [nostalgia,studio] Add FileExts_TileSheet const, and corresponding FilePickerPopup constructor 2025-06-25 21:30:49 -05:00
gary 21713ba945 [ox/std] Fix StringLiteral::operator= to work with DevkitARM 2025-06-25 21:29:41 -05:00
gary 73273b6fa7 [nostalgia/gfx] Add isTileSheet function for checking paths against both file extensions 2025-06-25 21:03:45 -05:00
gary 9f040392c7 [olympic,nostalgia] Cleanup style
Build / build (push) Successful in 1m18s
2025-06-24 01:59:22 -05:00
gary f4f7e5d053 Merge commit '9b5f7886cadc5c3dc826d00fa5b2e71696151dfd' 2025-06-23 20:49:01 -05:00
gary f847289bd4 [glutils] Cleanup
Build / build (push) Successful in 1m20s
2025-06-23 01:39:47 -05:00
gary 94b0020d15 [nostalgia,olympic] Cleanup
Build / build (push) Successful in 1m16s
2025-06-23 01:30:33 -05:00
gary c54c0bad38 [teagba] Cleanup
Build / build (push) Successful in 1m20s
2025-06-23 01:03:33 -05:00
gary b9ffae0269 [nostalgia/gfx] Cleanup
Build / build (push) Successful in 1m18s
2025-06-23 00:47:46 -05:00
gary 003f3e01c6 [nostalgia] Update release notes 2025-06-22 01:01:09 -05:00
gary 9028e74af0 [nostalgia/gfx/studio/tilesheet] Disable paste when nothing is selected 2025-06-22 01:00:56 -05:00
gary f5ccab5f2c [studio] Cleanup 2025-06-21 19:19:39 -05:00
gary c27726a4a9 Merge commit '6bbcae10cc7b21b73171ec0ff196f4baf6304404' 2025-06-21 14:29:47 -05:00
gary 37cfa927d1 [nostalgia/gfx] Address a couple of implicit conversions
Build / build (push) Successful in 1m19s
2025-06-21 14:16:17 -05:00
gary 0efed70b57 [studio] Fix Studio to clear editor pointers when opening a new project
Build / build (push) Successful in 1m20s
2025-06-21 14:12:45 -05:00
gary baf5fa3199 [nostalgia] Move d2025.05.2 release notes to d2025.06.0
Build / build (push) Successful in 1m19s
2025-06-21 08:54:57 -05:00
gary bd24a775b2 Merge commit '7371df429534f264c179684412f6197f7968ebfa' 2025-06-21 08:48:13 -05:00
gary 857587c18b [studio] Cleanup
Build / build (push) Successful in 1m16s
2025-06-21 08:31:27 -05:00
gary eb3d53c955 [studio] Cleanup
Build / build (push) Successful in 1m15s
2025-06-21 08:22:13 -05:00
gary 14d58f3f5b [studio] Fix Navigation shortcuts for non-Mac systems
Build / build (push) Successful in 1m18s
2025-06-21 08:13:14 -05:00
gary 5f2397903a [studio,nostalgia/gfx/studio/tilesheet] Fix copy/cut/paste enablement when there is no selection
Build / build (push) Successful in 2m2s
2025-06-21 00:20:06 -05:00
gary 58e0ecb469 [studio] Make FilePickerPopup accept on double click of a file
Build / build (push) Successful in 1m22s
2025-06-20 23:58:29 -05:00
gary 8838bf420e [studio] Fix to properly copy file that has the same name as deleted file
Build / build (push) Successful in 1m24s
2025-06-20 23:36:20 -05:00
gary bddc544d7c [nostalgia] Update release notes
Build / build (push) Successful in 1m33s
2025-06-20 22:48:39 -05:00
gary a9437191bf [studio,turbine] Add support for mouse back/forward buttons
Build / build (push) Successful in 1m30s
2025-06-20 22:44:09 -05:00
gary 9d8da7ccda [ox/std] Make strToInt return error for empty string
Build / build (push) Has been cancelled
2025-06-20 22:43:33 -05:00
gary 394b568e72 [studio] Add Back/Forward navigation
Build / build (push) Successful in 1m14s
2025-06-20 20:58:42 -05:00
gary 78e9f70db6 [nostalgia] Update release notes
Build / build (push) Successful in 1m20s
2025-06-19 23:58:42 -05:00
gary 12e5623fe6 [ox/logconn] Add exception handling for logger thread
Build / build (push) Successful in 1m18s
2025-06-19 23:56:26 -05:00
gary cfdfb0a8c9 [studio] Fix file deletion to close file even if not active 2025-06-19 23:55:47 -05:00
gary 56e665301f [studio] Cleanup
Build / build (push) Successful in 1m29s
2025-06-19 21:37:57 -05:00
gary 7415ce4bd9 [nostalgia/gfx/studio] Cleanup
Build / build (push) Successful in 2m53s
2025-06-17 20:45:24 -05:00
gary 05f42150a1 [olympic] Add new loc command to Makefile
Build / build (push) Successful in 1m19s
2025-06-09 21:29:27 -05:00
gary 8ea2bc6934 [nostalgia] Update release notes
Build / build (push) Successful in 1m16s
2025-06-09 00:22:17 -05:00
gary c780924122 [studio] Add [DEBUG] tag to About in debug builds
Build / build (push) Successful in 1m18s
2025-06-08 21:33:17 -05:00
gary 8c538560ca [nostalgia/gfx/studio/palette] Make RGB key shortcuts work when color channel inputs are focused
Build / build (push) Successful in 1m16s
2025-06-08 17:00:52 -05:00
gary c3e75bdb55 [nostalgia/gfx/studio/tilesheet] Cleanup
Build / build (push) Successful in 1m16s
2025-06-08 16:26:55 -05:00
gary 4419dff299 Merge commit '7688c05bac8c20bc267cae62ec78d55e5d0c493b' 2025-05-31 02:14:15 -05:00
gary e78c405046 [nostalgia/gfx] Cleanup
Build / build (push) Successful in 1m19s
2025-05-31 01:53:59 -05:00
gary 6b7c5d896e [nostalgia] Update release notes
Build / build (push) Successful in 1m14s
2025-05-31 01:48:07 -05:00
gary a33a73d73a [nostalgia/gfx/studio/palette] Add preview to color editor
Build / build (push) Successful in 1m16s
2025-05-31 01:34:00 -05:00
gary 536999c070 Merge commit '47eee1d56d591e3631d16e95a78ea3629ee312ee' 2025-05-30 23:38:53 -05:00
gary e1cfcc8b5f [nostalgia] Update release notes
Build / build (push) Successful in 1m13s
2025-05-30 23:37:58 -05:00
gary 514cb97835 [nostalgia/gfx/studio/tilesheet] Fix draw command to work on same pixel after switching subsheets 2025-05-30 23:32:51 -05:00
gary 4b5218c4f1 [nostalgia/gfx] Cleanup 2025-05-30 23:32:27 -05:00
gary 2ca77173d3 [keel] Add isUuidUrl function 2025-05-30 23:29:42 -05:00
gary cce5f52f96 [nostalgia/gfx/studio/tilesheet] Fix manual redo of draw actions, fix drawing to pixel 0, 0 as first action
Build / build (push) Successful in 1m15s
2025-05-29 22:12:10 -05:00
gary b55993294a [studio/modlib] Fix headerizeConfigFile to handle slashes in file name
Build / build (push) Successful in 1m12s
2025-05-25 01:20:20 -05:00
gary d8f847d707 [studio/applib] Move popup types into their own directory
Build / build (push) Successful in 1m20s
2025-05-24 15:01:17 -05:00
gary a5535ef59a Merge commit '08236fc790e711afe886b6ef545511d35e4e5c6c' 2025-05-24 01:44:07 -05:00
gary 8419b137e5 [turbine,studio] Fix some popup window resize weirdness, cleanup some function names
Build / build (push) Successful in 1m17s
2025-05-24 01:32:14 -05:00
gary ed1160ec74 [nostalgia] Update release notes
Build / build (push) Successful in 1m14s
2025-05-24 00:50:22 -05:00
gary 1e21778059 [nostalgia/gfx/studio/tilesheet] Ensure config file has a Claw header 2025-05-24 00:48:54 -05:00
gary 78379f58c8 [studio] Add ability to remember recent projects in config 2025-05-24 00:48:10 -05:00
gary 4322f720ba [keel] Fix ox::Result<DstType> convert(Context &ctx, ox::BufferView const&src) 2025-05-24 00:47:39 -05:00
gary 26f1a6051f [ox/std] Make Vector::remove take a MaybeView_t
Build / build (push) Successful in 1m17s
2025-05-24 00:46:39 -05:00
gary c4c1d4777b [keel] Cleanup ox::Error(0) instance 2025-05-23 20:25:08 -05:00
gary fab012d3e7 [ox] Cleanup all ox::Error(0) instances 2025-05-23 20:24:58 -05:00
gary a90380f377 Merge commit 'e90dd887477452922f783535edb3d4c55e9a0d2c' 2025-05-23 03:23:17 -05:00
gary 312097a799 [ox/std] Fix implementation of std cmp functions
Build / build (push) Successful in 1m12s
2025-05-23 03:22:27 -05:00
gary a40198ab8d [nostalgia] Update release-d2025.05.2 release notes
Build / build (push) Successful in 1m23s
2025-05-22 20:45:34 -05:00
gary 52d8c0bdc8 [nostalgia/gfx] Replace static_cast compare with std::cmp_equal 2025-05-22 20:43:27 -05:00
gary c19d7f4ea3 [nostalgia] Add .vs and cmake-build-* to .gitignore 2025-05-22 20:42:09 -05:00
gary 159b7e7ee7 [buildcore] Make pybb cmake_build specify --config debug/release 2025-05-22 20:41:30 -05:00
gary c93eec4f05 [teagba] Make cstart.cpp only compile if GCC 2025-05-22 20:40:33 -05:00
gary e7e7a22390 [nostalgia/sample_project] Make sample_project exempt from autocrlf 2025-05-22 20:39:56 -05:00
gary 26d5048e67 [ox/fs] Fix new build error in MSVC (VS 17.14) 2025-05-22 20:05:09 -05:00
gary 3b8f97cc41 [nostalgia/gfx] Cleanup
Build / build (push) Successful in 1m15s
2025-05-21 22:15:56 -05:00
gary f1e68e0a04 [nostalgia/gfx/studio/tilesheet] Fix overrun errors when switching subsheets, clear selection on switch 2025-05-21 22:15:07 -05:00
gary d6e4ab7a24 [keel] Cleanup
Build / build (push) Successful in 1m24s
2025-05-18 14:08:39 -05:00
gary 2000b2deee [nostalgia/gfx/studio] Cleanup 2025-05-17 23:35:10 -05:00
gary 7d92400f6d [nostalgia/gfx/studio] Add type specific navigateTo functions 2025-05-17 23:26:23 -05:00
gary cb304ecf28 [applib] Cleanup
Build / build (push) Successful in 1m12s
2025-05-17 17:46:38 -05:00
gary ea17377700 [ox/std] Make StringViewCR honest
Build / build (push) Successful in 1m17s
2025-05-17 17:34:22 -05:00
gary c424bde06d [nostalgia] Style cleanup
Build / build (push) Successful in 1m14s
2025-05-17 17:31:47 -05:00
gary ee7d5c6d51 [nostalgia/gfx] Cleanup
Build / build (push) Successful in 1m14s
2025-05-17 17:22:13 -05:00
gary 99247cee32 [nostalgia/gfx/test] Cleanup
Build / build (push) Successful in 1m15s
2025-05-17 17:18:51 -05:00
gary 7b8ddc189a [nostalgia/gfx] Consolidate implementations into single files, remove unnecessary function exports
Build / build (push) Successful in 1m17s
2025-05-17 17:13:13 -05:00
gary a6814030ee [studio/applib] Cleanup
Build / build (push) Successful in 1m13s
2025-05-17 16:15:32 -05:00
gary 9937a01042 [turbine] Cleanup 2025-05-17 16:12:16 -05:00
gary abcf2adc56 [nostalgia/gfx] Cleanup
Build / build (push) Successful in 1m14s
2025-05-17 03:02:59 -05:00
gary 05f9023550 [nostalgia/gfx] Cleanup
Build / build (push) Successful in 1m14s
2025-05-17 02:51:56 -05:00
gary 5ba0bcf963 [turbine] Consolidate some files that didn't have sensible distinctions
Build / build (push) Has been cancelled
2025-05-17 02:51:23 -05:00
gary 3ccadba2f5 [nostalgia/gfx/studio/tilesheet] Fix dragging cursor on image
Build / build (push) Successful in 1m20s
2025-05-16 21:22:33 -05:00
gary 00e52b6491 [nostalgia] Make pkg-dmg more versatile
Build / build (push) Successful in 1m14s
2025-05-15 22:26:35 -05:00
gary ae40487990 [nostalgia/gfx] Add navigateTo handler to TileSheetEditor
Build / build (push) Successful in 1m20s
2025-05-15 20:39:50 -05:00
gary 84b612c693 [studio/modlib] Give navigateTo a default argument 2025-05-15 20:39:01 -05:00
gary 3c2a6b047e [studio/applib] Make navigateTo handle UUID paths 2025-05-15 20:38:27 -05:00
gary 626da322d9 [ox/std] Add StringParam(IString const&) constructor 2025-05-15 20:37:44 -05:00
gary 0de428a2e5 [studio/applib] Cleanup
Build / build (push) Successful in 1m19s
2025-05-14 22:11:43 -05:00
gary 8a52df4f76 [nostalgia/gfx] More cleanup
Build / build (push) Successful in 1m16s
2025-05-14 01:43:59 -05:00
gary efec6eb3c8 [nostalgia/gfx/studio/palette] Add RGB key shortcuts for focusing color channels
Build / build (push) Successful in 1m15s
2025-05-14 01:13:40 -05:00
gary 56eeb24900 [nostalgia/gfx/opengl] More cleanup
Build / build (push) Successful in 1m56s
2025-05-13 22:06:08 -05:00
gary ae81f6b3de [ox/std] Make Span::operator[] const
Build / build (push) Successful in 1m17s
2025-05-13 22:02:23 -05:00
gary c1108301c0 [nostalgia/gfx] Cleanup 2025-05-13 22:01:59 -05:00
gary 83fbe6ac74 [keel,turbine,studio] Fix some install mistakes
Build / build (push) Successful in 2m17s
2025-05-13 21:39:37 -05:00
gary 80b452833f [nostalgia/gfx] Cleanup
Build / build (push) Successful in 2m28s
2025-05-13 21:24:04 -05:00
gary 0fa394333b [nostalgia] Add release note about Mac menubar using Cmd
Build / build (push) Successful in 1m15s
2025-05-10 01:01:11 -05:00
gary cae7535034 [nostalgia] Fix typos in release notes
Build / build (push) Successful in 1m15s
2025-05-10 00:57:45 -05:00
gary df87832324 [studio] Add build date to About
Build / build (push) Successful in 1m15s
2025-05-10 00:21:54 -05:00
gary d585794cbe [nostalgia/gfx/studio/tilesheet] Fix Insert tile command 2025-05-09 20:34:42 -05:00
gary 209658549c [nostalgia/gfx/studio/tilesheet] Cleanup 2025-05-09 20:34:04 -05:00
gary 02383a4aed [ox/std] Cleanup 2025-05-09 01:22:29 -05:00
gary 185a76282a [nostalgia] Make pkg-dmg delete bundle after archive created
Build / build (push) Successful in 1m15s
2025-05-08 23:29:36 -05:00
gary b722b4f701 [nostalgia] Update release notes
Build / build (push) Has been cancelled
2025-05-08 23:28:58 -05:00
gary 459ab5aad9 [studio] Remove ability to re-order Editor tabs 2025-05-08 23:28:51 -05:00
gary 565f621cfc [nostalgia/gfx/studio/tilesheet] Fix Delete Tile functionality
Build / build (push) Successful in 1m15s
2025-05-08 01:57:59 -05:00
gary 9589ca9148 [keel] Cleanup 2025-05-08 01:37:18 -05:00
gary 164db5007b [keel] Cleanup
Build / build (push) Successful in 1m25s
2025-05-08 00:49:50 -05:00
gary cbfb167d29 [nostalgia] Remove unused project directory
Build / build (push) Successful in 1m33s
2025-05-07 20:23:48 -05:00
gary e7b83be867 [nostalgia] Update release notes
Build / build (push) Successful in 2m28s
2025-05-07 20:18:08 -05:00
gary 649da5fca8 [nostalgia/sample_project] Delete Scenes directory 2025-05-07 20:16:35 -05:00
gary aa095f7680 [studio] Make Delete key initiate deletion of selected directory 2025-05-07 20:15:38 -05:00
gary bb99c99f01 [studio] Make deleting a directory close files in that directory 2025-05-07 20:10:34 -05:00
gary 7f0dcdd280 [nostalgia/gfx/studio/tilesheet] Cleanup
Build / build (push) Successful in 1m20s
2025-05-07 19:57:27 -05:00
gary 6029ad5d47 [nostalgia/studio] Add command for bundling Mac app 2025-05-07 02:48:14 -05:00
gary 26fe266b09 [ox/mc] Fix break from using strnlen_s inappropriately
Build / build (push) Successful in 1m16s
2025-05-07 01:18:14 -05:00
gary 091eda7b44 Merge commit 'ce53be92716b0f5201882d6959c398b61c6cc93c'
Build / build (push) Successful in 1m23s
2025-05-07 00:12:52 -05:00
gary 9676ea5978 [turbine/glfw] Fix programmatic shutdown to invoke shutdownHandler
Build / build (push) Successful in 1m50s
2025-05-07 00:06:21 -05:00
gary de8ac10653 [turbine/glfw] Fix closing when no shutdown handler is set
Build / build (push) Successful in 1m53s
2025-05-07 00:01:49 -05:00
gary 88a6cd59f3 [turbine/glfw] Treat close window event like other events with regard to a mandatory refresh period
Build / build (push) Waiting to run
2025-05-06 23:56:49 -05:00
gary cd43fb7f38 [turbine,studio] Fix confirm app close pop up to work with Ctrl-Q
Build / build (push) Successful in 2m1s
2025-05-06 23:25:00 -05:00
gary 136f422401 [nostalgia] Update release notes
Build / build (push) Successful in 1m16s
2025-05-06 23:11:06 -05:00
gary e773d6f0ee [studio] Rename StudioContext to Context
Build / build (push) Successful in 1m16s
2025-05-06 22:37:21 -05:00
gary 7da2f68d30 [nostalgia/sample_project] Add assets
Build / build (push) Successful in 1m22s
2025-05-06 22:30:28 -05:00
gary d20889aef1 [nostalgia/gfx/studio] Update for Ox changes 2025-05-06 22:29:51 -05:00
gary 50c8302f4a [ox] Rename itoa to intToStr 2025-05-06 22:29:31 -05:00
gary d8195d300d [olympic,nostalgia] Address unsafe buffer warnings 2025-05-06 22:25:36 -05:00
gary a8c1387d5a [ox] Address unsafe buffer warnings 2025-05-06 22:25:13 -05:00
gary ff1e8f260b [studio] Add popup to warn about UUID duplication 2025-05-06 22:22:26 -05:00
gary d4329981e7 [studio,nostalgia] Cleanup
Build / build (push) Successful in 1m14s
2025-05-06 01:11:47 -05:00
gary 0003454311 [studio,nostalgia/gfx/studio] Cleanup
Build / build (push) Successful in 1m14s
2025-05-06 01:00:04 -05:00
gary 8c6b2234ec [olympic/util] Make pkg-gba script check return code of subprocesses
Build / build (push) Successful in 1m14s
2025-05-05 23:11:37 -05:00
gary aad4b8a44c [studio] Cleanup 2025-05-05 23:10:18 -05:00
gary 7cab133127 [keel] Add ability to log UUID duplication
Build / build (push) Successful in 1m14s
2025-05-05 21:54:24 -05:00
gary 640ac85de4 [nostalgia/gfx/studio/palette] Make page rename dialog accept on enter if input focused
Build / build (push) Successful in 1m19s
2025-05-04 00:15:30 -05:00
gary b8d7658626 [nostalgia/studio] Update generated icondata.cpp with Clang fix
Build / build (push) Successful in 1m26s
2025-05-02 21:05:21 -05:00
gary 2503bb3b2c [nostalgia/sample_project] Update type descriptors 2025-05-02 21:04:36 -05:00
gary e5dd448fe7 [turbine,studio] Make Studio confirm with user before closing app if any unsaved changes
Build / build (push) Successful in 1m15s
2025-05-01 23:15:06 -05:00
gary 4770bb6a93 [olympic/util] Cleanup
Build / build (push) Successful in 1m17s
2025-04-20 21:44:36 -05:00
gary c0bac696dc [nostalgia/gfx/studio/paletteeditor] Fix color number key range
Build / build (push) Successful in 1m16s
2025-04-19 14:43:07 -05:00
gary 95f7c33419 [studio] Change Studio font
Build / build (push) Successful in 1m16s
2025-04-19 00:23:36 -05:00
gary 535d8876d3 [keel] Cleanup 2025-04-19 00:22:28 -05:00
gary 845e433221 [turbine] Fix Mac build 2025-04-18 01:38:32 -05:00
gary 5169a607cf [turbine] Disable useless window icon on Mac, it causes GLFW warning
Build / build (push) Successful in 1m16s
2025-04-17 21:36:56 -05:00
gary 8f03af99a7 [keel] Style updates 2025-04-17 21:36:24 -05:00
gary ee63a4a1e4 [keel] Cleanup
Build / build (push) Successful in 1m17s
2025-04-17 21:04:43 -05:00
gary ac29f7a0f2 Merge commit 'ec6cf92c4763be5933ee6debbf97bce25b9fcfc9' 2025-04-17 20:12:48 -05:00
gary 89ae226b1d [keel] Improve correctness
Build / build (push) Successful in 1m18s
2025-04-17 01:17:40 -05:00
gary 477834ac04 [keel] Cleanup
Build / build (push) Successful in 1m16s
2025-04-17 01:06:08 -05:00
gary 97b707b61c [keel] Fix MSVC build
Build / build (push) Successful in 1m16s
2025-04-17 01:01:22 -05:00
gary e86180e842 [nostalgia/core/keel] Consistency cleanup
Build / build (push) Successful in 1m16s
2025-04-17 00:39:34 -05:00
gary 035ba8810f [keel,nostalgia] Fix converter type names 2025-04-17 00:37:05 -05:00
gary f1c2113dd3 [keel] Fix some completely incomprehensible build break in GCC12...
Build / build (push) Successful in 1m16s
2025-04-17 00:32:38 -05:00
gary 56b79f414d [keel,nostalgia] Further simplify writing type converters
Build / build (push) Failing after 14s
2025-04-17 00:22:47 -05:00
gary 844656d557 [nostalgia/gfx/keel] Update type converter style
Build / build (push) Successful in 1m14s
2025-04-16 23:12:24 -05:00
gary 849aceb86d [keel] Add cleaner way to write type converters 2025-04-16 23:11:47 -05:00
gary eef51a6d2b [olympic] Improve error handling in file-to-cpp 2025-04-16 20:11:28 -05:00
gary c84b85102c [nostalgia/gfx/studio] Cleanup
Build / build (push) Successful in 1m15s
2025-04-15 22:05:46 -05:00
gary 3fe62464c3 [nostalgia/sample_project] Add NS_Logo32
Build / build (push) Successful in 1m18s
2025-04-14 22:20:06 -05:00
gary db55fc722f [nostalgia/player] Cleanup 2025-04-14 22:05:23 -05:00
gary 2094450898 [studio] Cleanup
Build / build (push) Successful in 1m22s
2025-04-14 22:00:05 -05:00
gary 889bec04b1 [nostalgia/gfx/studio/tilesheet] Cleanup 2025-04-13 23:20:49 -05:00
gary ac1e34d4cd [nostalgia] Update release notes
Build / build (push) Successful in 1m19s
2025-04-13 00:37:32 -05:00
gary 55ed75f44d [nostalgia/gfx/studio/tilesheet] Fix selection clearing to work when clicking outside image
Build / build (push) Successful in 1m19s
2025-04-13 00:33:06 -05:00
gary 2751872c59 [nostalgia] Cleanup file-to-cpp output
Build / build (push) Successful in 1m15s
2025-04-12 16:50:09 -05:00
gary 2a3cd35cc4 [nostalgia] Fix release notes version, add d2025.02.1
Build / build (push) Waiting to run
2025-04-12 16:45:58 -05:00
gary b66f459f75 [nostalgia] Cleanup icon rsrc generation
Build / build (push) Waiting to run
2025-04-12 16:40:49 -05:00
gary 3910f4e77c [nostalgia] Fix debug and gba-run commands in Makefile
Build / build (push) Waiting to run
2025-04-12 14:04:41 -05:00
gary c0e96216ae [turbine] Make accessor functions take const ref to Context
Build / build (push) Waiting to run
2025-04-12 13:49:43 -05:00
gary f9512d72e8 [turbine/glfw] Fix implicit conversion
Build / build (push) Waiting to run
2025-04-12 00:22:49 -05:00
gary b7f2c169ec [nostalgia/studio/gfx] Fix typo
Build / build (push) Waiting to run
2025-04-11 23:14:57 -05:00
gary 1e5057d6e6 [nostalgia] Add app icon note to release notes
Build / build (push) Waiting to run
2025-04-11 23:12:36 -05:00
gary c6255e3224 [nostalgia/studio] Add icon 16 src
Build / build (push) Waiting to run
2025-04-11 23:06:42 -05:00
gary 02230ef619 [turbine,studio,nostalgia/studio] Add support for window icon scaling, expand icons sizes for Nostalgia Studio
Build / build (push) Waiting to run
2025-04-11 22:45:11 -05:00
gary 9b6b60e4d1 [turbine] Cleanup
Build / build (push) Waiting to run
2025-04-11 21:47:26 -05:00
gary b9a26ab61e [turbine] Fix GLFWimage member init order
Build / build (push) Waiting to run
2025-04-11 21:44:52 -05:00
gary a521887ddd [studio,turbine] Add support for window icons
Build / build (push) Waiting to run
2025-04-11 21:41:30 -05:00
gary 5ca7e2f226 [ox/fs] Cleanup
Build / build (push) Successful in 1m14s
2025-04-02 01:30:58 -05:00
gary 125a235dd1 [ox/fs] Cleanup
Build / build (push) Successful in 1m26s
2025-04-02 01:29:02 -05:00
gary 91a7129f8f [nostalgia/gfx/keel] Cleanup 2025-04-02 01:07:26 -05:00
gary df48a232ec [nostalgia/studio] Add icon to Windows executable
Build / build (push) Successful in 1m28s
2025-04-02 00:49:13 -05:00
gary ab11b885e6 [keel] Add missing new line to log message
Build / build (push) Successful in 1m25s
2025-03-24 21:02:20 -05:00
gary 36fc25fb7e [studio] Fix closing tab with unsaved changes 2025-03-24 21:02:20 -05:00
gary 4803cca334 [nostalgia/player] Cleanup
Build / build (push) Successful in 1m29s
2025-03-08 22:28:29 -06:00
gary 6bd74611cd [nostalgia] Update release notes
Build / build (push) Successful in 1m28s
2025-02-25 20:02:52 -06:00
gary c3f9cf9a64 [studio] Fix New Project opening project, disable New if no project open
Build / build (push) Has been cancelled
2025-02-25 20:01:33 -06:00
gary 646ab1283f [nostalgia/gfx] Cleanup
Build / build (push) Successful in 1m26s
2025-02-24 21:45:45 -06:00
gary 74cf055610 [nostalgia] Cleanup
Build / build (push) Successful in 1m32s
2025-02-24 19:43:10 -06:00
gary 0d8ba1b154 [nostalgia/gfx] Cleanup formatting mistake
Build / build (push) Successful in 1m26s
2025-02-23 23:21:59 -06:00
gary 20edbb7f38 [buildcore] Map aarch64 to arm64
Build / build (push) Successful in 1m27s
2025-02-23 01:00:12 -06:00
gary 6febc7cc73 [nostalgia] Fix build
Build / build (push) Successful in 1m32s
2025-02-23 00:51:30 -06:00
gary b94d6b5061 [nostalgia] Remove scene package, finish stubbing out sound
Build / build (push) Failing after 21s
2025-02-23 00:49:58 -06:00
gary b3952cabbc [nostalgia] Add build upload step to CI
Build / build (push) Successful in 1m39s
2025-02-22 21:30:35 -06:00
gary 2ffc11b04e Merge commit 'e723ead864edb4bc160e4d69713309174ad9e82e'
Build / build (push) Successful in 1m34s
2025-02-22 20:55:17 -06:00
gary 96cace2cbb [studio] Cleanup 2025-02-22 19:51:55 -06:00
gary 472f5702bd [nostalgia/gfx/studio/tilesheet] Change max export scale to 135
Build / build (push) Successful in 1m32s
2025-02-22 15:31:39 -06:00
gary c0ac4345d3 [studio] Cleanup
Build / build (push) Successful in 1m30s
2025-02-22 15:16:26 -06:00
gary fbebf4ef83 [nostalgia/gfx/studio/tilesheet] Fix export for 4bpp images
Build / build (push) Successful in 1m27s
2025-02-22 00:58:12 -06:00
gary 20513f7749 [nostalgia/sample_project] Add type descriptors 2025-02-21 00:41:04 -06:00
gary 25a7873ea2 [nostalgia,studio] Fix crash that occurred when navigating to file that is not already open
Build / build (push) Successful in 1m32s
2025-02-20 23:57:02 -06:00
gary d0a32e247e [ox/std] Add Vector::remove
Build / build (push) Successful in 1m42s
2025-02-20 23:34:36 -06:00
gary 03d4a5736e [nostalgia,studio] Add ability to navigate from tile sheet to palette color
Build / build (push) Successful in 1m52s
2025-02-20 23:30:50 -06:00
gary a2e41e6527 Merge commit '4e94c925686cdda4b1ac777045dd7a17c7dc0329'
Build / build (push) Successful in 1m38s
2025-02-20 20:11:03 -06:00
gary 40a7caff90 [ox/std] Make bounds checking its own option enable-able in release builds 2025-02-20 20:05:07 -06:00
gary 26fc5565e8 [nostalgia/gfx] Make dangling reference warning suppressions check for GCC 13
Build / build (push) Successful in 1m30s
2025-02-20 19:40:08 -06:00
gary 388541ce32 [nostalgia/player] Cleanup
Build / build (push) Successful in 1m24s
2025-02-20 00:01:29 -06:00
gary 6c194667b9 [nostalgia] Fix NostalgiaGfx lib name, stub out sound package
Build / build (push) Successful in 1m27s
2025-02-19 22:19:16 -06:00
gary 62d0579f40 [ox/fs] Restructure stat error handling to make easier to debug
Build / build (push) Successful in 1m25s
2025-02-19 21:47:47 -06:00
gary 202595b2a6 [keel] Fix loading assets by path 2025-02-19 21:47:00 -06:00
gary cb21ff3f04 Merge commit 'a6b9657268eb3fe139b0c22df27c2cb2efc0013c' 2025-02-19 00:34:26 -06:00
gary 2a8e3c2dc4 [nostalgia/gfx] Remove unnecessary cast
Build / build (push) Successful in 1m26s
2025-02-18 23:01:15 -06:00
gary 998066d377 [ox/std] Add comparison functions
Build / build (push) Successful in 1m24s
2025-02-18 21:46:41 -06:00
gary fefb876fe7 [nostalgia/gfx] Add checks for GCC version for warning suppression
Build / build (push) Successful in 1m24s
2025-02-18 20:33:29 -06:00
gary 5979e9885e [jsoncpp] Up required CMake version 2025-02-18 20:26:47 -06:00
gary a17abe4639 [nfde] Up required CMake version 2025-02-18 20:26:47 -06:00
gary d62f913855 [nostalgia/gfx] Suppress some superfluous warnings
Build / build (push) Failing after 1m9s
2025-02-18 20:22:56 -06:00
gary 12bb7475fc [nostalgia/gfx/studio/tilesheet] Adjust pixel line size on Windows
Build / build (push) Successful in 1m25s
2025-02-18 20:19:51 -06:00
gary df2c7e2b67 [nostalgia] Update release notes
Build / build (push) Successful in 1m26s
2025-02-08 18:10:49 -06:00
gary 713aec887b [buildcore] Change mypy invokation
Build / build (push) Successful in 1m28s
2025-02-07 20:38:44 -06:00
gary 3089cd7afc Change builder type to olympic
Build / build (push) Has been cancelled
2025-02-07 20:34:22 -06:00
gary 00638bc812 [nostalgia/gfx/studio/tilesheet] Mark DrawCommands as obsolete if no changes
Build / build (push) Successful in 3m37s
2025-02-05 20:26:47 -06:00
gary e002109829 [studio] Make undo/redo skip over obsolete commands 2025-02-05 20:26:03 -06:00
gary b4798fd2ab [nostalgia/gfx/studio/tilesheet] Make rotate only available for square subsheets or selections
Build / build (push) Successful in 3m39s
2025-02-05 01:54:41 -06:00
gary 3c804bf62a [studio] Give MakeCopy popup an error message for files that already exist
Build / build (push) Successful in 3m36s
2025-02-03 23:30:07 -06:00
gary d39d552bd9 [nostalgia/studio] Update icon to higher resolution 2025-02-03 23:29:26 -06:00
gary b7202a2b0d [nostalgia/player] Disable Keel mods on GBA
Build / build (push) Successful in 3m34s
2025-02-03 22:48:07 -06:00
gary 4e27a4c1f5 [nostalgia/core/studio/tilesheet] Fix palette path display update
Build / build (push) Successful in 3m37s
2025-02-03 22:43:20 -06:00
gary 4ef31762d0 [nostalgia/core/studio/tilesheet] Cleanup 2025-02-03 22:43:02 -06:00
gary 8b22a8f339 [keel] Make buildUuidMap only read the first 40 bytes of each file 2025-02-03 20:29:06 -06:00
gary d45ff05bcd [ox/fs] Add new partial file read functions 2025-02-03 20:28:25 -06:00
gary 671dd86206 [keel,studio] Add Make Copy option to ProjectExplorer
Build / build (push) Successful in 3m46s
2025-02-03 02:01:40 -06:00
gary 0abadc1850 [studio] Fix QuestionPopup to only emit a response when there is a response
Build / build (push) Successful in 3m36s
2025-02-03 00:35:37 -06:00
gary 4e068d628c [studio] Fix misrender flash on tab close 2025-02-03 00:19:14 -06:00
gary 4461f99fa4 [studio] Add Ctrl-W shortcut for closing active tab
Build / build (push) Successful in 3m36s
2025-02-02 23:13:15 -06:00
gary cd1f4bdaa3 [studio] Add confirmation for closing file with unsaved changes 2025-02-02 23:07:59 -06:00
gary 4728699585 [studio] Add combobox that will take string views
Build / build (push) Successful in 3m47s
2025-02-02 20:46:08 -06:00
gary 105a1e5559 [nostalgia/core/studio/tilesheet] Rework operation ctrls into a dropbox
Build / build (push) Failing after 1m1s
2025-02-02 20:43:01 -06:00
gary 1bc18e34a8 [nostalgia/core/studio/tilesheet] Add ability to rotate a selection 2025-02-02 20:22:20 -06:00
gary fb8d295fcb [nostalgia/core/studio/tilesheet] Add rotate functionality 2025-02-02 14:46:21 -06:00
gary 8459d3baea Merge commit 'c42adc290cd8a27d01bb6d9877032dd2c963a4b7' 2025-02-01 22:55:46 -06:00
gary 804d78e116 [nostalgia/gfx/studio] Cleanup
Build / build (push) Successful in 3m32s
2025-02-01 15:14:24 -06:00
gary 5351e9aa0a [nostalgia/core/studio/tilesheet] Add line drawing tool
Build / build (push) Successful in 3m36s
2025-02-01 14:14:09 -06:00
gary b5954f15c5 [studio] Restore context menu for root dir, but exclude Delete
Build / build (push) Successful in 3m33s
2025-01-29 18:47:48 -06:00
gary 5dce9dd377 [studio] Suppress context menu for root dir in ProjectExplorer
Build / build (push) Successful in 3m32s
2025-01-28 01:27:51 -06:00
gary 0570f76236 [ox/fs] Fix PassThroughFS::stripSlash
Build / build (push) Successful in 3m32s
2025-01-28 01:18:44 -06:00
gary e22b658a67 [studio] Fix isParentOf check in Project to ensure child dir path ends with /
Build / build (push) Has been cancelled
2025-01-28 01:04:17 -06:00
gary 56b9cb6ebf [studio] Fix file explorer to treat empty directories as directories
Build / build (push) Successful in 3m32s
2025-01-27 23:31:58 -06:00
gary eaa9a2415e [keel] Make reloadAsset check if file is loaded 2025-01-27 21:59:57 -06:00
gary 95256a9a0d [studio] Make rename file give error message if the file already exists
Build / build (push) Successful in 3m32s
2025-01-27 00:54:58 -06:00
gary 2286238abc [studio] Make rename file accept input upon pressing Enter if text input is focused
Build / build (push) Successful in 3m36s
2025-01-27 00:33:14 -06:00
gary 13f0bf57e4 [studio] Make deleting a file close tabs associated with it 2025-01-27 00:30:27 -06:00
gary 8eb1ac215b [studio] Fix not to try moving a parent directory to its child
Build / build (push) Successful in 3m34s
2025-01-27 00:10:25 -06:00
gary e132f2fd1b [studio] Make file move do nothing if the file already exists 2025-01-26 23:59:13 -06:00
gary 12f6b22c8b [nostalgia/gfx/studio/palette] Cleanup 2025-01-26 23:35:03 -06:00
gary 6c858e0c4e [nostalgia/gfx/studio/tilesheet] UI cleanup
Build / build (push) Successful in 3m35s
2025-01-26 22:30:39 -06:00
gary c6b58f7c63 [nostalgia] Update release notes
Build / build (push) Successful in 3m35s
2025-01-26 22:16:04 -06:00
gary a22aafaf96 [nostalgia/gfx/studio/palette] Add ability to reorder Palette pages 2025-01-26 22:12:57 -06:00
gary 6298ac3a21 [nostalgia] Update release notes
Build / build (push) Successful in 3m28s
2025-01-26 20:58:22 -06:00
gary cd63afacfe [studio] Remove Ctrl-0 tab shortcut 2025-01-26 20:53:47 -06:00
gary 2859183742 [nostalgia/gfx/studio/tilesheet] Add the ability to move subsheets 2025-01-26 20:46:15 -06:00
gary 8d04af691e Merge commit 'ab760b064fd6a302bad13274e0e02b2b2c957b67' 2025-01-26 15:42:50 -06:00
gary 055165974e [nostalgia/sample_project] Update test assets 2025-01-26 15:41:40 -06:00
gary be51838775 [nostalgia/gfx/studio/tilesheet] Add flip x and flip y functionality
Build / build (push) Successful in 3m33s
2025-01-26 15:41:13 -06:00
gary 1207dadee8 [studio] Add ability to move directories
Build / build (push) Successful in 3m29s
2025-01-26 09:38:27 -06:00
gary 109e1898cc [studio] Add ability to drag files between directories
Build / build (push) Successful in 3m29s
2025-01-26 02:03:54 -06:00
gary a24bf7ffb9 [studio] Fix config to update when open file name changes 2025-01-26 01:01:48 -06:00
gary 046834c2b9 [studio,nostalgia] Update tab name when corresponding file's name changes
Build / build (push) Successful in 3m30s
2025-01-26 00:52:11 -06:00
gary f840240aac [nostalgia/gfx/studio/tilesheeteditor] Rework system for tracking current palette path
Build / build (push) Successful in 3m29s
2025-01-25 22:59:51 -06:00
gary cfa91d3d39 [keel,studio] Add ability to rename files 2025-01-25 22:59:01 -06:00
gary f7a7a66a6a [ox/event] Add Signal::connectionCnt 2025-01-25 22:58:18 -06:00
gary 5145595d57 [ox/std] Fix HashMap collision handling 2025-01-25 22:16:42 -06:00
gary f01d303381 [ox/std] Fix UPtr compare with nullptr 2025-01-25 20:13:47 -06:00
gary 098c8cb844 [nostalgia/gfx/studio] Make move color commands affect all pages
Build / build (push) Successful in 3m25s
2025-01-24 23:46:26 -06:00
gary 04ad0f0264 [studio] Add drag/drop functions that use model TypeName for name
Build / build (push) Successful in 3m23s
2025-01-24 23:26:30 -06:00
gary 695e7a4561 [nostalgia/gfx/studio/paletteeditor] Change move color mechanism to use drag/drop
Build / build (push) Failing after 54s
2025-01-24 23:19:45 -06:00
gary 7d53028faf [studio] Cleanup 2025-01-24 00:21:28 -06:00
gary 6c34198f58 Merge commit '897a59cdad66e593fd45eece9414d8414fa7f1ae' 2025-01-23 23:51:13 -06:00
gary 7e3e046109 [ox/model] Fix possible infinite recursion
Build / build (push) Successful in 3m26s
2025-01-23 23:48:40 -06:00
gary f63c58169f [studio] Add filepickerpopup.hpp to studio.hpp 2025-01-23 22:19:59 -06:00
gary e40b11246d [nostalgia/gfx/studio/paletteeditor] Fix num key shortcuts to ignore if ctrl is down
Build / build (push) Successful in 3m25s
2025-01-23 21:56:47 -06:00
gary 161194c8b2 [nostalgia/gfx/studio/tilesheeteditor] Add FilePicker to for choosing a Palette
Build / build (push) Successful in 3m25s
2025-01-23 21:24:10 -06:00
gary 48603ea2c5 [studio] Make tabs not draw while closing 2025-01-23 21:24:10 -06:00
gary e2f2a17315 [studio] Add FilePickerPopup 2025-01-23 21:24:10 -06:00
gary e8a0ce88c5 Merge commit 'dff9f81e073bb994d5ce96a6eaa1bfa547f1fdf4'
Build / build (push) Waiting to run
2025-01-23 21:21:58 -06:00
gary 82e2ea747f [studio] Fix NewMenu to track prev stage correctly when going back two stages 2025-01-23 21:13:58 -06:00
gary ff666eda9b [studio] Make NewMenu default Name field to focus when it appears
Build / build (push) Successful in 3m30s
2025-01-23 00:55:10 -06:00
gary 0d8b82ba49 [studio] Cleanup
Build / build (push) Successful in 3m10s
2025-01-23 00:32:03 -06:00
gary 5598dfdd87 [nostalgia/player] Update hardcoded tilesheet refs to new file ext
Build / build (push) Successful in 3m16s
2025-01-23 00:19:35 -06:00
gary 6ef462adcc [keel] Add clearer Error handling 2025-01-23 00:15:55 -06:00
gary 9511cb5719 [studio] Fix prev tracking
Build / build (push) Successful in 3m16s
2025-01-22 23:37:44 -06:00
gary 1cc1d561e2 [studio] Add a file explorer to NewMenu to choose where new files go
Build / build (push) Successful in 4m16s
2025-01-22 23:11:08 -06:00
gary d15a0df7da [studio] Make reusable FileTreeModel 2025-01-22 01:04:25 -06:00
gary e1282b6bae [studio] Fix build
Build / build (push) Successful in 3m23s
2025-01-22 00:58:43 -06:00
gary 5fe7c14ccb [nostalgia/sample_project] Rename TileSheet files using new file ext
Build / build (push) Failing after 52s
2025-01-21 23:40:19 -06:00
gary 42165ba2d6 [nostalgia/gfx] Change default file extension for TileSheets to nts 2025-01-21 23:35:55 -06:00
gary 1af4da43ad [nostalgia] Update release notes
Build / build (push) Successful in 3m22s
2025-01-21 22:56:59 -06:00
gary 4fa879a09e [nostalgia/sample_project] Update NS_Logo.ng to final TileSheetV5 format
Build / build (push) Has been cancelled
2025-01-21 22:54:27 -06:00
gary fd8f1a29c6 [nostalgia] Add release notes document
Build / build (push) Successful in 3m24s
2025-01-21 22:45:55 -06:00
gary 9fda2763ba [nostalgia/gfx] Make TileSheetV5::defaultPalette a string instead of FileAddress 2025-01-21 22:44:55 -06:00
gary cda23ac4af [ox/std] Change ox::String::operator[](size_t) const return a reference 2025-01-21 22:43:57 -06:00
gary c36b244dd3 [nostalgia/gfx] Cleanup, add PaletteV5, restore mistakenly removed function 2025-01-21 22:17:13 -06:00
gary 335d278f5e [ox/oc] Fix integer read for signed/unsigned 2025-01-21 22:15:36 -06:00
gary f987b02c65 [nostalgia/gfx] Move to TileSheetV5
Build / build (push) Successful in 3m23s
2025-01-21 02:21:01 -06:00
gary 3c056276c1 [turbine,nostalgia] Cleanup 2025-01-20 23:19:07 -06:00
gary 87e2fdefcf [ox/std] Make UAnyPtr uncopyable 2025-01-20 20:42:00 -06:00
gary 672b92b363 [nostalgia/gfx/studio] Remove accidental version tag in default Palette
Build / build (push) Successful in 3m23s
2025-01-20 03:13:01 -06:00
gary 762a6517b2 [nostalgia] Rename core to gfx 2025-01-20 03:11:35 -06:00
gary d141154a45 Merge commit '38777cfac8868b3628332090260710d5ac26aba0'
Build / build (push) Successful in 3m23s
2025-01-20 02:15:45 -06:00
gary 6170647c0c [nostalgia,studio] Proper fix for input filtering 2025-01-20 02:10:48 -06:00
gary 48e45c7dd6 [studio] Cleanup 2025-01-20 01:34:00 -06:00
gary 5d3d9229b7 [nostalgia/core/studio/paletteeditor] Ignore keyboard input when popup is open 2025-01-20 01:33:23 -06:00
gary d54e93d836 [studio] Cleanup 2025-01-20 00:16:16 -06:00
gary 830f8fe3e4 [studio,nostalgia/core/studio] Give default Palette created studio a default page
Build / build (push) Successful in 3m23s
2025-01-19 20:53:27 -06:00
gary 7b638538aa Merge commit '8e0b6ffbabb10f8a6e9ad7e9f07e0ba1d039a02e' 2025-01-19 20:18:56 -06:00
gary 2016f6e605 [studio] Fix DeleteConfirmation 'No' option to not delete file
Build / build (push) Successful in 3m22s
2025-01-19 20:17:35 -06:00
gary 240effd305 Merge commit '7e20f7200963cd0b22f84cc46e10db12b6c13806' 2025-01-19 19:04:24 -06:00
gary 6bc629e02c [nostalgia/core/studio/tilesheeteditor] Replace Palette combobox with a readonly text input
Build / build (push) Successful in 3m21s
2025-01-19 19:02:44 -06:00
gary f6f2acd67b [nostalgia/core/studio/tilesheeteditor] Add back file type check for palette drop 2025-01-19 18:21:50 -06:00
gary 0146d38405 [nostalgia/core/studio/tilesheeteditor] Manually merge in changes that were lost in conflict
Build / build (push) Successful in 3m19s
2025-01-19 18:18:52 -06:00
gary 75d8e7bb89 [nostalgia/core/studio/paletteeditor] Fix crash that occurs when removing last color 2025-01-19 17:56:21 -06:00
gary 6b53eaf6b1 [ox/std] Fix string append issues
Build / build (push) Successful in 3m22s
2025-01-19 16:51:05 -06:00
gary 16c32273ac [nostalgia/core/studio/tilesheeteditor] Fix palette drop target to only take palettes 2025-01-19 16:49:31 -06:00
gary 1567a6e29d [applib] Fix build 2025-01-19 14:32:08 -06:00
gary 89d543bcbc Merge commit '7b7d59cf63d77cf7ab6daf6ed7122eef97954555' 2025-01-19 13:39:31 -06:00
gary d68e64931b [nostalgia/core/studio/tilesheeteditor] Add support for dragging palette to palette selector
Build / build (push) Successful in 3m22s
2025-01-19 11:41:48 -06:00
gary 1cbc576286 [studio] Complete drag/drop support for files 2025-01-19 11:41:08 -06:00
gary 500b93562c [studio] Make new dir window OK on Enter key
Build / build (push) Successful in 3m17s
2025-01-19 09:33:17 -06:00
gary 800ca85176 [ox/std] Fix possible error that occurs with appending on boundary of small string size
Build / build (push) Successful in 3m20s
2025-01-19 09:26:06 -06:00
gary cc466a9f1d [studio] Add support for adding and deleting directories 2025-01-19 09:06:16 -06:00
gary 9d1155843e [nostalgia] Rename player from 'nostalgia' to 'Nostalgia'
Build / build (push) Successful in 3m24s
2025-01-19 01:48:53 -06:00
gary a2139c09b2 [studio] Cleanup unused member 2025-01-19 01:44:26 -06:00
gary a3e5f27ab8 [ox/std] Fix Mac build 2025-01-19 01:43:38 -06:00
gary 643f95ec80 [studio] Add confirmation dialog for file deletion, move deletion to Project
Build / build (push) Successful in 3m16s
2025-01-19 01:15:33 -06:00
gary 6924147686 [studio] Add ability to add file through dir context menu
Build / build (push) Successful in 3m15s
Also, fix dir context menu to work when dir is closed, and fix it not to
override last file in the directory.
2025-01-18 23:45:04 -06:00
gary 6e2b4fa7b4 [nostalgia] Cleanup player run in Makefile 2025-01-18 23:33:55 -06:00
gary 4e5c749918 [studio] Add support for deleting files
Build / build (push) Successful in 3m16s
2025-01-18 22:32:12 -06:00
gary 66229de77f [ox/fs] FileSystem fixes with removing files 2025-01-18 22:31:19 -06:00
gary 7eb37c5318 [nostalgia/core/studio/paletteeditor] Fix adding page if there is no existing page
Build / build (push) Successful in 3m17s
2025-01-18 21:29:36 -06:00
gary 7a21b20711 [nostalgia/core] Replace ContextDeleter with safeDelete(Context*)
Build / build (push) Successful in 3m15s
2025-01-18 20:57:15 -06:00
gary 894be237f2 [ox/std] Drop ox:: qualifier from safeDelete function for pointee 2025-01-18 20:56:24 -06:00
gary 92e9d9cbfc [keel,studio] Add support for New Item templates
Build / build (push) Failing after 1m3s
2025-01-18 20:16:29 -06:00
gary b29b9a9b3a [ox/std] Add UAnyPtr 2025-01-18 20:11:42 -06:00
gary 721f844214 [nostalgia/core/studio/tilesheeteditor] Fix subsheet and palette scrolling 2025-01-18 20:08:09 -06:00
gary a3d6a58cc8 [nostalgia/core/studio] Fix library cpp file ownership
Build / build (push) Successful in 3m10s
2025-01-17 21:50:42 -06:00
gary e598e7fe27 [nostalgia,keel] Add ability to types Obj to Obj
Build / build (push) Successful in 3m10s
2025-01-15 23:44:18 -06:00
gary ba9e720f9f [ox/model] Fix ModelTypeName_v to use requireModelTypeName 2025-01-15 23:34:58 -06:00
gary 8e816a261f [nostalgia/core/studio] Cleanup, fix possible TileSheet fill tool failure
Build / build (push) Successful in 3m11s
2025-01-14 23:06:12 -06:00
gary 5b9929ab3d [keel] Add detail to preload logging 2025-01-14 21:20:13 -06:00
gary ceb54b3f1b [nostalgia/core/opengl] Cleanup 2025-01-14 21:18:22 -06:00
gary 8764444758 [nostalgia/core] Add clearCbb functions
Build / build (push) Successful in 3m12s
2025-01-14 21:13:42 -06:00
gary ce9a0b1fdb [nostalgia/core/opengl] Cleanup memcpys 2025-01-14 21:13:10 -06:00
gary f7a468ea1e [ox/std] Add spancpy 2025-01-14 21:10:18 -06:00
gary 861d177a27 [studio] Cleanup
Build / build (push) Successful in 3m12s
2025-01-13 22:58:39 -06:00
gary 3936756b36 [nostalgia/developer-handbook] Update error handling to reflect the enablement of exceptions for GBA build 2025-01-13 22:53:12 -06:00
gary 3e78ec3fe5 [studio] Cleanup 2025-01-13 22:40:08 -06:00
gary 3c3d53b40c [studio] Ensure Editor tabs do first draw immediately, fix shift key being missed with tab shortcuts
Build / build (push) Successful in 3m14s
2025-01-13 22:29:48 -06:00
gary 151d7c5736 [nostalgia/core/gba] Fix partial tilesheet loading overrun
Build / build (push) Successful in 3m11s
2025-01-13 22:03:36 -06:00
gary 4e4d8d2c3f [nostalgia/core/gba] Make panic use standard abort call 2025-01-13 21:37:29 -06:00
gary 03d1fd2857 [ox/std] Add and integrate standard abort call 2025-01-13 20:39:21 -06:00
gary 6701decc91 [gbabuildcore] Enable exceptions 2025-01-13 20:18:28 -06:00
gary 6cff526647 [teagba] Add symbols needed for enabling exceptions 2025-01-13 20:17:10 -06:00
gary dd50bd0249 [studio] Remap toggle explorer keyboard shortcut, add Ctrl+1-0 mappings for jumping between tabs
Build / build (push) Successful in 3m17s
2025-01-13 01:14:57 -06:00
gary 55a1660242 [nostalgia/core] Fix TileSheet validation/repair to ensure pixels gets cleared if there are subsheets
Build / build (push) Successful in 3m10s
2025-01-12 16:06:24 -06:00
gary ed365dfef5 [studio] Fix new project menu to return an appropriately sized string for name 2025-01-12 15:04:31 -06:00
gary 23a09e4a13 [nostalgia/core/studio] Fix SubSheet editor to return an appropriately sized string 2025-01-12 14:55:50 -06:00
gary b69e7ebb98 [nostalgia/core/studio/tilesheeteditor] Fix select all not to go beyond end
Build / build (push) Successful in 3m10s
2025-01-11 16:21:10 -06:00
gary 418d6e3f22 [nostalgia/core/studio] Fix crash that occurs when a non-leaf node subsheet is selected
Build / build (push) Successful in 3m11s
2025-01-11 16:06:48 -06:00
gary c44d8678cb [nostalgia/core/studio] Fix tile insert to correct input when inserting past the last tile
Build / build (push) Successful in 3m11s
2025-01-11 15:38:11 -06:00
gary eb4cd7106d [nostalgia/core/studio] Fix tile insert to work on last tile
Build / build (push) Successful in 3m9s
2025-01-11 15:23:57 -06:00
gary d259770f32 Merge commit '4ea4a61d542777a270c4e2c283e0e986fc9eec9c'
Build / build (push) Successful in 3m9s
2025-01-11 12:32:00 -06:00
gary 80bad608f7 [keel] Fix reloadAsset 2025-01-11 03:39:38 -06:00
gary 2bce9a2baf [ox/std] Add non-const SmallMap::pairs 2025-01-11 03:37:27 -06:00
gary 791b7746f3 [nostalgia] Update liccor file
Build / build (push) Successful in 3m18s
2025-01-08 23:13:14 -06:00
gary 842e3587fd [nostalgia] Update .gitignore for new location of scripts dir 2025-01-08 23:13:02 -06:00
gary 318e79004b [ox] Update liccor file 2025-01-08 23:12:28 -06:00
gary 9f338a7429 [ox] Run liccor
Build / build (push) Successful in 3m18s
2025-01-08 23:03:05 -06:00
gary 645e48af7b [nostalgia,olympic] Run liccor 2025-01-08 23:02:08 -06:00
gary ef92c8df13 [nostalgia] Make pkg-gba.py force lower case for pack tool
Build / build (push) Successful in 3m9s
2025-01-08 22:01:27 -06:00
gary 849d50be8e [nostalgia/core] Make getTileIdx return an Optional 2025-01-08 21:34:01 -06:00
gary 845092f114 [turbine] Make common turbine.cpp file private to its target 2025-01-08 21:33:23 -06:00
gary 75819a1797 [ox/std] Add SmallMap::values() 2025-01-08 21:31:46 -06:00
gary d66da85753 [ox/std] SmallMap fixes, add findIdx function 2025-01-07 20:59:04 -06:00
gary 98ddb08abd [nostalgia] Cleanup
Build / build (push) Successful in 3m18s
2025-01-05 20:55:49 -06:00
gary 8d1701b0bb [turbine/glfw] Ensure window opens with a standard mandatory refresh period
Build / build (push) Successful in 3m19s
2025-01-04 23:49:04 -06:00
gary 1048e522fd [imgui] Make ImGui not an object lib 2025-01-04 23:42:43 -06:00
gary ee59da4aa3 [glad] Make glad not an object lib 2025-01-04 23:42:43 -06:00
gary 1ba64cb5d8 Merge commit '07610a5af2aaaac9cfcdcf8359b33f7df40d46cd'
Build / build (push) Successful in 3m15s
2025-01-04 01:29:09 -06:00
gary 462bebf6dd [nostalgia/core] Cleanup unused function declaration 2025-01-04 01:26:02 -06:00
gary e3f84c4e75 [studio] Make first tab not draw before selected tab when window opens 2025-01-04 01:12:48 -06:00
gary 6837a0556d [keel] Make AssetManager take StringViewCR for assetId
Build / build (push) Successful in 3m16s
2025-01-04 01:11:05 -06:00
gary ede2c8ca37 [keel] Make AssetTypeManager(Loader) move loader
Build / build (push) Successful in 3m23s
2025-01-04 01:05:04 -06:00
gary f50367f7d5 [ox/std] Add hash.hpp to install
Build / build (push) Successful in 3m31s
2025-01-03 00:26:10 -06:00
gary e758e03d2b [nostalgia,olympic] Update for ox::Error changes
Build / build (push) Successful in 3m20s
2025-01-01 23:43:32 -06:00
gary 835e3270ce [ox] Make Error use std::source_location 2025-01-01 23:42:46 -06:00
gary 480dd5ece4 [ox/std] Cleanup
Build / build (push) Successful in 3m25s
2025-01-01 22:57:20 -06:00
gary dba6bb5800 [ox/std] Make Vector(initializer_list) use list size as capacity
Build / build (push) Successful in 3m55s
2025-01-01 22:37:28 -06:00
gary 40a456e54a [ox/std] Add Vector::shrink_to_fit 2025-01-01 22:32:57 -06:00
gary bf5be00c12 Merge commit 'dc96270ca5e882e41f6b657be14a20e8bd2ad501'
Build / build (push) Successful in 3m14s
2024-12-21 20:13:20 -06:00
gary dc7c2559d6 [studio] Make selection tracker not go below 0 2024-12-21 20:06:48 -06:00
gary a75c4a11d3 [nfde] Address CMake warning, remove unwanted logging
Build / build (push) Successful in 2m45s
2024-12-21 17:07:23 -06:00
gary 347a165762 [sample_project] Update type descriptors
Build / build (push) Successful in 2m55s
2024-12-21 02:45:24 -06:00
gary fd64bfae13 [keel] Fix a use after free, cleanup
Build / build (push) Waiting to run
2024-12-21 02:42:19 -06:00
gary aaeec20ac9 [nostalgia/player] Fix build 2024-12-21 02:42:05 -06:00
gary 37030f9c11 [keel] Cleanup pack tool 2024-12-21 02:41:56 -06:00
gary 462f2bca4c [nostalgia,olympic] Change macro names to comply with broader conventions 2024-12-21 02:41:19 -06:00
gary dc72500b98 [glutils] Change macro names to comply with broader conventions 2024-12-18 22:04:39 -06:00
gary 962fe8bc22 [ox] Change macro names to comply with broader conventions 2024-12-18 22:04:25 -06:00
gary 305eb62647 [studio] Fix build
Build / build (push) Waiting to run
2024-12-18 21:41:15 -06:00
gary 4754359a21 [ox/std] Cleanup Vec2
Build / build (push) Has been cancelled
2024-12-15 01:26:41 -06:00
gary dc07f3d58b [studio] Change FilePicker consturctor to take StringParams 2024-12-15 01:20:29 -06:00
gary fcdcfd10d1 [ox/std] Run liccor
Build / build (push) Successful in 2m52s
2024-12-14 14:33:43 -06:00
gary b74f6a7ace [studio,turbine] Run liccor 2024-12-14 14:33:06 -06:00
gary ac7e5be187 [ox] Remove OxException
Build / build (push) Successful in 2m52s
2024-12-14 00:40:05 -06:00
gary ed910c0beb [nostalgia/core/studio/tilesheeteditor] Fix access overflow on out of bounds Fill command
Build / build (push) Successful in 2m51s
2024-12-13 22:24:58 -06:00
gary 345fb03857 [ox] Remove OxError 2024-12-13 22:06:47 -06:00
gary 9881253f2a [glutils] Cleanup OxError 2024-12-13 22:06:26 -06:00
gary 96d27eecd1 [nostalgia,olympic] Cleanup 2024-12-13 22:00:03 -06:00
gary 28ebe93b77 [ox/std] Make source_location::current only init if valid
Build / build (push) Successful in 2m52s
2024-12-12 23:13:39 -06:00
gary e849e7a3dd [ox/std] Add source_location
Build / build (push) Has been cancelled
2024-12-12 23:09:01 -06:00
gary e6777b0ad7 [cityhash] Add install rule 2024-12-12 22:36:09 -06:00
gary c488c336de [turbine/glfw] Fix mandatoryRefreshPeriodEnd tracking
Build / build (push) Successful in 2m54s
2024-12-11 22:13:28 -06:00
gary 003f97201f [turbine/glfw] Move MandatoryRefreshPeriod to config.hpp
Build / build (push) Successful in 2m45s
2024-12-10 23:29:50 -06:00
gary d85a10af84 [nostalgia/core/studio] Cleanup 2024-12-10 23:29:21 -06:00
gary ff05d860c4 [turbine/glfw] Replace uninterruptedRefreshes with mandatoryRefreshPeriodEnd
Build / build (push) Has been cancelled
2024-12-10 01:49:20 -06:00
gary 7679403742 [turbine] Add init wrapper that takes FS path 2024-12-06 23:20:30 -06:00
gary c51a45e1ba [olympic] Cleanup 2024-12-06 00:22:33 -06:00
gary a6e24ff2b6 [ox/std] Add CString type alias 2024-12-06 00:20:03 -06:00
gary e0ec9e0c5f [nostalgia,olympic] Move olympic::run to global namespace
Build / build (push) Successful in 2m34s
2024-12-06 00:13:10 -06:00
gary 9a42a9b9d9 [nfde] Fix Windows warnings 2024-12-06 00:12:38 -06:00
gary 03a05c511e Merge commit '4ccdfc3a6e5bd501968903a01f7d8141b6f88375'
Build / build (push) Successful in 2m31s
2024-12-04 19:55:17 -06:00
gary bd91137d27 [nostalgia,olympic] Fix pack tool build for Windows 2024-12-02 21:10:52 -06:00
gary 161640fa11 [nostalgia] Cleanup
Build / build (push) Successful in 2m46s
2024-12-02 19:58:05 -06:00
gary 2b7d12945e [nostalgia/core/studio] Fix MSVC build 2024-12-01 19:42:29 -06:00
gary e42126c956 [nostalgia/core] Improve TileSheet validation, add repair
Build / build (push) Successful in 2m40s
2024-12-01 15:47:49 -06:00
gary 36942cca18 [nostalgia,olympic] Replace SpanView with Span<const T>
Build / build (push) Successful in 2m36s
2024-12-01 08:41:20 -06:00
gary b14f1d5000 [ox] Replace SpanView with Span<const T> 2024-12-01 08:41:08 -06:00
gary 1bf4f246c2 [applib] Make run take args as a SpanView 2024-11-28 00:51:42 -06:00
gary edda8e010e [ox/clargs] Add constructor that takes a SpanView 2024-11-28 00:51:02 -06:00
gary 3308b4dd72 [ox/std] Add missing + and += operators to Span
Build / build (push) Successful in 2m38s
2024-11-27 00:17:37 -06:00
gary 27f4703a9a [teagba] Suppress warnings for unsafe buffers 2024-11-27 00:15:59 -06:00
gary 6af00d9a2e [nostalgia] Enable warnings for unsafe buffers 2024-11-27 00:14:57 -06:00
gary 86b9f9316e [olympic] Enable warnings for unsafe buffers 2024-11-26 23:58:11 -06:00
gary a0ed1b3f62 [ox/std] Fix Span raw array constructor 2024-11-26 23:57:41 -06:00
gary 8dad624b21 [studio/applib] Cleanup 2024-11-26 23:32:32 -06:00
gary dc6605fd48 [keel] Add missing error checking to pack 2024-11-26 23:32:15 -06:00
gary c78d3cf638 [ox] Add more unsafe buffer exceptions 2024-11-26 23:31:34 -06:00
gary cee4f65d4a [ox/std] Replace an unsafe buffer
Build / build (push) Successful in 2m38s
2024-11-26 22:31:20 -06:00
gary cd3eeeef14 [ox/fs] Suppress unsafe buffer warnings 2024-11-26 22:30:57 -06:00
gary 287d42f2b9 [ox/clargs] Cleanup
Build / build (push) Successful in 2m41s
2024-11-26 22:08:36 -06:00
gary dbbaaa46b9 [ox/clargs] Enable unsafe buffer warnings
Build / build (push) Has been cancelled
2024-11-26 22:06:50 -06:00
gary 9b8a8c4e46 [ox/std] Enable unsafe buffer warnings 2024-11-26 21:59:26 -06:00
gary e44fa288fd [cityhash] Add pragmas to ignore unsafe buffer warnings 2024-11-26 21:58:39 -06:00
gary e13c6e812b [ox/std] Remove raw char* CharBufferWriter constructor 2024-11-26 20:48:13 -06:00
gary cb55b31afa [ox/std] Cleanup 2024-11-26 20:43:43 -06:00
gary ab3f9e1627 [ox/std] Make Span access check message consistent with other messages 2024-11-26 20:43:20 -06:00
gary 8f25ef96ff [ox/std] Make CharBufferWriter constructor take a Span 2024-11-26 20:42:33 -06:00
gary e13eebaf0b [ox/std] Cleanup an unsafe buffer 2024-11-26 20:38:00 -06:00
gary 114f5c6685 [ox/std] Add overflow checking to SpanIterator
Build / build (push) Successful in 2m36s
2024-11-19 01:09:48 -06:00
gary df44fe235b [keel] Cleanup
Build / build (push) Successful in 2m42s
2024-11-15 19:59:42 -06:00
gary 72f4db3d5e [nostalgia/core/studio] Fix paste command to never paste beyond target dimensions
Build / build (push) Successful in 2m40s
2024-11-15 01:39:57 -06:00
gary 8a9ff971a1 [nostalgia/core] Fix resizeSubsheet to work for both growing and shrinking 2024-11-15 01:09:48 -06:00
gary 5a8da59df1 [keel] Fix readAsset to actually return asset 2024-11-15 01:01:31 -06:00
gary afa3a13d41 [keel] Cleanup 2024-11-14 21:23:42 -06:00
gary 6522cf8a43 [keel] Add ensureValid call to readAsset 2024-11-14 21:17:41 -06:00
gary f772e48b36 [ox] Add Vector/Array/Span overflow checking 2024-11-14 21:08:38 -06:00
gary 13bfe88195 [nostalgia/core] Fix resizeSubsheet array overflow 2024-11-14 19:59:58 -06:00
gary 5025475414 Merge commit '9e11019b87ba27d1dac9e097dc212a126e404218' 2024-11-01 22:23:08 -05:00
gary 3c7652efc2 [nostalgia/core/studio] Fix PaletteEditor to handle Palettes with 0 pages
Build / build (push) Successful in 2m55s
2024-10-28 20:57:34 -05:00
gary 941bc71348 [studio] Fix NewMenu name input 2024-10-28 20:57:34 -05:00
gary bfe890ae00 [ox] Fix typo in docs 2024-10-08 23:04:49 -05:00
gary ab5bc1adb6 [ox/std] Remove oxRequireT and oxRequireMT 2024-10-06 06:16:14 -05:00
gary abf7548ab5 [nostalgia/core] Add missing include 2024-10-04 21:36:26 -05:00
gary e2682b5ef7 [studio/modlib] Add missing include 2024-10-04 21:35:08 -05:00
gary 792ad41499 [nostalgia] Remove .vs dir 2024-10-04 18:51:36 -05:00
gary e4ae23e114 [olympic/developer-handbook] Remove Ox submodules from project structure
Build / build (push) Successful in 2m31s
2024-10-04 01:22:21 -05:00
gary 67187d5ec5 [olympic/developer-handbook] Elaborate more on exception usage 2024-10-04 01:18:25 -05:00
gary 3271a37115 [ox] Add Project Structure section to docs
Build / build (push) Successful in 2m36s
2024-10-04 01:15:17 -05:00
gary ea9f50de8d [olympic] Add error handling back to developer-handbook.md 2024-10-04 01:13:45 -05:00
gary ea3c5e03fb [olympic] Remove Ox from developer-handbook.md 2024-10-04 01:00:02 -05:00
gary c8c4177d60 [ox] Add ox-docs.md 2024-10-04 00:59:23 -05:00
gary 76b540e3b8 [nostalgia/core] Cleanup, add missing FileAddress wrapper function
Build / build (push) Successful in 2m32s
2024-10-03 22:48:26 -05:00
gary 2062748676 [keel] Cleanup 2024-10-03 22:39:48 -05:00
gary 135f0e4ce8 [nostalgia/core/studio/paletteeditor] Fix Alt shortcuts to respect keyboard focus
Build / build (push) Successful in 2m30s
2024-10-02 22:50:55 -05:00
gary cb16687641 [studio] Add variant of InputText that returns an IString 2024-10-02 20:55:12 -05:00
gary cb3ef0e79d [keel] Cleanup 2024-10-02 20:54:40 -05:00
gary 0a62d90065 [studio] Remove Editor::setRequiresConstantRefresh 2024-10-02 01:18:37 -05:00
gary ba7e3929e9 [nostalgia/core/studio] Make TileSheetEditor palette keys behave like PaletteEditor 2024-10-01 22:37:36 -05:00
gary 36c4022b56 [nostalgia/core/studio] Fix PaletteEditor shortcuts to differentiate based on Alt key 2024-10-01 22:37:05 -05:00
gary e22b25e54c [studio] Remove Editor::requiresConstantRefresh 2024-10-01 22:35:29 -05:00
gary c6efabaa1d [studio,nostalgia] Fix PaletteEditor color update command merging, add setObsolete 2024-09-30 23:07:14 -05:00
gary 1f6fefdb68 [nostalgia/core/studio] Disable PaletteEditor num key shorts when page rename is open
Build / build (push) Successful in 2m32s
2024-09-29 23:17:47 -05:00
gary 1e34f91ebd Merge commit '34b7779397bd4712603b4c5a39ffc57b74da0abd'
Build / build (push) Successful in 2m29s
2024-09-29 22:03:41 -05:00
gary 35cb2ece9f [nostalgia/core/studio] Fix PaletteEditor color name edit 2024-09-29 16:14:26 -05:00
gary 66cd5c4a7e [ox/std] Add CStringViewCR
Build / build (push) Successful in 2m32s
2024-09-28 23:56:14 -05:00
gary 0daf938f76 [nostalgia/core/studio] Cleanup, make all number keys after num colors jump to last
Build / build (push) Successful in 2m32s
2024-09-28 23:44:12 -05:00
gary b90ab27a65 [nostalgia/core/studio] Fix Palette Color Name input to properly take focus
Build / build (push) Successful in 2m34s
2024-09-28 21:51:28 -05:00
gary c711f4358e [nostalgia/core/studio] Fix PaletteEditor 0 key shortcut
Build / build (push) Successful in 2m32s
2024-09-28 21:42:11 -05:00
gary 84cb03d807 [nostalgia/core/studio] Cleanup
Build / build (push) Successful in 2m32s
2024-09-28 21:37:29 -05:00
gary 945a55f94a [studio] Fix Project to cut off correct end of OC data
Build / build (push) Successful in 2m31s
2024-09-28 21:10:13 -05:00
gary 2173b12c67 [nostalgia/core/studio] Give PaletteEditor keyboard shortcuts 2024-09-28 21:09:24 -05:00
gary aa970b1fc0 [keel,studio] Cleanup 2024-09-28 18:45:09 -05:00
gary 6ad79b305c [ox] Cleanup 2024-09-28 18:44:50 -05:00
627 changed files with 45788 additions and 14924 deletions
+1
View File
@@ -0,0 +1 @@
sample_project text eol=lf
+8 -1
View File
@@ -4,7 +4,7 @@ on: [push]
jobs:
build:
runs-on: nostalgia
runs-on: olympic
steps:
- name: Check out repository code
uses: actions/checkout@v3
@@ -17,3 +17,10 @@ jobs:
- run: make purge configure-release
- run: make build
- run: make test
- run: make install
- run: mv dist/linux-x86_64-release nostalgia-linux-x86_64
- run: tar cf nostalgia-linux-x86_64.tar nostalgia-linux-x86_64
- uses: actions/upload-artifact@v3
with:
name: nostalgia-linux-x86_64
path: nostalgia-linux-x86_64.tar
+3 -1
View File
@@ -6,12 +6,14 @@
.mypy_cache
.stfolder
.stignore
scripts/__pycache__
.vs
util/scripts/__pycache__
pyenv
CMakeLists.txt.user
ROM.oxfs
Session.vim
build
cmake-build-*
compile_commands.json
dist
graph_info.json
+1 -1
View File
@@ -2,4 +2,4 @@
source:
- src
copyright_notice: |-
Copyright 2016 - 2024 Gary Talent (gary@drinkingtea.net). All rights reserved.
Copyright 2016 - 2025 Gary Talent (gary@drinkingtea.net). All rights reserved.
-44
View File
@@ -1,44 +0,0 @@
{
"version": "0.2.1",
"defaults": {},
"configurations": [
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "nostalgia.exe (Install)",
"name": "nostalgia.exe (Install)",
"args": [
"${projectDir}/sample_project"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "nostalgia.exe",
"name": "nostalgia.exe",
"args": [
"${projectDir}/sample_project"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "nostalgia-studio.exe (Install)",
"name": "nostalgia-studio.exe (Install)",
"args": [
"-profile",
"${projectDir}/src/nostalgia/studio/nostalgia-studio-dev.json"
]
},
{
"type": "default",
"project": "CMakeLists.txt",
"projectTarget": "nostalgia-studio.exe",
"name": "nostalgia-studio.exe",
"args": [
"-profile",
"${projectDir}/src/nostalgia/studio/nostalgia-studio-dev.json"
]
}
]
}
+80 -12
View File
@@ -1,35 +1,81 @@
BC_VAR_PROJECT_NAME=nostalgia
BC_VAR_PROJECT_NAME_CAP=Nostalgia
BUILDCORE_PATH=deps/buildcore
BC_VAR_DEVENV_ROOT=util
BUILDCORE_PATH=deps/ox/deps/buildcore
include ${BUILDCORE_PATH}/base.mk
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
PROJECT_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=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}Studio
PROJECT_STUDIO=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}Studio
MGBA=mgba-qt
endif
PROJECT_PLAYER=./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME_CAP}
.PHONY: git-setup-ox-remote
git-setup-ox-remote:
git remote add -f ox-master git@git.drinkingtea.net:drinkingtea/ox.git
.PHONY: git-pull-ox
git-pull-ox:
git fetch ox-master master
git subtree pull --prefix deps/ox ox-master master --squash
.PHONY: git-push-ox
git-push-ox:
git subtree push --prefix=deps/ox ox-master master
.PHONY: pkg-gba
pkg-gba: build
${BC_CMD_ENVRUN} ${BC_PY3} ./scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME}
pkg-gba: build-pack build-gba-player
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-gba.py sample_project ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: pkg-mac
pkg-mac: install
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/pkg-dmg.py NostalgiaStudio
.PHONY: generate-studio-rsrc
generate-studio-rsrc:
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/file-to-cpp.py --rsrc src/olympic/studio/applib/src/rsrc.json
${BC_CMD_ENVRUN} ${BC_PY3} ./util/scripts/file-to-cpp.py --rsrc src/nostalgia/studio/rsrc.json
.PHONY: build-gba-player
build-gba-player:
cmake --build ./build/gba-*
.PHONY: build-player
build-player:
${BC_CMD_CMAKE_BUILD} ${BC_VAR_BUILD_PATH} ${BC_VAR_PROJECT_NAME_CAP}
.PHONY: build-pack
build-pack:
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME}-pack
.PHONY: run
run: build
./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME} sample_project
run: build-player
${PROJECT_PLAYER} sample_project
.PHONY: build-studio
build-studio:
cmake --build ./build/${BC_VAR_CURRENT_BUILD} --target ${BC_VAR_PROJECT_NAME_CAP}Studio
.PHONY: run-studio
run-studio: build
${NOSTALGIA_STUDIO}
run-studio: build-studio
${PROJECT_STUDIO}
.PHONY: gba-run
gba-run: pkg-gba
${MGBA} ${BC_VAR_PROJECT_NAME}.gba
${MGBA} ${BC_VAR_PROJECT_NAME_CAP}.gba
.PHONY: debug
debug: build
${BC_CMD_HOST_DEBUGGER} ./build/${BC_VAR_CURRENT_BUILD}/bin/${BC_VAR_PROJECT_NAME} sample_project
${BC_CMD_HOST_DEBUGGER} ${PROJECT_PLAYER} sample_project
.PHONY: debug-studio
debug-studio: build
${BC_CMD_HOST_DEBUGGER} ${NOSTALGIA_STUDIO}
${BC_CMD_HOST_DEBUGGER} ${PROJECT_STUDIO}
.PHONY: configure-gba
configure-gba:
@@ -38,3 +84,25 @@ configure-gba:
.PHONY: configure-gba-debug
configure-gba-debug:
${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}
.PHONY: loc
loc:
${BC_PY3} util/scripts/loc.py \
--search-dirs \
src \
deps/ox/src \
deps/buildcore \
deps/gbabuildcore \
deps/glutils \
deps/teagba \
--include-exts \
.cpp \
.hpp \
.py \
.s \
.cmake \
--exclude-paths \
deps/teagba/src/gba_crt0.s \
src/olympic/studio/applib/src/font.cpp \
src/olympic/studio/applib/src/font.hpp \
src/nostalgia/studio/icondata.cpp
+2 -2
View File
@@ -1,8 +1,8 @@
list(APPEND CMAKE_MODULE_PATH ${CMAKE_CURRENT_LIST_DIR}/cmake/modules)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdlib")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -nostdinc++")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-unwind-tables")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-unwind-tables")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-exceptions")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-rtti")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -fno-strict-aliasing")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -mthumb-interwork")
+10 -1
View File
@@ -1,2 +1,11 @@
add_library(glad OBJECT src/glad.c)
add_library(glad src/glad.c)
target_include_directories(glad PUBLIC include)
install(
TARGETS
glad
DESTINATION
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
+23 -23
View File
@@ -89,7 +89,7 @@ struct GLObject: public Base {
return id;
}
constexpr operator const GLuint&() const noexcept {
constexpr operator GLuint const&() const noexcept {
return id;
}
@@ -135,7 +135,7 @@ struct FrameBuffer {
return fbo.id;
}
constexpr operator const GLuint&() const noexcept {
constexpr operator GLuint const&() const noexcept {
return fbo.id;
}
@@ -158,14 +158,14 @@ struct FrameBuffer {
class FrameBufferBind {
private:
static const FrameBuffer *s_activeFb;
const FrameBuffer *m_restoreFb = nullptr;
static FrameBuffer const *s_activeFb;
FrameBuffer const *m_restoreFb = nullptr;
public:
explicit FrameBufferBind(const FrameBuffer &fb) noexcept;
explicit FrameBufferBind(FrameBuffer const &fb) noexcept;
~FrameBufferBind() noexcept;
};
void bind(const FrameBuffer &fb) noexcept;
void bind(FrameBuffer const &fb) noexcept;
struct ShaderVarSet {
GLsizei len{};
@@ -176,7 +176,7 @@ struct ProgramSource {
ox::Vector<glutils::ShaderVarSet> const shaderParams;
GLsizei const rowLen = [this] {
GLsizei len{};
for (auto const&v : shaderParams) {
for (auto const &v : shaderParams) {
len += v.len;
}
return len;
@@ -187,23 +187,23 @@ struct ProgramSource {
ox::String const geomShader{};
};
ox::Result<GLProgram> buildShaderProgram(ProgramSource const&src) noexcept;
ox::Result<GLProgram> buildShaderProgram(ProgramSource const &src) noexcept;
ox::Result<GLProgram> buildShaderProgram(
ox::CStringView const&vert,
ox::CStringView const&frag,
ox::CStringView const&geo = "") noexcept;
ox::CStringView const &vert,
ox::CStringView const &frag,
ox::CStringView const &geo = "") noexcept;
void setupShaderParams(
GLProgram const&shader,
ox::Vector<ShaderVarSet> const&vars,
GLProgram const &shader,
ox::Vector<ShaderVarSet> const &vars,
GLsizei vertexRowLen) noexcept;
void setupShaderParams(GLProgram const&shader, ox::Vector<ShaderVarSet> const&vars) noexcept;
void setupShaderParams(GLProgram const &shader, ox::Vector<ShaderVarSet> const &vars) noexcept;
glutils::GLVertexArray generateVertexArrayObject() noexcept;
GLVertexArray generateVertexArrayObject() noexcept;
glutils::GLBuffer generateBuffer() noexcept;
GLBuffer generateBuffer() noexcept;
[[nodiscard]]
FrameBuffer generateFrameBuffer(int width, int height) noexcept;
@@ -215,20 +215,20 @@ void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept;
*/
void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept;
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const&sz) noexcept;
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const &sz) noexcept;
struct BufferSet {
glutils::GLVertexArray vao;
glutils::GLBuffer vbo;
glutils::GLBuffer ebo;
glutils::GLTexture tex;
GLVertexArray vao;
GLBuffer vbo;
GLBuffer ebo;
GLTexture tex;
ox::Vector<float> vertices;
ox::Vector<GLuint> elements;
};
void sendVbo(BufferSet const&bs) noexcept;
void sendVbo(BufferSet const &bs) noexcept;
void sendEbo(BufferSet const&bs) noexcept;
void sendEbo(BufferSet const &bs) noexcept;
void clearScreen() noexcept;
+52 -29
View File
@@ -46,9 +46,9 @@ template struct GLObject<deleteVertexArray>;
template struct GLObject<deleteProgram>;
template struct GLObject<deleteShader>;
const FrameBuffer *FrameBufferBind::s_activeFb = nullptr;
FrameBuffer const *FrameBufferBind::s_activeFb = nullptr;
FrameBufferBind::FrameBufferBind(const FrameBuffer &fb) noexcept: m_restoreFb(s_activeFb) {
FrameBufferBind::FrameBufferBind(FrameBuffer const &fb) noexcept: m_restoreFb(s_activeFb) {
s_activeFb = &fb;
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glViewport(0, 0, fb.width, fb.height);
@@ -64,15 +64,15 @@ FrameBufferBind::~FrameBufferBind() noexcept {
}
}
void bind(const FrameBuffer &fb) noexcept {
void bind(FrameBuffer const &fb) noexcept {
glBindFramebuffer(GL_FRAMEBUFFER, fb);
glViewport(0, 0, fb.width, fb.height);
}
static ox::Result<GLShader> buildShader(
GLuint shaderType,
const GLchar *src,
GLuint const shaderType,
GLchar const *src,
ox::StringViewCR shaderName) noexcept {
GLShader shader(glCreateShader(shaderType));
glShaderSource(shader, 1, &src, nullptr);
@@ -83,13 +83,13 @@ static ox::Result<GLShader> buildShader(
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 ox::Error(1, "shader compile error");
}
return shader;
}
ox::Result<GLProgram> buildShaderProgram(ProgramSource const&src) noexcept {
oxRequireM(program, buildShaderProgram(
ox::Result<GLProgram> buildShaderProgram(ProgramSource const &src) noexcept {
OX_REQUIRE_M(program, buildShaderProgram(
src.vertShader,
src.fragShader,
src.geomShader));
@@ -98,11 +98,11 @@ ox::Result<GLProgram> buildShaderProgram(ProgramSource const&src) noexcept {
}
void setupShaderParams(
GLProgram const&shader,
ox::Vector<ShaderVarSet> const&vars,
GLProgram const &shader,
ox::Vector<ShaderVarSet> const &vars,
GLsizei vertexRowLen) noexcept {
// setup vars
for (size_t lenWritten = 0; auto const&v : vars) {
for (size_t lenWritten = 0; auto const &v : vars) {
auto const attr = static_cast<GLuint>(glGetAttribLocation(shader, v.name.c_str()));
glEnableVertexAttribArray(attr);
glVertexAttribPointer(
@@ -113,27 +113,27 @@ void setupShaderParams(
}
}
void setupShaderParams(GLProgram const&shader, ox::Vector<ShaderVarSet> const&vars) noexcept {
void setupShaderParams(GLProgram const &shader, ox::Vector<ShaderVarSet> const &vars) noexcept {
// get row len
GLsizei vertexRowLen{};
for (auto const&v : vars) {
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 {
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"));
OX_REQUIRE(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"));
OX_REQUIRE(gs, buildShader(GL_GEOMETRY_SHADER, geo.c_str(), "gshad"));
glAttachShader(prgm, gs);
}
oxRequire(fs, buildShader(GL_FRAGMENT_SHADER, frag.c_str(), "fshad"));
OX_REQUIRE(fs, buildShader(GL_FRAGMENT_SHADER, frag.c_str(), "fshad"));
glAttachShader(prgm, fs);
glLinkProgram(prgm);
return prgm;
@@ -162,16 +162,30 @@ FrameBuffer generateFrameBuffer(int width, int height) noexcept {
// 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);
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);
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);
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
@@ -189,7 +203,16 @@ void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
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);
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
@@ -201,7 +224,7 @@ void resizeFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
glBindRenderbuffer(GL_RENDERBUFFER, 0);
}
void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
void resizeInitFrameBuffer(FrameBuffer &fb, int const width, int const height) noexcept {
if (!fb) {
fb = generateFrameBuffer(width, height);
return;
@@ -209,18 +232,18 @@ void resizeInitFrameBuffer(FrameBuffer &fb, int width, int height) noexcept {
resizeFrameBuffer(fb, width, height);
}
void resizeInitFrameBuffer(FrameBuffer &fb, ox::Size const&sz) noexcept {
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());
void sendVbo(BufferSet const &bs) noexcept {
auto const 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());
void sendEbo(BufferSet const &bs) noexcept {
auto const 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);
}
+9 -1
View File
@@ -6,7 +6,7 @@ endif()
# DrinkingTea: end
add_library(
imgui OBJECT
imgui
imgui.cpp
imgui_demo.cpp
imgui_draw.cpp
@@ -20,3 +20,11 @@ target_include_directories(
imgui SYSTEM PUBLIC
.
)
install(
TARGETS
imgui
DESTINATION
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
+12 -4
View File
@@ -1,4 +1,4 @@
cmake_minimum_required(VERSION 3.5)
cmake_minimum_required(VERSION 3.19)
project(nativefiledialog-extended VERSION 1.1.1)
set(nfd_ROOT_PROJECT OFF)
@@ -10,7 +10,11 @@ if(NOT DEFINED BUILD_SHARED_LIBS)
option(BUILD_SHARED_LIBS "Build a shared library instead of static" OFF)
endif()
option(NFD_BUILD_TESTS "Build tests for nfd" ${nfd_ROOT_PROJECT})
option(NFD_INSTALL "Generate install target for nfd" ${nfd_ROOT_PROJECT})
# DrinkingTea: begin
if(NOT DEFINED NFD_INSTALL)
option(NFD_INSTALL "Generate install target for nfd" ${nfd_ROOT_PROJECT})
endif()
# DrinkingTea: end
set(nfd_PLATFORM Undefined)
if(WIN32)
@@ -21,7 +25,9 @@ elseif(UNIX AND NOT APPLE)
set(nfd_PLATFORM PLATFORM_UNIX)
endif()
message("nfd Platform: ${nfd_PLATFORM}")
# DrinkingTea: begin
#message("nfd Platform: ${nfd_PLATFORM}")
# DrinkingTea: end
set(nfd_COMPILER Undefined)
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang" AND CMAKE_CXX_SIMULATE_ID STREQUAL "MSVC")
@@ -33,7 +39,9 @@ elseif(CMAKE_CXX_COMPILER_ID STREQUAL "GNU" OR CMAKE_CXX_COMPILER_ID STREQUAL "C
set(nfd_COMPILER COMPILER_GNU)
endif()
message("nfd Compiler: ${nfd_COMPILER}")
# DrinkingTea: begin
#message("nfd Compiler: ${nfd_COMPILER}")
# DrinkingTea: end
# Use latest C++ by default (should be the best one), but let user override it
if(NOT DEFINED CMAKE_CXX_STANDARD)
+3 -3
View File
@@ -201,7 +201,7 @@ nfdresult_t SetDefaultExtension(::IFileDialog* fileOpenDialog,
}
if (*p_spec) {
// multiple file extensions for this type (need to allocate memory)
size_t numChars = p_spec - filterList[0].spec;
size_t numChars = static_cast<size_t>(p_spec - filterList[0].spec);
// allocate one more char space for the '\0'
nfdnchar_t* extnBuf = NFDi_Malloc<nfdnchar_t>(sizeof(nfdnchar_t) * (numChars + 1));
if (!extnBuf) {
@@ -710,7 +710,7 @@ nfdresult_t CopyCharToWChar(const nfdu8char_t* inStr, nfdnchar_t*& outStr) {
int charsNeeded = MultiByteToWideChar(CP_UTF8, 0, inStr, -1, nullptr, 0);
assert(charsNeeded);
nfdnchar_t* tmp_outStr = NFDi_Malloc<nfdnchar_t>(sizeof(nfdnchar_t) * charsNeeded);
nfdnchar_t* tmp_outStr = NFDi_Malloc<nfdnchar_t>(sizeof(nfdnchar_t) * static_cast<size_t>(charsNeeded));
if (!tmp_outStr) {
return NFD_ERROR;
}
@@ -727,7 +727,7 @@ nfdresult_t CopyWCharToNFDChar(const nfdnchar_t* inStr, nfdu8char_t*& outStr) {
int bytesNeeded = WideCharToMultiByte(CP_UTF8, 0, inStr, -1, nullptr, 0, nullptr, nullptr);
assert(bytesNeeded);
nfdu8char_t* tmp_outStr = NFDi_Malloc<nfdu8char_t>(sizeof(nfdu8char_t) * bytesNeeded);
nfdu8char_t* tmp_outStr = NFDi_Malloc<nfdu8char_t>(sizeof(nfdu8char_t) * static_cast<size_t>(bytesNeeded));
if (!tmp_outStr) {
return NFD_ERROR;
}
-12
View File
@@ -1,12 +0,0 @@
{
"log_functions": [
{
"function": "ox::trace::gdblogger::captureLogFunc",
"ignore_frames": 3,
"file_var": "file",
"line_var": "line",
"channel_var": "ch",
"msg_var": "msg"
}
]
}
+20
View File
@@ -0,0 +1,20 @@
name: Build
run-name: ${{ gitea.actor }} build and test
on: [push]
jobs:
build:
runs-on: olympic
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
- run: make install
+2
View File
@@ -3,7 +3,9 @@ build/gba
build/*-asan
build/*-debug
build/*-release
.current_build
tags
compile_commands.json
conanbuildinfo.cmake
conanbuildinfo.txt
conaninfo.txt
+1 -1
View File
@@ -2,7 +2,7 @@
source:
- src
copyright_notice: |-
Copyright 2015 - 2024 gary@drinkingtea.net
Copyright 2015 - 2025 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
-11
View File
@@ -1,11 +0,0 @@
language: cpp
sudo: false
dist: trusty
compiler:
- clang
- gcc
addons:
apt:
packages:
- cmake
script: ./scripts/cibuild
+9 -2
View File
@@ -3,8 +3,8 @@ set(CMAKE_POLICY_DEFAULT_CMP0110 NEW) # requires CMake 3.19
project(Ox CXX)
list(APPEND CMAKE_MODULE_PATH ${CMAKE_SOURCE_DIR}/cmake/modules)
include(address_sanitizer)
include(deps/buildcore/base.cmake)
if(NOT DEFINED OX_RUN_TESTS)
set(OX_RUN_TESTS ON)
@@ -78,6 +78,13 @@ include_directories(src)
install(FILES OxConfig.cmake DESTINATION lib/cmake/ox)
install(
DIRECTORY
include/ox
DESTINATION
include
)
if(OX_USE_STDLIB)
set(JSONCPP_INCLUDE_DIR "${CMAKE_CURRENT_SOURCE_DIR}/deps/jsoncpp/include")
add_subdirectory(deps/jsoncpp)
+15 -65
View File
@@ -1,68 +1,18 @@
OS=$(shell uname | tr [:upper:] [:lower:])
HOST_ENV=${OS}-$(shell uname -m)
DEVENV=devenv$(shell pwd | sed 's/\//-/g')
DEVENV_IMAGE=wombatant/devenv
ifneq ($(shell which docker 2>&1),)
ifeq ($(shell docker inspect --format="{{.State.Status}}" ${DEVENV} 2>&1),running)
ENV_RUN=docker exec -i -t --user $(shell id -u ${USER}) ${DEVENV}
endif
endif
BC_VAR_PROJECT_NAME=ox
BC_VAR_PROJECT_NAME_CAP=Ox
BC_VAR_DEVENV_ROOT=util
BUILDCORE_PATH=deps/buildcore
include ${BUILDCORE_PATH}/base.mk
all:
${ENV_RUN} ./scripts/run-make build
preinstall:
${ENV_RUN} ./scripts/run-make build preinstall
install:
${ENV_RUN} ./scripts/run-make build install
clean:
${ENV_RUN} ./scripts/run-make build clean
purge:
${ENV_RUN} rm -rf build
test:
${ENV_RUN} ./scripts/run-make build test
.PHONY: git-setup-buildcore-remote
git-setup-buildcore-remote:
git remote add -f buildcore-master git@git.drinkingtea.net:drinkingtea/buildcore.git
devenv:
docker pull ${DEVENV_IMAGE}
docker run -d -v $(shell pwd):/usr/src/project \
-e LOCAL_USER_ID=$(shell id -u ${USER}) \
--name ${DEVENV} -t ${DEVENV_IMAGE} bash
devenv-destroy:
docker rm -f ${DEVENV}
devenv-shell:
${ENV_RUN} bash
.PHONY: git-pull-buildcore
git-pull-buildcore:
git fetch buildcore-master master
git subtree pull --prefix deps/buildcore buildcore-master master --squash
configure-release:
${ENV_RUN} rm -rf build/${HOST_ENV}-release
${ENV_RUN} ./scripts/setup_build ${HOST_ENV}
${ENV_RUN} rm -f build/current
${ENV_RUN} ln -s ${HOST_ENV}-release build/current
configure-debug:
${ENV_RUN} rm -rf build/${HOST_ENV}-debug
${ENV_RUN} ./scripts/setup_build ${HOST_ENV} debug
${ENV_RUN} rm -f build/current
${ENV_RUN} ln -s ${HOST_ENV}-debug build/current
configure-asan:
${ENV_RUN} rm -rf build/${HOST_ENV}-asan
${ENV_RUN} ./scripts/setup_build ${HOST_ENV} asan
${ENV_RUN} rm -f build/current
${ENV_RUN} ln -s ${HOST_ENV}-asan build/current
configure-windows:
${ENV_RUN} rm -rf build/windows
${ENV_RUN} ./scripts/setup_build windows
${ENV_RUN} rm -f build/current
${ENV_RUN} ln -s windows build/current
configure-windows-debug:
${ENV_RUN} rm -rf build/windows
${ENV_RUN} ./scripts/setup_build windows debug
${ENV_RUN} rm -f build/current
${ENV_RUN} ln -s windows build/current
configure-gba:
${ENV_RUN} rm -rf build/gba-release
${ENV_RUN} ./scripts/setup_build gba
${ENV_RUN} rm -f build/current
${ENV_RUN} ln -s gba-release build/current
.PHONY: git-push-buildcore
git-push-buildcore:
git subtree push --prefix=deps/buildcore buildcore-master master
-24
View File
@@ -1,24 +0,0 @@
set(CMAKE_SYSTEM_NAME "Generic")
set(DEVKITARM $ENV{DEVKITARM})
if(NOT DEVKITARM)
message(FATAL_ERROR "DEVKITARM environment variable not set")
endif()
set(CMAKE_C_COMPILER ${DEVKITARM}/bin/arm-none-eabi-gcc)
set(CMAKE_CXX_COMPILER ${DEVKITARM}/bin/arm-none-eabi-g++)
set(CMAKE_FIND_ROOT_PATH ${DEVKITARM})
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
set(CMAKE_FIND_LIBRARY_PREFIXES lib)
set(CMAKE_FIND_LIBRARY_SUFFIXES .a)
set(LINKER_FLAGS "-specs=gba.specs")
add_definitions (
-DARM7
)
include(FindPackageHandleStandardArgs)
-18
View File
@@ -1,18 +0,0 @@
set(CMAKE_SYSTEM_NAME Windows)
set(TOOLCHAIN_PREFIX x86_64-w64-mingw32)
# cross compilers to use for C and C++
set(CMAKE_C_COMPILER /usr/bin/${TOOLCHAIN_PREFIX}-gcc)
set(CMAKE_CXX_COMPILER /usr/bin/${TOOLCHAIN_PREFIX}-g++)
set(CMAKE_RC_COMPILER /usr/bin/${TOOLCHAIN_PREFIX}-windres)
# target environment on the build host system
# set 1st to dir with the cross compiler's C/C++ headers/libs
set(CMAKE_FIND_ROOT_PATH /usr/${TOOLCHAIN_PREFIX})
# modify default behavior of FIND_XXX() commands to
# search for headers/libs in the target environment and
# search for programs in the build host environment
set(CMAKE_FIND_ROOT_PATH_MODE_PROGRAM NEVER)
set(CMAKE_FIND_ROOT_PATH_MODE_LIBRARY ONLY)
set(CMAKE_FIND_ROOT_PATH_MODE_INCLUDE ONLY)
-52
View File
@@ -1,52 +0,0 @@
# This file belongs Nick Overdijk, and is from https://github.com/NickNick/wubwubcmake
# The MIT License (MIT)
#
# Copyright (c) 2013 Nick Overdijk
#
# 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.option(USE_ASAN "Enable Address Sanitizer, if your compiler supports it" ON)
option(USE_ASAN "Enable Address Sanitizer, if your compiler supports it" OFF)
if(USE_ASAN)
include(CheckCXXSourceCompiles)
# If the compiler understands -fsanitize=address, add it to the flags (gcc since 4.8 & clang since version 3.2)
set(CMAKE_REQUIRED_FLAGS_BAK "${CMAKE_REQUIRED_FLAGS}")
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -fsanitize=address")
CHECK_CXX_SOURCE_COMPILES("int main() { return 0; }" FLAG_FSANA_SUPPORTED)
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_BAK}")
if(FLAG_FSANA_SUPPORTED)
set(asan_flag "-fsanitize=address")
else(FLAG_FSANA_SUPPORTED)
# Alternatively, try if it understands -faddress-sanitizer (clang until version 3.2)
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS} -faddress-sanitizer")
CHECK_CXX_SOURCE_COMPILES("int main() { return 0; }" FLAG_FASAN_SUPPORTED)
set(CMAKE_REQUIRED_FLAGS "${CMAKE_REQUIRED_FLAGS_BAK}")
if(FLAG_FASAN_SUPPORTED)
set(asan_flag "-faddress-sanitizer")
endif(FLAG_FASAN_SUPPORTED)
endif(FLAG_FSANA_SUPPORTED)
if(FLAG_FSANA_SUPPORTED OR FLAG_FASAN_SUPPORTED)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} ${asan_flag}")
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} ${asan_flag}")
set(CMAKE_MODULE_LINKER_FLAGS "${CMAKE_MODULE_LINKER_FLAGS} ${asan_flag}")
set(CMAKE_SHARED_LINKER_FLAGS "${CMAKE_SHARED_LINKER_FLAGS} ${asan_flag}")
endif()
endif(USE_ASAN)
+1 -1
View File
@@ -93,7 +93,7 @@ purge:
${BC_CMD_RM_RF} compile_commands.json
.PHONY: test
test: build
${BC_CMD_ENVRUN} mypy ${BC_VAR_SCRIPTS}
${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
@@ -11,6 +11,7 @@
# "Python Busy Box" - adds cross-platform equivalents to Unix commands that
# don't translate well to that other operating system
import multiprocessing
import os
import platform
import shutil
@@ -57,7 +58,11 @@ def cmake_build(base_path: str, target: Optional[str]) -> int:
path = os.path.join(base_path, d)
if not os.path.isdir(path):
continue
args = ['cmake', '--build', path]
args = ['cmake', '--build', path, f'-j{multiprocessing.cpu_count()}']
if path.endswith('release'):
args.append('--config=release')
elif path.endswith('debug'):
args.append('--config=debug')
if target is not None:
args.extend(['--target', target])
err = subprocess.run(args).returncode
@@ -35,4 +35,6 @@ def get_arch() -> str:
arch = platform.machine().lower()
if arch == 'amd64':
arch = 'x86_64'
elif arch == 'aarch64':
arch = 'arm64'
return arch
+7 -3
View File
@@ -9,9 +9,6 @@ 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)
@@ -28,3 +25,10 @@ endif()
add_library(CityHash INTERFACE)
target_include_directories(CityHash INTERFACE include)
install(
DIRECTORY
include/cityhash
DESTINATION
include
)
+9
View File
@@ -104,6 +104,11 @@ using size_t = decltype(alignof(int));
#endif
#ifdef __clang__
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunsafe-buffer-usage"
#endif
namespace cityhash::detail {
template<typename T>
@@ -671,4 +676,8 @@ constexpr uint128 CityHash128(const char *s, size_t len) noexcept {
}
#ifdef __clang__
#pragma clang diagnostic pop
#endif
#endif // CITY_HASH_H_
+1 -1
View File
@@ -12,7 +12,7 @@
# CMake versions greater than the JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION policies will
# continue to generate policy warnings "CMake Warning (dev)...Policy CMP0XXX is not set:"
#
set(JSONCPP_OLDEST_VALIDATED_POLICIES_VERSION "3.8.0")
set(JSONCPP_OLDEST_VALIDATED_POLICIES_VERSION "3.13.2")
set(JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION "3.13.2")
cmake_minimum_required(VERSION ${JSONCPP_OLDEST_VALIDATED_POLICIES_VERSION})
if("${CMAKE_VERSION}" VERSION_LESS "${JSONCPP_NEWEST_VALIDATED_POLICIES_VERSION}")
+685
View File
@@ -0,0 +1,685 @@
# Ox Docs
## Project Structure
All components have a platform indicator next to them:
(OB) - OS, Bare Metal
(-B) - Bare Metal
(O-) - OS
* Ox - Library of things useful for portable bare metal and userland code. Not really that external...
* clargs - Command Line Args processing (OB)
* claw - Reads and writes Metal or Organic Claw with header to indicate which
* event - Qt-like signal system (OB)
* fs - file system (OB)
* logconn - connects logging to Bullock (O-)
* mc - Metal Claw serialization, builds on model (OB)
* oc - Organic Claw serialization (wrapper around JsonCpp), builds on model (O-)
* model - Data structure modelling (OB)
* preloader - library for handling preloading of data (OB)
* std - Standard-ish Library with a lot missing and some things added (OB)
## Systems
### Error Handling
Ox provides ```ox::Error``` to report errors.
```ox::Error``` is a struct that has overloaded operators to behave like an
integer error code, plus some extra fields to enhance debuggability.
```ox::Error```s will also include the file and line of the error.
In addition to ```ox::Error``` there is also the template ```ox::Result<T>```.
```ox::Result``` simply wraps the type T value in a struct that also includes
error information, which allows the returning of a value and an error without
resorting to output parameters.
If a function returns an ```ox::Error``` or ```ox::Result``` it should be
declared as ```noexcept``` and all exceptions should be translated to an
```ox::Error```.
```ox::Result``` can be used as follows:
```cpp
ox::Result<int> foo(int i) noexcept {
if (i < 10) {
return i + 1; // implicitly calls ox::Result<T>::Result(T)
}
return ox::Error(1); // implicitly calls ox::Result<T>::Result(ox::Error)
}
int caller1() {
auto v = foo(argc);
if (v.error) {
return 1;
}
std::cout << v.value << '\n';
return 0;
}
int caller2() {
// it is also possible to capture the value and error in their own variables
auto [val, err] = foo(argc);
if (err) {
return 1;
}
std::cout << val << '\n';
return 0;
}
ox::Error caller3(int &i) {
return foo(i).moveTo(i);
}
ox::Error caller4(int &i) {
return foo(i).copyTo(i);
}
int caller5(int i) {
return foo(i).unwrap(); // unwrap will kill the program if there is an error
}
int caller6(int i) {
return foo(i).unwrapThrow(); // unwrap will throw if there is an error
}
int caller7(int i) {
return foo(i).or_value(0); // will return 0 if foo returned an error
}
ox::Result<uint64_t> caller8(int i) {
return foo(i).to<uint64_t>(); // will convert the result of foo to uint64_t
}
```
Lastly, there are a few macros available to help in passing ```ox::Error```s
back up the call stack, ```OX_RETURN_ERROR```, ```OX_THROW_ERROR```, and
```OX_REQUIRE```.
```OX_RETURN_ERROR``` is by far the more helpful of the two.
```OX_RETURN_ERROR``` will return an ```ox::Error``` if it is not 0 and
```OX_THROW_ERROR``` will throw an ```ox::Error``` if it is not 0.
Since ```ox::Error``` is always nodiscard, you must do something with them.
In rare cases, you may not have anything you can do with them or you may know
the code will never fail in that particular instance.
This should be used sparingly.
```cpp
void studioCode() {
auto [val, err] = foo(1);
OX_THROW_ERROR(err);
doStuff(val);
}
ox::Error engineCode() noexcept {
auto [val, err] = foo(1);
OX_RETURN_ERROR(err);
doStuff(val);
return {};
}
void anyCode() {
auto [val, err] = foo(1);
std::ignore = err;
doStuff(val);
}
```
Both macros will also take the ```ox::Result``` directly:
```cpp
void studioCode() {
auto valerr = foo(1);
OX_THROW_ERROR(valerr);
doStuff(valerr.value);
}
ox::Error engineCode() noexcept {
auto valerr = foo(1);
OX_RETURN_ERROR(valerr);
doStuff(valerr.value);
return {};
}
```
Ox also has the ```OX_REQUIRE``` macro, which will initialize a value if there is no error, and return if there is.
It aims to somewhat emulate the ```?``` operator in Rust and Swift.
Rust ```?``` operator:
```rust
fn f() -> Result<i32, i32> {
// do stuff
}
fn f2() -> Result<i32, i32> {
let i = f()?;
Ok(i + 4)
}
```
```OX_REQUIRE```:
```cpp
ox::Result<int> f() noexcept {
// do stuff
}
ox::Result<int> f2() noexcept {
OX_REQUIRE(i, f()); // const auto [out, OX_CONCAT(oxRequire_err_, __LINE__)] = x; OX_RETURN_ERROR(OX_CONCAT(oxRequire_err_, __LINE__))
return i + 4;
}
```
```OX_REQUIRE``` is not quite as versatile, but it should still cleanup a lot of otherwise less ideal code.
```OX_REQUIRE``` by default creates a const, but there is also an ```OX_REQUIRE_M``` (OX_REQUIRE Mutable)
variant for creating a non-const value.
* ```OX_REQUIRE_M``` - OX_REQUIRE Mutable
### Ox String Types
Ox has six different major string types.
These types are divided into two categories: store types and view types.
String stores maintain a copy of the string data, whereas view types only
maintain a reference to the data.
Views should be used where you otherwise might use a const reference to a
string store type.
Having all of these different string types may sound like an interoperability
nightmare, but taking string view types extensively where applicable makes the
imagined interoperability issues virtually non-existent.
#### String Store Types
##### String / BasicString
```ox::String```, or really ```ox::BasicString```, is Ox's version of
```std::string```.
Like ```std::string```, ```String``` allocates to store the string data.
Also like ```std::string```, ```String``` allows for small string
optimization for strings under 8 bytes.
Unlike ```std::string```, the template that ```String``` is based on,
```BasicString```, takes a parameter that allows adjusting to different size
small string buffers.
```ox::String``` is an alias to ```ox::BasicString<8>```.
```cpp
// s can hold up to 100 bytes, plus one for a null terminator before allocating
ox::BasicString<100> s;
```
Also unlike ```std::string```, ```ox::String``` has an explicit C-string conversion
constructor.
This prevents accidental instantiations of ```String```.
Consider the following:
```cpp
void fStd(std::string const&);
void fOx(ox::String const&);
int main() {
// implicit and silent instantiation of std::string, which includes an
// allocation
fStd("123456789");
// Will fail to compile:
fOx("123456789");
// But explicit String instantiation will work:
fOx(ox::String{"123456789"});
}
```
##### IString
```IString```, or "inline string", is like ```BasicString```, but it will cut
off strings that exceed that limit.
```cpp
ox::IString<5> s; // s can hold up to 5 characters, plus a null terminator
s = "12345"; // valid
s = "123456"; // will compile and run, but will get cut off at '5'
```
This is useful for certain string categories that have fixed lengths, like UUID
strings or for numbers.
Ox makes use of ```IString``` in the following ways:
```cpp
using UUIDStr = ox::IString<36>;
// and
template<Integer_c Integer>
[[nodiscard]]
constexpr auto intToStr(Integer v) noexcept {
constexpr auto Cap = [] {
auto out = 0;
switch (sizeof(Integer)) {
case 1:
out = 3;
break;
case 2:
out = 5;
break;
case 4:
out = 10;
break;
case 8:
out = 21;
break;
}
return out + ox::is_signed_v<Integer>;
}();
ox::IString<Cap> out;
std::ignore = out.resize(out.cap());
ox::CharBuffWriter w{{out.data(), out.cap()}};
std::ignore = writeItoa(v, w);
std::ignore = out.resize(w.tellp());
return out;
}
```
##### StringParam
```StringParam``` is a weird type.
Because ```String::String(const char*)``` is explicit, it becomes a pain for
functions to take ```String```s.
```cpp
struct Type {
ox::String m_s;
explicit Type(ox::String p): m_s(std::move(p)) {
}
};
void f() {
ox::String s{"asdf"};
Type t1{"asdf"}; // invalid - will not compile
Type t2{s}; // invalid - will not compile
Type t3{std::move(s)}; // valid
Type t4{ox::String{"asdf"}}; // valid
}
```
```StringParam``` has implicit conversion constructors, and will appropriately
move from r-value ```String```s or create a ```String``` if not passed
ownership of an existing ```String```.
Think of ```StringParam``` as a way to opt-in to implicit instantiation with
strings.
```StringParam``` can access the string as a view through the ```view()```
function, and the ```String``` inside can be accessed by moving from the
```StringParam```.
```cpp
struct Type {
ox::String m_s;
explicit Type(ox::StringParam p): m_s(std::move(p)) {
}
};
void f() {
ox::String s{"asdf"};
Type t1{"asdf"}; // valid
Type t2{s}; // valid
Type t3{std::move(s)}; // valid
Type t4{ox::String{"asdf"}}; // valid
}
```
#### String View Types
##### StringView
```ox::StringView``` is Ox's version of ```std::string_view```.
```StringView``` contains a pointer to a string, along with its size.
This should be the normal type taken when a function needs a string that will
exist until it returns.
##### CStringView
```CStringView``` is like ```StringView```, but it comes with the promise that
the string ends with a null terminator.
Accordingly, it has a ```c_str()``` function in addition to the ```data()```
function that ```StringView``` has.
```CStringView``` should be used when wrapping a C API that only takes C
strings.
##### StringLiteral
```StringLiteral``` is a string view type, but it kind of straddles the line
between view and store types.
Creating a ```StringLiteral``` is a promise that you are passing a string
literal into the constructor.
This means you can treat it like a store, that can be safely used as a copy of
the data.
Functions that take ```StringLiteral```s are allowed to assume that the data
will have no lifetime concerns and hold onto it without any need to make a
copy.
It has a consteval constructor to enforce the promise that it is a compile time
string.
```cpp
void f(ox::StringLiteral const&);
int main() {
f("123456789"); // valid
f(ox::String{"123456789"}.c_str()); // invalid - will not compile
}
```
#### Other Variants
There are a few convenience aliases as well.
* StringCR = String const&
* StringViewCR = StringView const&
* CStringViewCR = CStringView const&
* CString = const char*
String views do not generally need const references, but it does make debugging
easier, as we can skip the constructor call if a string view already exists.
These kind of aliases probably should not exist for most types, but strings are
fundamental and ease of use is desirable.
### Logging and Output
Ox provides for logging and debug prints via the ```oxTrace```, ```oxDebug```, and ```oxError``` macros.
Each of these also provides a format variation.
Ox also provide ```oxOut``` and ```oxErr``` for printing to stdout and stderr.
These are intended for permanent messages and always go to stdout and stderr.
Tracing functions do not go to stdout unless the OXTRACE environment variable is set.
They also print with the channel that they are on, along with file and line.
Debug statements go to stdout and go to the logger on the "debug" channel.
Where trace statements are intended to be written with thoughtfulness,
debug statements are intended to be quick and temporary insertions.
Debug statements trigger compilation failures if OX_NODEBUG is enabled when CMake is run,
as it is on Jenkins builds, so ```oxDebug``` statements should never be checked in.
This makes ```oxDebug``` preferable to other forms of logging, as temporary prints should
never be checked in.
```oxError``` always prints.
It includes file and line, and is prefixed with a red "ERROR:".
It should generally be used conservatively.
It should be used only when there is an error that is not technically fatal, but
the user almost certainly wants to know about it.
```oxTrace``` and ```oxTracef```:
```cpp
void f(int x, int y) { // x = 9, y = 4
oxTrace("nostalgia.core.sdl.gfx") << "f:" << x << y; // Output: "f: 9 4"
oxTracef("nostalgia.core.sdl.gfx", "f: {}, {}", x, y); // Output: "f: 9, 4"
}
```
```oxDebug``` and ```oxDebugf```:
```cpp
void f(int x, int y) { // x = 9, y = 4
oxDebug() << "f:" << x << y; // Output: "f: 9 4"
oxDebugf("f: {}, {}", x, y); // Output: "f: 9, 4"
}
```
```oxError``` and ```oxErrorf```:
```cpp
void f(int x, int y) { // x = 9, y = 4
oxError() << "f:" << x << y; // Output: "ERROR: (<file>:<line>): f: 9 4"
oxErrorf("f: {}, {}", x, y); // Output: "ERROR: (<file>:<line>): f: 9, 4"
}
```
### Model System
Ox has a model system that provides a sort of manual reflection mechanism.
Models require a model function for the type that you want to model.
It is also good to provide a type name and type version number, though that is not required.
The model function takes an instance of the type it is modelling and a template
parameter type.
The template parameter type must implement the API used in the models, but it
can do anything with the data provided to it.
Here is an example from the Nostalgia/Core package:
```cpp
struct NostalgiaPalette {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.NostalgiaPalette";
static constexpr auto TypeVersion = 1;
ox::Vector<Color16> colors;
};
struct NostalgiaGraphic {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.core.NostalgiaGraphic";
static constexpr auto TypeVersion = 1;
int8_t bpp = 0;
// rows and columns are really only used by TileSheetEditor
int rows = 1;
int columns = 1;
ox::FileAddress defaultPalette;
NostalgiaPalette pal;
ox::Vector<uint8_t> pixels;
};
template<typename T>
constexpr ox::Error model(T *h, ox::CommonPtrWith<NostalgiaPalette> auto *pal) noexcept {
h->template setTypeInfo<NostalgiaPalette>();
// it is also possible to provide the type name and type version as function arguments
//h->setTypeInfo("net.drinkingtea.nostalgia.core.NostalgiaPalette", 1);
OX_RETURN_ERROR(h->field("colors", &pal->colors));
return {};
}
template<typename T>
constexpr ox::Error model(T *h, ox::CommonPtrWith<NostalgiaGraphic> auto *ng) noexcept {
h->template setTypeInfo<NostalgiaGraphic>();
OX_RETURN_ERROR(h->field("bpp", &ng->bpp));
OX_RETURN_ERROR(h->field("rows", &ng->rows));
OX_RETURN_ERROR(h->field("columns", &ng->columns));
OX_RETURN_ERROR(h->field("defaultPalette", &ng->defaultPalette));
OX_RETURN_ERROR(h->field("pal", &ng->pal));
OX_RETURN_ERROR(h->field("pixels", &ng->pixels));
return {};
}
```
The model system also provides for unions:
```cpp
#include <ox/model/types.hpp>
class FileAddress {
template<typename T>
friend constexpr Error model(T*, ox::CommonPtrWith<FileAddress> auto*) noexcept;
public:
static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress";
union Data {
static constexpr auto TypeName = "net.drinkingtea.ox.FileAddress.Data";
char *path;
const char *constPath;
uint64_t inode;
};
protected:
FileAddressType m_type = FileAddressType::None;
Data m_data;
};
template<typename T>
constexpr Error model(T *h, ox::CommonPtrWith<FileAddress::Data> auto *obj) noexcept {
h->template setTypeInfo<FileAddress::Data>();
OX_RETURN_ERROR(h->fieldCString("path", &obj->path));
OX_RETURN_ERROR(h->fieldCString("constPath", &obj->path));
OX_RETURN_ERROR(h->field("inode", &obj->inode));
return {};
}
template<typename T>
constexpr Error model(T *io, ox::CommonPtrWith<FileAddress> auto *fa) noexcept {
io->template setTypeInfo<FileAddress>();
// cannot read from object in Reflect operation
if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) {
int8_t type = 0;
OX_RETURN_ERROR(io->field("type", &type));
OX_RETURN_ERROR(io->field("data", UnionView(&fa->m_data, 0)));
} else {
auto type = static_cast<int8_t>(fa->m_type);
OX_RETURN_ERROR(io->field("type", &type));
fa->m_type = static_cast<FileAddressType>(type);
OX_RETURN_ERROR(io->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
}
return {};
}
```
There are also macros in ```<ox/model/def.hpp>``` for simplifying the declaration of models:
```cpp
OX_MODEL_BEGIN(NostalgiaGraphic)
OX_MODEL_FIELD(bpp)
OX_MODEL_FIELD(rows)
OX_MODEL_FIELD(columns)
OX_MODEL_FIELD(defaultPalette)
OX_MODEL_FIELD(pal)
OX_MODEL_FIELD(pixels)
oxModelEnd()
```
### Serialization
Using the model system, Ox provides for serialization.
Ox has MetalClaw and OrganicClaw as its serialization format options.
MetalClaw is a custom binary format designed for minimal size.
OrganicClaw is a wrapper around JsonCpp, chosen because it technically
implements a superset of JSON.
OrganicClaw requires support for 64 bit integers, whereas normal JSON
technically does not.
These formats do not currently support floats.
There is also a wrapper format called Claw that provides a header at the
beginning of the file and can dynamically switch between the two depending on
what the header says is present.
The Claw header also includes information about the type and type version of
the data.
Claw header: ```M1;net.drinkingtea.nostalgia.core.NostalgiaPalette;1;```
That reads:
* Format is Metal Claw, version 1
* Type ID is net.drinkingtea.nostalgia.core.NostalgiaPalette
* Type version is 1
#### Metal Claw Example
##### Read
```cpp
#include <ox/mc/read.hpp>
ox::Result<NostalgiaPalette> loadPalette1(ox::BufferView const&buff) noexcept {
return ox::readMC<NostalgiaPalette>(buff);
}
ox::Result<NostalgiaPalette> loadPalette2(ox::BufferView const&buff) noexcept {
NostalgiaPalette pal;
OX_RETURN_ERROR(ox::readMC(buff, pal));
return pal;
}
```
##### Write
```cpp
#include <ox/mc/write.hpp>
ox::Result<ox::Buffer> writeSpritePalette1(NostalgiaPalette const&pal) noexcept {
ox::Buffer buffer(ox::units::MB);
std::size_t sz = 0;
OX_RETURN_ERROR(ox::writeMC(buffer.data(), buffer.size(), pal, &sz));
buffer.resize(sz);
return buffer;
}
ox::Result<ox::Buffer> writeSpritePalette2(NostalgiaPalette const&pal) noexcept {
return ox::writeMC(pal);
}
```
#### Organic Claw Example
##### Read
```cpp
#include <ox/oc/read.hpp>
ox::Result<NostalgiaPalette> loadPalette1(ox::BufferView const&buff) noexcept {
return ox::readOC<NostalgiaPalette>(buff);
}
ox::Result<NostalgiaPalette> loadPalette2(ox::BufferView const&buff) noexcept {
NostalgiaPalette pal;
OX_RETURN_ERROR(ox::readOC(buff, &pal));
return pal;
}
```
##### Write
```cpp
#include <ox/oc/write.hpp>
ox::Result<ox::Buffer> writeSpritePalette1(NostalgiaPalette const&pal) noexcept {
ox::Buffer buffer(ox::units::MB);
OX_RETURN_ERROR(ox::writeOC(buffer.data(), buffer.size(), pal));
return buffer;
}
ox::Result<ox::Buffer> writeSpritePalette2(NostalgiaPalette const&pal) noexcept {
return ox::writeOC(pal);
}
```
#### Claw Example
##### Read
```cpp
#include <ox/claw/read.hpp>
ox::Result<NostalgiaPalette> loadPalette1(ox::BufferView const&buff) noexcept {
return ox::readClaw<NostalgiaPalette>(buff);
}
ox::Result<NostalgiaPalette> loadPalette2(ox::BufferView const&buff) noexcept {
NostalgiaPalette pal;
OX_RETURN_ERROR(ox::readClaw(buff, pal));
return pal;
}
```
##### Write
```cpp
#include <ox/claw/write.hpp>
ox::Result<ox::Buffer> writeSpritePalette(NostalgiaPalette const&pal) noexcept {
return ox::writeClaw(pal);
}
```
-8
View File
@@ -1,8 +0,0 @@
#! /usr/bin/env bash
set -e
make -j release
make -j debug
make -j
make -j test
-8
View File
@@ -1,8 +0,0 @@
#! /usr/bin/env bash
set -e
for f in $(find $1 -maxdepth 1 -mindepth 1 -type d)
do
cmake --build "$f" --target $2 --
done
-34
View File
@@ -1,34 +0,0 @@
#! /usr/bin/env bash
set -e
project=$(pwd)/
TARGET=$1
BUILD_TYPE=$2
if [[ $TARGET == windows ]]; then
toolchain="-DCMAKE_TOOLCHAIN_FILE=cmake/modules/Mingw.cmake"
elif [[ $TARGET == gba ]]; then
toolchain="-DCMAKE_TOOLCHAIN_FILE=cmake/modules/GBA.cmake -DOX_USE_STDLIB=OFF -DCMAKE_INSTALL_PREFIX=$DEVKITARM"
fi
if [[ $BUILD_TYPE == asan ]]; then
buildTypeArgs="-DUSE_ASAN=ON -DCMAKE_BUILD_TYPE=Debug"
buildDir="build/${TARGET}-asan"
elif [[ $BUILD_TYPE == debug ]]; then
buildTypeArgs="-DCMAKE_BUILD_TYPE=Debug"
buildDir="build/${TARGET}-debug"
else
buildTypeArgs="-DCMAKE_BUILD_TYPE=Release"
buildDir="build/${TARGET}-release"
fi
mkdir -p $buildDir
pushd $buildDir
cmake -DCMAKE_EXPORT_COMPILE_COMMANDS=ON \
-GNinja \
$buildTypeArgs \
$toolchain \
$project
popd
+27 -1
View File
@@ -1 +1,27 @@
add_subdirectory(ox)
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()
add_subdirectory(clargs)
add_subdirectory(claw)
add_subdirectory(event)
add_subdirectory(fs)
add_subdirectory(logconn)
add_subdirectory(mc)
add_subdirectory(model)
add_subdirectory(preloader)
add_subdirectory(std)
@@ -1,8 +1,13 @@
cmake_minimum_required(VERSION 3.10)
if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
# enable warnings
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunsafe-buffer-usage")
endif()
add_library(
OxClArgs
clargs.cpp
src/clargs.cpp
)
set_property(
@@ -22,11 +27,16 @@ target_link_libraries(
OxStd
)
target_include_directories(
OxClArgs PUBLIC
include
)
install(
FILES
clargs.hpp
DIRECTORY
include/ox
DESTINATION
include/ox/clargs
include
)
install(
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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,6 +9,7 @@
#pragma once
#include <ox/std/hashmap.hpp>
#include <ox/std/span.hpp>
#include <ox/std/string.hpp>
namespace ox {
@@ -22,6 +23,8 @@ class ClArgs {
public:
ClArgs(int argc, const char **args) noexcept;
ClArgs(ox::SpanView<const char*> args) noexcept;
[[nodiscard]]
bool getBool(ox::StringViewCR arg, bool defaultValue) const noexcept;
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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,27 +7,29 @@
*/
#include <ox/std/string.hpp>
#include "clargs.hpp"
#include <ox/clargs/clargs.hpp>
namespace ox {
ClArgs::ClArgs(int argc, const char **args) noexcept {
for (auto i = 0u; i < static_cast<unsigned>(argc); ++i) {
auto arg = String(args[i]);
ClArgs::ClArgs(int argc, const char **args) noexcept: ClArgs({args, static_cast<size_t>(argc)}) {}
ClArgs::ClArgs(ox::SpanView<const char*> args) noexcept {
for (auto i = 0u; i < args.size(); ++i) {
auto arg = StringView{args[i]};
if (arg[0] == '-') {
while (arg[0] == '-' && arg.len()) {
arg = arg.substr(1);
while (arg[0] == '-' && arg.size()) {
arg = substr(arg, 1);
}
m_bools[arg] = true;
// parse additional arguments
if (i < static_cast<unsigned>(argc) && args[i + 1]) {
auto val = String(args[i + 1]);
if (val.len() && val[i] != '-') {
if (i < args.size() && args[i + 1]) {
auto const val = StringView{args[i + 1]};
if (val.size() && val[0] != '-') {
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::strToInt(val); r.error == 0) {
m_ints[arg] = r.value;
}
++i;
@@ -38,32 +40,32 @@ ClArgs::ClArgs(int argc, const char **args) noexcept {
}
bool ClArgs::getBool(ox::StringViewCR arg, bool defaultValue) const noexcept {
auto [value, err] = m_ints.at(arg);
auto const [value, err] = m_ints.at(arg);
return !err ? *value : defaultValue;
}
String ClArgs::getString(ox::StringViewCR arg, ox::StringView defaultValue) const noexcept {
auto [value, err] = m_strings.at(arg);
auto const [value, err] = m_strings.at(arg);
return !err ? ox::String(*value) : ox::String(defaultValue);
}
int ClArgs::getInt(ox::StringViewCR arg, int defaultValue) const noexcept {
auto [value, err] = m_ints.at(arg);
auto const [value, err] = m_ints.at(arg);
return !err ? *value : defaultValue;
}
Result<bool> ClArgs::getBool(ox::StringViewCR arg) const noexcept {
oxRequire(out, m_bools.at(arg));
OX_REQUIRE(out, m_bools.at(arg));
return *out;
}
Result<String> ClArgs::getString(ox::StringViewCR argName) const noexcept {
oxRequire(out, m_strings.at(argName));
OX_REQUIRE(out, m_strings.at(argName));
return *out;
}
Result<int> ClArgs::getInt(ox::StringViewCR arg) const noexcept {
oxRequire(out, m_ints.at(arg));
OX_REQUIRE(out, m_ints.at(arg));
return *out;
}
@@ -1,8 +1,8 @@
add_library(
OxClaw
read.cpp
write.cpp
src/read.cpp
src/write.cpp
)
if(NOT MSVC)
@@ -27,7 +27,20 @@ target_link_libraries(
# )
#endif()
install(TARGETS OxClaw
target_include_directories(
OxClaw PUBLIC
include
)
install(
DIRECTORY
include/ox
DESTINATION
include
)
install(
TARGETS OxClaw
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -40,20 +40,19 @@ Result<BufferView> stripClawHeader(ox::BufferView buff) noexcept;
template<typename T>
Error readClaw(ox::BufferView buff, T &val) {
oxRequire(header, readClawHeader(buff));
OX_REQUIRE(header, readClawHeader(buff));
if (header.typeName != getModelTypeName<T>()) {
return OxError(Error_ClawTypeMismatch, "Claw Read: Type mismatch");
return ox::Error(Error_ClawTypeMismatch, "Claw Read: Type mismatch");
}
if (header.typeVersion != getModelTypeVersion<T>()) {
return OxError(Error_ClawTypeVersionMismatch, "Claw Read: Type Version mismatch");
return ox::Error(Error_ClawTypeVersionMismatch, "Claw Read: Type Version mismatch");
}
switch (header.fmt) {
case ClawFormat::Metal:
{
ox::BufferReader br({header.data, header.dataSize});
MetalClawReader reader(br);
ModelHandlerInterface handler(&reader);
return model(&handler, &val);
return model(reader.interface(), &val);
}
case ClawFormat::Organic:
{
@@ -65,15 +64,15 @@ Error readClaw(ox::BufferView buff, T &val) {
#endif
}
case ClawFormat::None:
return OxError(1);
return ox::Error(1);
}
return OxError(1);
return ox::Error(1);
}
template<typename T>
Result<T> readClaw(ox::BufferView buff) {
Result<T> val;
oxReturnError(readClaw(buff, val.value));
OX_RETURN_ERROR(readClaw(buff, val.value));
return val;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -39,7 +39,7 @@ struct TypeInfoCatcher {
}
constexpr Error field(...) noexcept {
return OxError(0);
return {};
}
static constexpr auto opType() {
@@ -76,21 +76,21 @@ template<typename T>
ox::Error writeClawHeader(Writer_c auto &writer, const T *t, ClawFormat fmt) noexcept {
switch (fmt) {
case ClawFormat::Metal:
oxReturnError(write(writer, "M2;"));
OX_RETURN_ERROR(write(writer, "M2;"));
break;
case ClawFormat::Organic:
oxReturnError(write(writer, "O1;"));
OX_RETURN_ERROR(write(writer, "O1;"));
break;
default:
return OxError(1);
return ox::Error(1);
}
oxReturnError(write(writer, detail::getTypeName(t)));
oxReturnError(writer.put(';'));
OX_RETURN_ERROR(write(writer, detail::getTypeName(t)));
OX_RETURN_ERROR(writer.put(';'));
const auto tn = detail::getTypeVersion(t);
if (tn > -1) {
oxReturnError(ox::writeItoa(tn, writer));
OX_RETURN_ERROR(ox::writeItoa(tn, writer));
}
oxReturnError(writer.put(';'));
OX_RETURN_ERROR(writer.put(';'));
return {};
}
@@ -102,19 +102,19 @@ Result<Buffer> writeClaw(
std::size_t buffReserveSz = 2 * units::KB) noexcept {
Buffer out(buffReserveSz);
BufferWriter bw(&out, 0);
oxReturnError(detail::writeClawHeader(bw, &t, fmt));
OX_RETURN_ERROR(detail::writeClawHeader(bw, &t, fmt));
#ifdef OX_USE_STDLIB
if (fmt == ClawFormat::Metal) {
oxReturnError(writeMC(bw, t));
OX_RETURN_ERROR(writeMC(bw, t));
} else if (fmt == ClawFormat::Organic) {
oxRequire(data, writeOC(t));
oxReturnError(bw.write(data.data(), data.size()));
OX_REQUIRE(data, writeOC(t));
OX_RETURN_ERROR(bw.write(data.data(), data.size()));
}
#else
if (fmt != ClawFormat::Metal) {
return OxError(1, "OC is not supported in this build");
return ox::Error(1, "OC is not supported in this build");
}
oxReturnError(writeMC(bw, t));
OX_RETURN_ERROR(writeMC(bw, t));
#endif
out.resize(bw.tellp());
return out;
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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,17 +8,17 @@
#include <ox/std/buffer.hpp>
#include "read.hpp"
#include <ox/claw/read.hpp>
namespace ox {
ox::Result<ox::StringView> readClawTypeId(ox::BufferView buff) noexcept {
Result<StringView> readClawTypeId(BufferView const 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");
return ox::Error(1, "Could not read Claw header");
}
auto const fmtSz = static_cast<std::size_t>(s1End - buffRaw) + 1;
buffRaw += fmtSz;
@@ -26,7 +26,7 @@ ox::Result<ox::StringView> readClawTypeId(ox::BufferView buff) noexcept {
outSz += fmtSz;
auto const s2End = ox::strchr(buffRaw, ';', buffLen);
if (!s2End) {
return OxError(2, "Could not read Claw header");
return ox::Error(2, "Could not read Claw header");
}
auto const s2Size = static_cast<std::size_t>(s2End - buffRaw) + 1;
buffRaw += s2Size;
@@ -34,7 +34,7 @@ ox::Result<ox::StringView> readClawTypeId(ox::BufferView buff) noexcept {
outSz += s2Size;
auto const s3End = ox::strchr(buffRaw, ';', buffLen) + 1;
if (!s3End) {
return OxError(3, "Could not read Claw header");
return ox::Error(3, "Could not read Claw header");
}
auto const s3Size = static_cast<std::size_t>(s3End - buffRaw);
buffRaw += s3Size;
@@ -43,12 +43,12 @@ ox::Result<ox::StringView> readClawTypeId(ox::BufferView buff) noexcept {
return {{buff.data() + fmtSz, outSz - fmtSz - 1}};
}
Result<ClawHeader> readClawHeader(ox::BufferView buff) noexcept {
Result<ClawHeader> readClawHeader(BufferView const 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");
return ox::Error(1, "Could not read Claw header");
}
auto const s1Size = static_cast<std::size_t>(s1End - buffRaw);
StringView const fmt(buffRaw, s1Size);
@@ -57,7 +57,7 @@ Result<ClawHeader> readClawHeader(ox::BufferView buff) noexcept {
auto const s2End = ox::strchr(buffRaw, ';', buffLen);
if (!s2End) {
return OxError(2, "Could not read Claw header");
return ox::Error(2, "Could not read Claw header");
}
auto const s2Size = static_cast<std::size_t>(s2End - buffRaw);
StringView const typeName(buffRaw, s2Size);
@@ -66,7 +66,7 @@ Result<ClawHeader> readClawHeader(ox::BufferView buff) noexcept {
auto const s3End = ox::strchr(buffRaw, ';', buffLen);
if (!s3End) {
return OxError(3, "Could not read Claw header");
return ox::Error(3, "Could not read Claw header");
}
auto const s3Size = static_cast<std::size_t>(s3End - buffRaw);
StringView const versionStr(buffRaw, s3Size);
@@ -78,53 +78,52 @@ Result<ClawHeader> readClawHeader(ox::BufferView buff) noexcept {
} else if (fmt == "O1") {
hdr.fmt = ClawFormat::Organic;
} else {
return OxError(4, "Claw format does not match any supported format/version combo");
return ox::Error(4, "Claw format does not match any supported format/version combo");
}
hdr.typeName = typeName;
std::ignore = ox::atoi(versionStr).copyTo(hdr.typeVersion);
std::ignore = ox::strToInt(versionStr).copyTo(hdr.typeVersion);
hdr.data = buffRaw;
hdr.dataSize = buffLen;
return hdr;
}
Result<BufferView> stripClawHeader(ox::BufferView buff) noexcept {
oxRequire(header, readClawHeader(buff));
Result<BufferView> stripClawHeader(BufferView const buff) noexcept {
OX_REQUIRE(header, readClawHeader(buff));
return {{header.data, header.dataSize}};
}
Result<ModelObject> readClaw(TypeStore &ts, BufferView buff) noexcept {
oxRequire(header, readClawHeader(buff));
OX_REQUIRE(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");
return ox::Error(3, "Could not load type descriptor");
}
ModelObject obj;
oxReturnError(obj.setType(t));
OX_RETURN_ERROR(obj.setType(t));
switch (header.fmt) {
case ClawFormat::Metal:
{
ox::BufferReader br({header.data, header.dataSize});
MetalClawReader reader(br);
ModelHandlerInterface handler(&reader);
oxReturnError(model(&handler, &obj));
OX_RETURN_ERROR(model(reader.interface(), &obj));
return obj;
}
case ClawFormat::Organic:
{
#ifdef OX_USE_STDLIB
OrganicClawReader reader({header.data, header.dataSize});
ModelHandlerInterface handler(&reader);
oxReturnError(model(&handler, &obj));
ModelHandlerInterface handler(reader);
OX_RETURN_ERROR(model(&handler, &obj));
return obj;
#else
break;
#endif
}
case ClawFormat::None:
return OxError(1);
return ox::Error(1);
}
return OxError(1);
return ox::Error(1);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -1,12 +1,12 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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 "write.hpp"
#include <ox/claw/write.hpp>
namespace ox::detail {
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -62,45 +62,45 @@ struct TestStruct {
template<typename T>
constexpr ox::Error model(T *io, ox::CommonPtrWith<TestUnion> auto *obj) {
oxReturnError(io->template setTypeInfo<TestUnion>());
oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int));
oxReturnError(io->fieldCString("String", &obj->String));
return OxError(0);
OX_RETURN_ERROR(io->template setTypeInfo<TestUnion>());
OX_RETURN_ERROR(io->field("Bool", &obj->Bool));
OX_RETURN_ERROR(io->field("Int", &obj->Int));
OX_RETURN_ERROR(io->fieldCString("String", &obj->String));
return ox::Error(0);
}
template<typename T>
constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStructNest> auto *obj) {
oxReturnError(io->template setTypeInfo<TestStructNest>());
oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int));
oxReturnError(io->field("String", &obj->String));
return OxError(0);
OX_RETURN_ERROR(io->template setTypeInfo<TestStructNest>());
OX_RETURN_ERROR(io->field("Bool", &obj->Bool));
OX_RETURN_ERROR(io->field("Int", &obj->Int));
OX_RETURN_ERROR(io->field("String", &obj->String));
return ox::Error(0);
}
template<typename T>
constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) {
oxReturnError(io->template setTypeInfo<TestStruct>());
oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int));
oxReturnError(io->field("Int1", &obj->Int1));
oxReturnError(io->field("Int2", &obj->Int2));
oxReturnError(io->field("Int3", &obj->Int3));
oxReturnError(io->field("Int4", &obj->Int4));
oxReturnError(io->field("Int5", &obj->Int5));
oxReturnError(io->field("Int6", &obj->Int6));
oxReturnError(io->field("Int7", &obj->Int7));
oxReturnError(io->field("Int8", &obj->Int8));
OX_RETURN_ERROR(io->template setTypeInfo<TestStruct>());
OX_RETURN_ERROR(io->field("Bool", &obj->Bool));
OX_RETURN_ERROR(io->field("Int", &obj->Int));
OX_RETURN_ERROR(io->field("Int1", &obj->Int1));
OX_RETURN_ERROR(io->field("Int2", &obj->Int2));
OX_RETURN_ERROR(io->field("Int3", &obj->Int3));
OX_RETURN_ERROR(io->field("Int4", &obj->Int4));
OX_RETURN_ERROR(io->field("Int5", &obj->Int5));
OX_RETURN_ERROR(io->field("Int6", &obj->Int6));
OX_RETURN_ERROR(io->field("Int7", &obj->Int7));
OX_RETURN_ERROR(io->field("Int8", &obj->Int8));
int unionIdx = 0;
if constexpr(T::opType() != ox::OpType::Reflect) {
unionIdx = obj->unionIdx;
}
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, unionIdx}));
oxReturnError(io->field("String", &obj->String));
oxReturnError(io->field("List", obj->List, 4));
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));
oxReturnError(io->field("Struct", &obj->Struct));
return OxError(0);
OX_RETURN_ERROR(io->field("Union", ox::UnionView{&obj->Union, unionIdx}));
OX_RETURN_ERROR(io->field("String", &obj->String));
OX_RETURN_ERROR(io->field("List", obj->List, 4));
OX_RETURN_ERROR(io->field("EmptyStruct", &obj->EmptyStruct));
OX_RETURN_ERROR(io->field("Struct", &obj->Struct));
return ox::Error(0);
}
static std::map<ox::StringView, ox::Error(*)()> tests = {
@@ -109,24 +109,24 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
"ClawHeaderReader",
[] {
constexpr auto hdr = ox::StringLiteral("O1;com.drinkingtea.ox.claw.test.Header;2;");
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.len() + 1});
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.size() + 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");
oxAssert(ch.typeVersion == 2, "Type version wrong");
return OxError(0);
return ox::Error(0);
}
},
{
"ClawHeaderReader2",
[] {
constexpr auto hdr = ox::StringLiteral("M2;com.drinkingtea.ox.claw.test.Header2;3;");
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.len() + 1});
auto [ch, err] = ox::readClawHeader({hdr.c_str(), hdr.size() + 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");
oxAssert(ch.typeVersion == 3, "Type version wrong");
return OxError(0);
return ox::Error(0);
}
},
{
@@ -134,8 +134,8 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
[] {
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);
OX_REQUIRE(actual, ox::readClawTypeId({hdr.data(), hdr.size() + 1}));
ox::expect(actual, expected);
return ox::Error{};
}
},
@@ -145,8 +145,8 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
// 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));
return OxError(0);
OX_RETURN_ERROR(ox::writeClaw(ts, ox::ClawFormat::Metal));
return ox::Error(0);
}
},
{
@@ -191,7 +191,7 @@ static std::map<ox::StringView, ox::Error(*)()> tests = {
oxAssert(testIn.Struct.String == testOut.Struct.String, "Struct.String value mismatch");
oxAssert(testIn.Struct.Bool == testOut.Struct.Bool, "Struct.Bool value mismatch");
return OxError(0);
return ox::Error(0);
}
},
}
+51
View File
@@ -0,0 +1,51 @@
add_library(
OxEvent
src/signal.cpp
)
if(NOT MSVC)
target_compile_options(OxEvent PRIVATE -Wsign-conversion)
target_compile_options(OxEvent PRIVATE -Wconversion)
endif()
if(NOT OX_BARE_METAL)
set_property(
TARGET
OxEvent
PROPERTY
POSITION_INDEPENDENT_CODE ON
)
endif()
target_compile_definitions(
OxEvent PUBLIC
$<$<BOOL:${OX_USE_STDLIB}>:OX_USE_STDLIB>
$<$<BOOL:${OX_NODEBUG}>:OX_NODEBUG>
)
target_link_libraries(
OxEvent PUBLIC
OxStd
)
target_include_directories(
OxEvent PUBLIC
include
)
install(
DIRECTORY
include/ox
DESTINATION
include
)
install(
TARGETS OxEvent
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
if(OX_RUN_TESTS)
add_subdirectory(test)
endif()
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -57,7 +57,7 @@ class Signal {
void call(Args... args) final {
if constexpr(detail::isError<decltype(f(args...))>::value) {
oxThrowError(f(args...));
OX_THROW_ERROR(f(args...));
} else {
f(args...);
}
@@ -76,7 +76,7 @@ class Signal {
void call(Args... args) final {
if constexpr(detail::isError<decltype((m_receiver->*(m_methodPtr))(args...))>::value) {
oxThrowError((m_receiver->*(m_methodPtr))(args...));
OX_THROW_ERROR((m_receiver->*(m_methodPtr))(args...));
} else {
f(args...);
}
@@ -107,7 +107,7 @@ class Signal {
void call(Args... args) final {
if constexpr(detail::isError<decltype((m_receiver->*(m_methodPtr))(args...))>::value) {
oxThrowError((m_receiver->*(m_methodPtr))(args...));
OX_THROW_ERROR((m_receiver->*(m_methodPtr))(args...));
} else {
(m_receiver->*(m_methodPtr))(args...);
}
@@ -122,7 +122,7 @@ class Signal {
}
};
mutable Vector<UniquePtr<BaseSlot>> m_slots;
mutable Vector<UPtr<BaseSlot>> m_slots;
public:
~Signal() noexcept;
@@ -143,6 +143,11 @@ class Signal {
Error disconnectObject(const void *receiver) const noexcept;
[[nodiscard]]
size_t connectionCnt() const noexcept {
return m_slots.size();
}
void emit(Args... args) const;
Error emitCheckError(Args... args) const noexcept;
@@ -193,11 +198,11 @@ Error Signal<Args...>::disconnectObject(const void *receiver) const noexcept {
for (auto i = 0u; i < m_slots.size(); ++i) {
const auto &slot = m_slots[i];
if (slot->receiver() == receiver) {
oxReturnError(m_slots.erase(i));
OX_RETURN_ERROR(m_slots.erase(i));
--i;
}
}
return OxError(1, "Signal::disconnectObject: Receiver was not found among this Signal's slots");
return ox::Error(1, "Signal::disconnectObject: Receiver was not found among this Signal's slots");
}
template<class... Args>
@@ -213,9 +218,9 @@ Error Signal<Args...>::emitCheckError(Args... args) const noexcept {
for (auto &f : m_slots) {
f->call(args...);
}
return OxError(0);
return {};
} catch (const ox::Exception &ex) {
return ox::Error(ex.file, ex.line, ex.errCode, ex.msg);
return ox::Error(ex.errCode, ex.msg, ex.src);
}
}
@@ -298,7 +303,7 @@ class Signal<Error(Args...)> {
}
};
mutable Vector<UniquePtr<BaseSlot>> m_slots;
mutable Vector<UPtr<BaseSlot>> m_slots;
public:
~Signal() noexcept;
@@ -319,6 +324,11 @@ class Signal<Error(Args...)> {
Error disconnectObject(const void *receiver) const noexcept;
[[nodiscard]]
size_t connectionCnt() const noexcept {
return m_slots.size();
}
void emit(Args... args) const noexcept;
Error emitCheckError(Args... args) const noexcept;
@@ -381,11 +391,11 @@ Error Signal<Error(Args...)>::disconnectObject(const void *receiver) const noexc
for (auto i = 0u; i < m_slots.size(); ++i) {
const auto &slot = m_slots[i];
if (slot->receiver() == receiver) {
oxReturnError(m_slots.erase(i));
OX_RETURN_ERROR(m_slots.erase(i));
--i;
}
}
return OxError(1, "Signal::disconnectObject: Receiver was not found among this Signal's slots");
return ox::Error(1, "Signal::disconnectObject: Receiver was not found among this Signal's slots");
}
template<class... Args>
@@ -398,9 +408,9 @@ void Signal<Error(Args...)>::emit(Args... args) const noexcept {
template<class... Args>
Error Signal<Error(Args...)>::emitCheckError(Args... args) const noexcept {
for (auto &f : m_slots) {
oxReturnError(f->call(ox::forward<Args>(args)...));
OX_RETURN_ERROR(f->call(ox::forward<Args>(args)...));
}
return OxError(0);
return {};
}
}
@@ -1,12 +1,12 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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 "signal.hpp"
#include <ox/event/signal.hpp>
namespace ox {
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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 @@ struct TestStruct: public ox::SignalHandler {
int value = 0;
ox::Error method(int i) noexcept {
value = i;
return OxError(0);
return ox::Error(0);
}
};
@@ -27,13 +27,13 @@ std::map<ox::StringView, std::function<ox::Error()>> tests = {
[] {
ox::Signal<ox::Error(int)> signal;
signal.connect([](int i) -> ox::Error {
return OxError(i != 5);
return ox::Error(i != 5);
});
TestStruct ts;
signal.connect(&ts, &TestStruct::method);
oxReturnError(signal.emitCheckError(5));
oxReturnError(OxError(ts.value != 5));
return OxError(0);
OX_RETURN_ERROR(signal.emitCheckError(5));
OX_RETURN_ERROR(ox::Error(ts.value != 5));
return ox::Error(0);
}
},
};
@@ -1,14 +1,16 @@
if(CMAKE_CXX_COMPILER_ID MATCHES ".*Clang")
# enable warnings
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wunsafe-buffer-usage")
endif()
add_library(
OxFS
ptrarith/nodebuffer.hpp
ptrarith/ptr.hpp
filestore/filestoretemplate.cpp
filesystem/filelocation.cpp
filesystem/pathiterator.cpp
filesystem/directory.cpp
filesystem/filesystem.cpp
filesystem/passthroughfs.cpp
src/filestore/filestoretemplate.cpp
src/filesystem/filelocation.cpp
src/filesystem/pathiterator.cpp
src/filesystem/directory.cpp
src/filesystem/filesystem.cpp
src/filesystem/passthroughfs.cpp
)
if(NOT MSVC)
@@ -29,10 +31,22 @@ target_link_libraries(
OxMetalClaw
)
target_include_directories(
OxFS PUBLIC
include
)
install(
DIRECTORY
include/ox
DESTINATION
include
)
if(NOT OX_BARE_METAL)
add_executable(
oxfs-tool
tool.cpp
src/tool.cpp
)
target_link_libraries(
@@ -48,29 +62,6 @@ if(NOT OX_BARE_METAL)
)
endif()
install(
FILES
filestore/filestoretemplate.hpp
DESTINATION
include/ox/fs/filestore
)
install(
FILES
filesystem/filesystem.hpp
filesystem/pathiterator.hpp
DESTINATION
include/ox/fs/filesystem
)
install(
FILES
ptrarith/nodebuffer.hpp
ptrarith/ptr.hpp
DESTINATION
include/ox/fs/ptrarith
)
install(
TARGETS
OxFS
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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,6 +10,8 @@
#include <ox/fs/ptrarith/nodebuffer.hpp>
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
using InodeId_t = uint64_t;
@@ -205,12 +207,12 @@ Error FileStoreTemplate<size_t>::format(void *buffer, std::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");
return OxError(1, "Could not read data section of FileStoreData");
return ox::Error(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");
return OxError(1, "Could not read data section of FileStoreData");
return ox::Error(1, "Could not read data section of FileStoreData");
}
new (data) FileStoreData;
return {};
@@ -221,24 +223,24 @@ Error FileStoreTemplate<size_t>::setSize(std::size_t size) {
if (m_buffSize >= size) {
return m_buffer->setSize(static_cast<size_t>(size));
}
return OxError(1);
return ox::Error(1);
}
template<typename size_t>
Error FileStoreTemplate<size_t>::incLinks(uint64_t id) {
oxRequireM(item, find(static_cast<size_t>(id)).validate());
OX_REQUIRE_M(item, find(static_cast<size_t>(id)).validate());
++item->links;
return OxError(0);
return {};
}
template<typename size_t>
Error FileStoreTemplate<size_t>::decLinks(uint64_t id) {
oxRequireM(item, find(static_cast<size_t>(id)).validate());
OX_REQUIRE_M(item, find(static_cast<size_t>(id)).validate());
--item->links;
if (item->links == 0) {
oxReturnError(remove(item));
OX_RETURN_ERROR(remove(item));
}
return OxError(0);
return {};
}
template<typename size_t>
@@ -247,7 +249,7 @@ Error FileStoreTemplate<size_t>::write(uint64_t id64, const void *data, FsSize_t
oxTracef("ox.fs.FileStoreTemplate.write", "Attempting to write to inode {}", id);
auto existing = find(id);
if (!canWrite(existing, dataSize)) {
oxReturnError(compact());
OX_RETURN_ERROR(compact());
existing = find(id);
}
@@ -267,7 +269,7 @@ Error FileStoreTemplate<size_t>::write(uint64_t id64, const void *data, FsSize_t
// if first malloc failed, compact and try again
if (!dest.valid()) {
oxTrace("ox.fs.FileStoreTemplate.write", "Allocation failed, compacting");
oxReturnError(compact());
OX_RETURN_ERROR(compact());
dest = m_buffer->malloc(dataSize).value;
}
if (dest.valid()) {
@@ -296,16 +298,16 @@ Error FileStoreTemplate<size_t>::write(uint64_t id64, const void *data, FsSize_t
dest->id.get(), dest.offset(), destData.size());
fsData->rootNode = dest.offset();
oxTracef("ox.fs.FileStoreTemplate.write", "Root inode: {}", dest->id.get());
return OxError(0);
return {};
}
} else {
oxTrace("ox.fs.FileStoreTemplate.write.fail", "Could not place item due to absence of FileStore header.");
}
}
}
oxReturnError(m_buffer->free(dest));
OX_RETURN_ERROR(m_buffer->free(dest));
}
return OxError(1);
return ox::Error(1);
}
template<typename size_t>
@@ -320,7 +322,7 @@ Error FileStoreTemplate<size_t>::read(uint64_t id, void *out, FsSize_t outSize,
// error check
if (!src.valid()) {
oxTracef("ox.fs.FileStoreTemplate.read.fail", "Could not find requested item: {}", id);
return OxError(1, "Could not find requested item");
return ox::Error(1, "Could not find requested item");
}
auto srcData = m_buffer->template dataOf<uint8_t>(src);
@@ -333,7 +335,7 @@ Error FileStoreTemplate<size_t>::read(uint64_t id, void *out, FsSize_t outSize,
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, "Invalid inode");
return ox::Error(1, "Invalid inode");
}
ox::memcpy(out, srcData, srcData.size());
@@ -351,7 +353,7 @@ Error FileStoreTemplate<size_t>::read(uint64_t id, FsSize_t readStart, FsSize_t
// error check
if (!src.valid()) {
oxTracef("ox.fs.FileStoreTemplate.read.fail", "Could not find requested item: {}", id);
return OxError(1);
return ox::Error(1);
}
auto srcData = m_buffer->template dataOf<uint8_t>(src);
@@ -364,7 +366,7 @@ Error FileStoreTemplate<size_t>::read(uint64_t id, FsSize_t readStart, FsSize_t
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);
return ox::Error(1);
}
ox::memcpy(out, srcData.get() + readStart, readSize);
@@ -384,7 +386,7 @@ Error FileStoreTemplate<size_t>::read(uint64_t id, FsSize_t readStart,
// error check
if (!src.valid()) {
oxTracef("ox.fs.FileStoreTemplate.read.fail", "Could not find requested item: {}", id);
return OxError(1);
return ox::Error(1);
}
auto srcData = m_buffer->template dataOf<uint8_t>(src);
@@ -397,7 +399,7 @@ Error FileStoreTemplate<size_t>::read(uint64_t id, FsSize_t readStart,
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);
return ox::Error(1);
}
ox::memcpy(out, srcData.get() + readStart, readSize);
@@ -420,30 +422,30 @@ ptrarith::Ptr<uint8_t, std::size_t> FileStoreTemplate<size_t>::read(uint64_t id)
template<typename size_t>
Error FileStoreTemplate<size_t>::resize() {
oxReturnError(compact());
OX_RETURN_ERROR(compact());
const auto newSize = static_cast<std::size_t>(size() - available());
oxTracef("ox.fs.FileStoreTemplate.resize", "resize to: {}", newSize);
oxReturnError(m_buffer->setSize(newSize));
OX_RETURN_ERROR(m_buffer->setSize(newSize));
oxTracef("ox.fs.FileStoreTemplate.resize", "resized to: {}", m_buffer->size());
return OxError(0);
return {};
}
template<typename size_t>
Error FileStoreTemplate<size_t>::resize(std::size_t size, void *newBuff) {
if (m_buffer->size() > size) {
return OxError(1);
return ox::Error{1, "new buffer is too small for existing data"};
}
m_buffSize = static_cast<size_t>(size);
if (newBuff) {
m_buffer = reinterpret_cast<Buffer*>(newBuff);
oxReturnError(m_buffer->setSize(static_cast<size_t>(size)));
m_buffer = static_cast<Buffer*>(newBuff);
OX_RETURN_ERROR(m_buffer->setSize(static_cast<size_t>(size)));
}
return OxError(0);
return {};
}
template<typename size_t>
Result<StatInfo> FileStoreTemplate<size_t>::stat(uint64_t id) const {
oxRequire(inode, find(static_cast<size_t>(id)).validate());
OX_REQUIRE(inode, find(static_cast<size_t>(id)).validate());
return StatInfo {
id,
inode->links,
@@ -475,16 +477,16 @@ char *FileStoreTemplate<size_t>::buff() {
template<typename size_t>
Error FileStoreTemplate<size_t>::walk(Error(*cb)(uint8_t, uint64_t, uint64_t)) {
for (auto i = m_buffer->iterator(); i.valid(); i.next()) {
oxReturnError(cb(i->fileType, i.ptr().offset(), i.ptr().end()));
OX_RETURN_ERROR(cb(i->fileType, i.ptr().offset(), i.ptr().end()));
}
return OxError(0);
return {};
}
template<typename size_t>
Result<typename FileStoreTemplate<size_t>::InodeId_t> FileStoreTemplate<size_t>::generateInodeId() {
auto fsData = fileStoreData();
if (!fsData) {
return OxError(1);
return ox::Error(1);
}
for (auto i = 0; i < 100; i++) {
auto inode = static_cast<typename FileStoreTemplate<size_t>::InodeId_t>(fsData->random.gen() % MaxValue<InodeId_t>);
@@ -492,7 +494,7 @@ Result<typename FileStoreTemplate<size_t>::InodeId_t> FileStoreTemplate<size_t>:
return inode;
}
}
return OxError(2);
return ox::Error(2);
}
template<typename size_t>
@@ -501,10 +503,10 @@ Error FileStoreTemplate<size_t>::compact() {
return m_buffer->compact([this, &isFirstItem](uint64_t oldAddr, ItemPtr item) -> Error {
if (isFirstItem) {
isFirstItem = false;
return OxError(0);
return {};
}
if (!item.valid()) {
return OxError(1);
return ox::Error(1);
}
oxTracef("ox.fs.FileStoreTemplate.compact.moveItem", "Moving Item: {} from {} to {}", item->id.get(), oldAddr, item.offset());
// update rootInode if this is it
@@ -522,7 +524,7 @@ Error FileStoreTemplate<size_t>::compact() {
parent->right = item;
}
}
return OxError(0);
return {};
});
}
@@ -542,15 +544,15 @@ template<typename size_t>
Error FileStoreTemplate<size_t>::placeItem(ItemPtr item) {
auto fsData = fileStoreData();
if (!fsData) {
return OxError(1);
return ox::Error(1);
}
oxRequireM(root, m_buffer->ptr(fsData->rootNode).validate());
OX_REQUIRE_M(root, m_buffer->ptr(fsData->rootNode).validate());
if (root->id == item->id) {
fsData->rootNode = item;
item->left = root->left;
item->right = root->right;
oxTracef("ox.fs.FileStoreTemplate.placeItem", "Overwrote Root Item: {}", item->id.get());
return OxError(0);
return {};
} else {
return placeItem(root, item);
}
@@ -560,7 +562,7 @@ 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.");
return OxError(2);
return ox::Error(2);
}
if (item->id > root->id) {
auto right = m_buffer->ptr(root->right);
@@ -571,7 +573,7 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr root, ItemPtr item, int depth
item->right = right->right;
}
oxTracef("ox.fs.FileStoreTemplate.placeItem", "Placed Item: {}", item->id.get());
return OxError(0);
return {};
} else {
return placeItem(right, item, depth + 1);
}
@@ -584,13 +586,13 @@ Error FileStoreTemplate<size_t>::placeItem(ItemPtr root, ItemPtr item, int depth
item->right = left->right;
}
oxTracef("ox.fs.FileStoreTemplate.placeItem", "Placed Item: {}", item->id.get());
return OxError(0);
return {};
} else {
return placeItem(left, item, depth + 1);
}
} else {
oxTrace("ox.fs.FileStoreTemplate.placeItem.fail", "Cannot insert an item on itself.");
return OxError(1, "Cannot insert an item on itself.");
return ox::Error(1, "Cannot insert an item on itself.");
}
}
@@ -598,9 +600,9 @@ template<typename size_t>
Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr item) {
auto fsData = fileStoreData();
if (!fsData) {
return OxError(1);
return ox::Error(1);
}
oxRequireM(root, m_buffer->ptr(fsData->rootNode).validate());
OX_REQUIRE_M(root, m_buffer->ptr(fsData->rootNode).validate());
if (root->id == item->id) {
item->left = root->left;
item->right = root->right;
@@ -622,7 +624,7 @@ Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr item) {
} else {
fsData->rootNode = 0;
}
return OxError(0);
return {};
} else {
return unplaceItem(root, item);
}
@@ -632,7 +634,7 @@ 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.");
return OxError(1, "Excessive recursion depth, stopping before stack overflow.");
return ox::Error(1, "Excessive recursion depth, stopping before stack overflow.");
}
if (item->id > root->id) {
auto right = m_buffer->ptr(root->right);
@@ -651,25 +653,25 @@ Error FileStoreTemplate<size_t>::unplaceItem(ItemPtr root, ItemPtr item, int dep
return unplaceItem(left, item, depth + 1);
}
} else {
return OxError(1);
return ox::Error(1);
}
if (item->right) {
oxReturnError(placeItem(m_buffer->ptr(item->right)));
OX_RETURN_ERROR(placeItem(m_buffer->ptr(item->right)));
}
if (item->left) {
oxReturnError(placeItem(m_buffer->ptr(item->left)));
OX_RETURN_ERROR(placeItem(m_buffer->ptr(item->left)));
}
return OxError(0);
return {};
}
template<typename size_t>
Error FileStoreTemplate<size_t>::remove(ItemPtr item) {
if (item.valid()) {
oxReturnError(unplaceItem(item));
oxReturnError(m_buffer->free(item));
return OxError(0);
OX_RETURN_ERROR(unplaceItem(item));
OX_RETURN_ERROR(m_buffer->free(item));
return {};
}
return OxError(1);
return ox::Error(1);
}
template<typename size_t>
@@ -771,3 +773,5 @@ using FileStore16 = FileStoreTemplate<uint16_t>;
using FileStore32 = FileStoreTemplate<uint32_t>;
}
OX_CLANG_NOWARN_END
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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,8 @@
#include "types.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
template<typename InodeId_t>
@@ -50,10 +52,10 @@ struct OX_PACKED DirectoryEntry {
if (d.valid()) {
d->inode = inode;
auto const maxStrSz = bufferSize - 1 - sizeof(*this);
ox::strncpy(d->name, name.data(), ox::min(maxStrSz, name.len()));
ox::strncpy(d->name, name.data(), ox::min(maxStrSz, name.size()));
return {};
}
return OxError(1);
return ox::Error(1);
}
ptrarith::Ptr<DirectoryEntryData, InodeId_t> data() noexcept {
@@ -139,11 +141,11 @@ 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);
oxReturnError(m_fs.write(m_inodeId, nullptr, Size, static_cast<uint8_t>(FileType::Directory)));
OX_RETURN_ERROR(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()) {
m_size = 0;
return OxError(1);
return ox::Error(1);
}
new (buff) Buffer(Size);
m_size = Size;
@@ -156,21 +158,21 @@ Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents) {
oxTrace("ox.fs.Directory.mkdir", path.fullPath());
// determine if already exists
ox::StringView name;
oxReturnError(path.get(name));
OX_RETURN_ERROR(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,
// return an error
if (!parents && path.hasNext()) {
return OxError(1);
return ox::Error(1);
}
childInode = m_fs.generateInodeId();
oxTracef("ox.fs.Directory.mkdir", "Generated Inode ID: {}", childInode.value);
oxLogError(childInode.error);
oxReturnError(childInode.error);
OX_RETURN_ERROR(childInode.error);
// initialize the directory
Directory<FileStore, InodeId_t> child(m_fs, childInode.value);
oxReturnError(child.init());
OX_RETURN_ERROR(child.init());
auto err = write(PathIterator(name), childInode.value);
if (err) {
oxLogError(err);
@@ -181,7 +183,7 @@ Error Directory<FileStore, InodeId_t>::mkdir(PathIterator path, bool parents) {
}
Directory<FileStore, InodeId_t> child(m_fs, childInode.value);
if (path.hasNext()) {
oxReturnError(child.mkdir(path.next(), parents));
OX_RETURN_ERROR(child.mkdir(path.next(), parents));
}
}
return {};
@@ -194,45 +196,45 @@ Error Directory<FileStore, InodeId_t>::write(PathIterator path, uint64_t inode64
if (path.next().hasNext()) { // not yet at target directory, recurse to next one
oxTracef("ox.fs.Directory.write", "Attempting to write to next sub-Directory: {} of {}",
name, path.fullPath());
oxReturnError(path.get(name));
oxRequire(nextChild, findEntry(name));
OX_RETURN_ERROR(path.get(name));
OX_REQUIRE(nextChild, findEntry(name));
oxTracef("ox.fs.Directory.write", "{}: {}", name, nextChild);
if (nextChild) {
return Directory(m_fs, nextChild).write(path.next(), inode);
} else {
oxTracef("ox.fs.Directory.write", "{} not found and not allowed to create it.", name);
return OxError(1, "File not found and not allowed to create it.");
return ox::Error(1, "File not found and not allowed to create it.");
}
} else {
oxTrace("ox.fs.Directory.write", path.fullPath());
oxReturnError(path.next(name));
OX_RETURN_ERROR(path.next(name));
// insert the new entry on this directory
// get the name
// find existing version of directory
oxTracef("ox.fs.Directory.write", "Searching for directory inode {}", m_inodeId);
oxRequire(oldStat, m_fs.stat(m_inodeId));
OX_REQUIRE(oldStat, m_fs.stat(m_inodeId));
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");
return OxError(1, "Could not read existing version of Directory");
return ox::Error(1, "Could not read existing version of Directory");
}
const auto pathSize = name.len() + 1;
const auto pathSize = name.size() + 1;
const auto entryDataSize = DirectoryEntry<InodeId_t>::DirectoryEntryData::spaceNeeded(pathSize);
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");
return OxError(1, "Could not allocate memory for copy of Directory");
return ox::Error(1, "Could not allocate memory for copy of Directory");
}
oxReturnError(cpy->setSize(newSize));
OX_RETURN_ERROR(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");
return OxError(1, "Could not allocate memory for new directory entry");
return ox::Error(1, "Could not allocate memory for new directory entry");
}
oxTracef("ox.fs.Directory.write", "Attempting to write Directory entry: {}", name);
oxReturnError(val->init(inode, name, val.size()));
OX_RETURN_ERROR(val->init(inode, name, val.size()));
return m_fs.write(m_inodeId, cpy.get(), cpy->size(), static_cast<uint8_t>(FileType::Directory));
}
}
@@ -240,7 +242,7 @@ Error Directory<FileStore, InodeId_t>::write(PathIterator path, uint64_t inode64
template<typename FileStore, typename InodeId_t>
Error Directory<FileStore, InodeId_t>::remove(PathIterator path) noexcept {
ox::StringView name;
oxReturnError(path.get(name));
OX_RETURN_ERROR(path.get(name));
oxTrace("ox.fs.Directory.remove", name);
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
if (buff.valid()) {
@@ -249,7 +251,7 @@ Error Directory<FileStore, InodeId_t>::remove(PathIterator path) noexcept {
auto data = i->data();
if (data.valid()) {
if (name == data->name) {
oxReturnError(buff->free(i));
OX_RETURN_ERROR(buff->free(i));
}
} else {
oxTrace("ox.fs.Directory.remove", "INVALID DIRECTORY ENTRY");
@@ -257,7 +259,7 @@ Error Directory<FileStore, InodeId_t>::remove(PathIterator path) noexcept {
}
} else {
oxTrace("ox.fs.Directory.remove.fail", "Could not find directory buffer");
return OxError(1, "Could not find directory buffer");
return ox::Error(1, "Could not find directory buffer");
}
return {};
}
@@ -269,13 +271,13 @@ Error Directory<FileStore, InodeId_t>::ls(F cb) noexcept {
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
if (!buff.valid()) {
oxTrace("ox.fs.Directory.ls.fail", "Could not directory buffer");
return OxError(1, "Could not directory buffer");
return ox::Error(1, "Could not 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));
OX_RETURN_ERROR(cb(data->name, data->inode));
} else {
oxTrace("ox.fs.Directory.ls", "INVALID DIRECTORY ENTRY");
}
@@ -289,7 +291,7 @@ Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::findEntry
auto buff = m_fs.read(m_inodeId).template to<Buffer>();
if (!buff.valid()) {
oxTrace("ox.fs.Directory.findEntry.fail", "Could not findEntry directory buffer");
return OxError(2, "Could not findEntry directory buffer");
return ox::Error(2, "Could not findEntry directory buffer");
}
oxTracef("ox.fs.Directory.findEntry", "Found directory buffer, size: {}", buff.size());
for (auto i = buff->iterator(); i.valid(); i.next()) {
@@ -305,15 +307,15 @@ Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::findEntry
}
}
oxTrace("ox.fs.Directory.findEntry.fail", "Entry not present");
return OxError(1, "Entry not present");
return ox::Error(1, "Entry not present");
}
template<typename FileStore, typename InodeId_t>
Result<typename FileStore::InodeId_t> Directory<FileStore, InodeId_t>::find(PathIterator path) const noexcept {
// determine if already exists
ox::StringView name;
oxReturnError(path.get(name));
oxRequire(v, findEntry(name));
OX_RETURN_ERROR(path.get(name));
OX_REQUIRE(v, findEntry(name));
// recurse if not at end of path
if (auto p = path.next(); p.valid()) {
Directory dir(m_fs, v);
@@ -333,3 +335,5 @@ using Directory16 = Directory<FileStore16, uint16_t>;
using Directory32 = Directory<FileStore32, uint32_t>;
}
OX_CLANG_NOWARN_END
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -13,6 +13,8 @@
#include <ox/model/typenamecatcher.hpp>
#include <ox/model/types.hpp>
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
enum class FileAddressType: int8_t {
@@ -22,9 +24,6 @@ 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>
@@ -87,7 +86,7 @@ class FileAddress {
case FileAddressType::Inode:
return m_data.inode;
default:
return OxError(1);
return ox::Error(1);
}
}
@@ -98,7 +97,7 @@ class FileAddress {
case FileAddressType::ConstPath:
return ox::CStringView(m_data.constPath);
default:
return OxError(1);
return ox::Error(1);
}
}
@@ -152,31 +151,33 @@ constexpr const char *getModelTypeName<FileAddress>() noexcept {
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));
OX_RETURN_ERROR(h->template setTypeInfo<FileAddress::Data>());
OX_RETURN_ERROR(h->fieldCString("path", &obj->path));
OX_RETURN_ERROR(h->fieldCString("constPath", &obj->path));
OX_RETURN_ERROR(h->field("inode", &obj->inode));
return {};
}
template<typename T>
constexpr Error model(T *h, CommonPtrWith<FileAddress> auto *fa) noexcept {
oxReturnError(h->template setTypeInfo<FileAddress>());
OX_RETURN_ERROR(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)));
OX_RETURN_ERROR(h->field("type", &type));
OX_RETURN_ERROR(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));
OX_RETURN_ERROR(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))));
OX_RETURN_ERROR(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))));
OX_RETURN_ERROR(h->field("type", &type));
OX_RETURN_ERROR(h->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
}
return {};
}
}
OX_CLANG_NOWARN_END
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -20,7 +20,7 @@
namespace ox {
namespace detail {
static inline void fsBuffFree(char *buff) noexcept {
inline void fsBuffFree(char *buff) noexcept {
safeDelete(buff);
}
}
@@ -41,25 +41,45 @@ class FileSystem {
Error read(const FileAddress &addr, void *buffer, std::size_t size) noexcept;
Result<Buffer> read(FileAddress const &addr, size_t size) noexcept;
Result<Buffer> read(StringViewCR path, size_t size) noexcept;
Result<Buffer> read(const FileAddress &addr) noexcept;
Result<Buffer> read(StringViewCR path) noexcept;
inline Error read(StringViewCR path, void *buffer, std::size_t buffSize) noexcept {
Error read(StringViewCR path, void *buffer, std::size_t buffSize) noexcept {
return readFilePath(path, buffer, buffSize);
}
inline Error read(uint64_t inode, void *buffer, std::size_t buffSize) noexcept {
Error read(uint64_t inode, void *buffer, std::size_t buffSize) noexcept {
return readFileInode(inode, buffer, buffSize);
}
Error read(const FileAddress &addr, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept;
Error read(
FileAddress const &addr,
size_t readStart,
size_t readSize,
void *buffer,
size_t *size) noexcept;
/**
*
* @param path
* @param readStart
* @param readSize
* @param buff
* @return error or number of bytes read
*/
Result<size_t> read(
StringViewCR path, size_t readStart, size_t readSize, ox::Span<char> buff) noexcept;
virtual Result<Vector<String>> ls(StringViewCR dir) const noexcept = 0;
virtual Error remove(StringViewCR path, bool recursive) noexcept = 0;
Error remove(const FileAddress &addr, bool recursive = false) noexcept;
Error remove(StringViewCR path, bool recursive = false) noexcept {
return removePath(path, recursive);
}
virtual Error resize(uint64_t size, void *buffer) noexcept = 0;
@@ -67,7 +87,7 @@ class FileSystem {
return writeFilePath(path, buffer, size, FileType::NormalFile);
}
Error write(StringViewCR path, ox::Span<char> const&buff) noexcept {
Error write(StringViewCR path, ox::SpanView<char> const&buff) noexcept {
return write(path, buff.data(), buff.size(), FileType::NormalFile);
}
@@ -75,42 +95,42 @@ class FileSystem {
return write(inode, buffer, size, FileType::NormalFile);
}
Error write(uint64_t inode, ox::Span<char> const&buff) noexcept {
Error write(uint64_t inode, ox::SpanView<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(StringViewCR path, const void *buffer, uint64_t size, FileType fileType) noexcept {
Error write(StringViewCR path, const void *buffer, uint64_t size, FileType fileType) noexcept {
return writeFilePath(path, buffer, size, fileType);
}
inline Error write(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept {
Error write(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept {
return writeFileInode(inode, buffer, size, fileType);
}
inline Result<FileStat> stat(uint64_t inode) const noexcept {
Result<FileStat> stat(uint64_t inode) const noexcept {
return statInode(inode);
}
inline Result<FileStat> stat(StringViewCR path) const noexcept {
Result<FileStat> stat(StringViewCR path) const noexcept {
return statPath(path);
}
Result<FileStat> stat(const FileAddress &addr) const noexcept;
[[nodiscard]]
inline bool exists(uint64_t inode) const noexcept {
bool exists(uint64_t inode) const noexcept {
return statInode(inode).ok();
}
[[nodiscard]]
inline bool exists(ox::StringView path) const noexcept {
bool exists(ox::StringView path) const noexcept {
return statPath(path).ok();
}
[[nodiscard]]
inline bool exists(FileAddress const&addr) const noexcept {
bool exists(FileAddress const&addr) const noexcept {
return stat(addr).ok();
}
@@ -140,7 +160,12 @@ class FileSystem {
virtual Error readFileInode(uint64_t inode, void *buffer, std::size_t size) noexcept = 0;
virtual Error readFileInodeRange(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept = 0;
virtual Error readFilePathRange(
StringViewCR path, size_t readStart, size_t readSize, void *buffer, size_t *buffSize) noexcept = 0;
virtual Error readFileInodeRange(uint64_t inode, size_t readStart, size_t readSize, void *buffer, size_t *size) noexcept = 0;
virtual Error removePath(StringViewCR path, bool recursive) noexcept = 0;
virtual Error writeFilePath(StringViewCR path, const void *buffer, uint64_t size, FileType fileType) noexcept = 0;
@@ -152,11 +177,11 @@ class MemFS: public FileSystem {
public:
Result<const char*> directAccess(const FileAddress &addr) const noexcept;
inline Result<const char*> directAccess(StringViewCR path) const noexcept {
Result<const char*> directAccess(StringViewCR path) const noexcept {
return directAccessPath(path);
}
inline Result<const char*> directAccess(uint64_t inode) const noexcept {
Result<const char*> directAccess(uint64_t inode) const noexcept {
return directAccessInode(inode);
}
@@ -209,6 +234,11 @@ class FileSystemTemplate: public MemFS {
Error readFileInodeRange(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept override;
Error readFilePathRange(
StringViewCR path, size_t readStart, size_t readSize, void *buffer, size_t *buffSize) noexcept override;
Error removePath(StringViewCR path, bool recursive) noexcept override;
Result<const char*> directAccessInode(uint64_t) const noexcept override;
Result<Vector<String>> ls(StringViewCR dir) const noexcept override;
@@ -216,8 +246,6 @@ class FileSystemTemplate: public MemFS {
template<typename F>
Error ls(StringViewCR path, F cb) const;
Error remove(StringViewCR path, bool recursive) noexcept override;
/**
* Resizes FileSystem to minimum possible size.
*/
@@ -284,69 +312,69 @@ 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, static_cast<size_t>(buffSize)));
OX_RETURN_ERROR(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);
oxReturnError(rootDir.init());
OX_RETURN_ERROR(rootDir.init());
FileSystemData fd;
fd.rootDirInode = rootDirInode;
oxTracef("ox.fs.FileSystemTemplate.format", "rootDirInode: {}", fd.rootDirInode.get());
oxReturnError(fs.write(InodeFsData, &fd, sizeof(fd)));
OX_RETURN_ERROR(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");
return OxError(1);
return ox::Error(1);
}
return OxError(0);
return {};
}
template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::mkdir(StringViewCR path, bool recursive) noexcept {
oxTracef("ox.fs.FileSystemTemplate.mkdir", "path: {}, recursive: {}", path, recursive);
oxRequireM(rootDir, this->rootDir());
OX_REQUIRE_M(rootDir, this->rootDir());
return rootDir.mkdir(path, recursive);
}
template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::move(StringViewCR src, StringViewCR dest) noexcept {
oxRequire(fd, fileSystemData());
OX_REQUIRE(fd, fileSystemData());
Directory rootDir(m_fs, fd.rootDirInode);
oxRequireM(inode, rootDir.find(src));
oxReturnError(rootDir.write(dest, inode));
oxReturnError(rootDir.remove(src));
return OxError(0);
OX_REQUIRE_M(inode, rootDir.find(src));
OX_RETURN_ERROR(rootDir.write(dest, inode));
OX_RETURN_ERROR(rootDir.remove(src));
return {};
}
template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::readFilePath(StringViewCR path, void *buffer, std::size_t buffSize) noexcept {
oxTrace("ox.fs.FileSystemTemplate.readFilePath", path);
oxRequire(fd, fileSystemData());
OX_REQUIRE(fd, fileSystemData());
Directory rootDir(m_fs, fd.rootDirInode);
oxRequire(s, stat(path));
OX_REQUIRE(s, stat(path));
if (s.size > buffSize) {
return OxError(1, "Buffer to small to load file");
return ox::Error(1, "Buffer to small to load file");
}
return readFileInodeRange(s.inode, 0, static_cast<size_t>(s.size), buffer, &buffSize);
}
template<typename FileStore, typename Directory>
Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccessPath(StringViewCR path) const noexcept {
oxRequire(fd, fileSystemData());
OX_REQUIRE(fd, fileSystemData());
Directory rootDir(m_fs, fd.rootDirInode);
oxRequire(inode, rootDir.find(path));
OX_REQUIRE(inode, rootDir.find(path));
return directAccessInode(inode);
}
template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::readFileInode(uint64_t inode, void *buffer, std::size_t buffSize) noexcept {
oxTracef("ox.fs.FileSystemTemplate.readFileInode", "{}", inode);
oxRequire(s, stat(inode));
OX_REQUIRE(s, stat(inode));
if (s.size > buffSize) {
return OxError(1, "Buffer to small to load file");
return ox::Error(1, "Buffer to small to load file");
}
return readFileInodeRange(inode, 0, static_cast<size_t>(s.size), buffer, &buffSize);
}
@@ -357,39 +385,18 @@ Error FileSystemTemplate<FileStore, Directory>::readFileInodeRange(uint64_t inod
}
template<typename FileStore, typename Directory>
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");
}
return reinterpret_cast<char*>(data.get());
Error FileSystemTemplate<FileStore, Directory>::readFilePathRange(
StringViewCR path, size_t readStart, size_t readSize, void *buffer, size_t *buffSize) noexcept {
OX_REQUIRE(s, stat(path));
return readFileInodeRange(s.inode, readStart, readSize, buffer, buffSize);
}
template<typename FileStore, typename Directory>
Result<Vector<String>> FileSystemTemplate<FileStore, Directory>::ls(StringViewCR path) const noexcept {
Vector<String> out;
oxReturnError(ls(path, [&out](StringViewCR name, typename FileStore::InodeId_t) {
out.emplace_back(name);
return OxError(0);
}));
return out;
}
template<typename FileStore, typename Directory>
template<typename F>
Error FileSystemTemplate<FileStore, Directory>::ls(StringViewCR path, F cb) const {
oxTracef("ox.fs.FileSystemTemplate.ls", "path: {}", path);
oxRequire(s, stat(path));
Directory dir(m_fs, s.inode);
return dir.ls(cb);
}
template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::remove(StringViewCR path, bool recursive) noexcept {
oxRequire(fd, fileSystemData());
Error FileSystemTemplate<FileStore, Directory>::removePath(StringViewCR path, bool recursive) noexcept {
OX_REQUIRE(fd, fileSystemData());
Directory rootDir(m_fs, fd.rootDirInode);
oxRequire(inode, rootDir.find(path));
oxRequire(st, statInode(inode));
OX_REQUIRE(inode, rootDir.find(path));
OX_REQUIRE(st, statInode(inode));
if (st.fileType == FileType::NormalFile || recursive) {
if (auto err = rootDir.remove(path)) {
// removal failed, try putting the index back
@@ -398,9 +405,37 @@ Error FileSystemTemplate<FileStore, Directory>::remove(StringViewCR path, bool r
}
} else {
oxTrace("FileSystemTemplate.remove.fail", "Tried to remove directory without recursive setting.");
return OxError(1);
return ox::Error(1);
}
return OxError(0);
return {};
}
template<typename FileStore, typename Directory>
Result<const char*> FileSystemTemplate<FileStore, Directory>::directAccessInode(uint64_t inode) const noexcept {
auto data = m_fs.read(inode);
if (!data.valid()) {
return ox::Error(1, "Data not valid");
}
return reinterpret_cast<char*>(data.get());
}
template<typename FileStore, typename Directory>
Result<Vector<String>> FileSystemTemplate<FileStore, Directory>::ls(StringViewCR path) const noexcept {
Vector<String> out;
OX_RETURN_ERROR(ls(path, [&out](StringViewCR name, typename FileStore::InodeId_t) {
out.emplace_back(name);
return ox::Error{};
}));
return out;
}
template<typename FileStore, typename Directory>
template<typename F>
Error FileSystemTemplate<FileStore, Directory>::ls(StringViewCR path, F cb) const {
oxTracef("ox.fs.FileSystemTemplate.ls", "path: {}", path);
OX_REQUIRE(s, stat(path));
Directory dir(m_fs, s.inode);
return dir.ls(cb);
}
template<typename FileStore, typename Directory>
@@ -410,7 +445,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(static_cast<size_t>(size), buffer));
OX_RETURN_ERROR(m_fs.resize(static_cast<size_t>(size), buffer));
return {};
}
@@ -423,23 +458,23 @@ Error FileSystemTemplate<FileStore, Directory>::writeFilePath(
oxTrace("ox.fs.FileSystemTemplate.writeFilePath", path);
auto [inode, err] = find(path);
if (err) {
oxReturnError(m_fs.generateInodeId().moveTo(inode));
oxRequireM(rootDir, this->rootDir());
oxReturnError(rootDir.write(path, inode));
OX_RETURN_ERROR(m_fs.generateInodeId().moveTo(inode));
OX_REQUIRE_M(rootDir, this->rootDir());
OX_RETURN_ERROR(rootDir.write(path, inode));
}
oxReturnError(writeFileInode(inode, buffer, size, fileType));
OX_RETURN_ERROR(writeFileInode(inode, buffer, size, fileType));
return {};
}
template<typename FileStore, typename Directory>
Error FileSystemTemplate<FileStore, Directory>::writeFileInode(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept {
oxTrace("ox.fs.FileSystemTemplate.writeFileInode", ox::itoa(inode));
oxTrace("ox.fs.FileSystemTemplate.writeFileInode", ox::intToStr(inode));
return m_fs.write(inode, buffer, static_cast<size_t>(size), static_cast<uint8_t>(fileType));
}
template<typename FileStore, typename Directory>
Result<FileStat> FileSystemTemplate<FileStore, Directory>::statInode(uint64_t inode) const noexcept {
oxRequire(s, m_fs.stat(inode));
OX_REQUIRE(s, m_fs.stat(inode));
FileStat out;
out.inode = s.inode;
out.links = s.links;
@@ -450,7 +485,7 @@ Result<FileStat> FileSystemTemplate<FileStore, Directory>::statInode(uint64_t in
template<typename FileStore, typename Directory>
Result<FileStat> FileSystemTemplate<FileStore, Directory>::statPath(StringViewCR path) const noexcept {
oxRequire(inode, find(path));
OX_REQUIRE(inode, find(path));
return stat(inode);
}
@@ -487,25 +522,25 @@ bool FileSystemTemplate<FileStore, Directory>::valid() const noexcept {
template<typename FileStore, typename Directory>
Result<typename FileSystemTemplate<FileStore, Directory>::FileSystemData> FileSystemTemplate<FileStore, Directory>::fileSystemData() const noexcept {
FileSystemData fd;
oxReturnError(m_fs.read(InodeFsData, &fd, sizeof(fd)));
OX_RETURN_ERROR(m_fs.read(InodeFsData, &fd, sizeof(fd)));
return fd;
}
template<typename FileStore, typename Directory>
Result<uint64_t> FileSystemTemplate<FileStore, Directory>::find(StringViewCR path) const noexcept {
oxRequire(fd, fileSystemData());
OX_REQUIRE(fd, fileSystemData());
// return root as a special case
if (path == "/") {
return static_cast<uint64_t>(fd.rootDirInode);
}
Directory rootDir(m_fs, fd.rootDirInode);
oxRequire(out, rootDir.find(path));
OX_REQUIRE(out, rootDir.find(path));
return static_cast<uint64_t>(out);
}
template<typename FileStore, typename Directory>
Result<Directory> FileSystemTemplate<FileStore, Directory>::rootDir() const noexcept {
oxRequire(fd, fileSystemData());
OX_REQUIRE(fd, fileSystemData());
return Directory(m_fs, fd.rootDirInode);
}
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -45,8 +45,6 @@ class PassThroughFS: public FileSystem {
template<typename F>
Error ls(StringViewCR dir, F cb) const noexcept;
Error remove(StringViewCR path, bool recursive) noexcept override;
Error resize(uint64_t size, void *buffer) noexcept override;
Result<FileStat> statInode(uint64_t inode) const noexcept override;
@@ -73,8 +71,13 @@ class PassThroughFS: public FileSystem {
Error readFileInode(uint64_t inode, void *buffer, std::size_t size) noexcept override;
Error readFilePathRange(
StringViewCR path, size_t readStart, size_t readSize, void *buffer, size_t *buffSize) noexcept override;
Error readFileInodeRange(uint64_t inode, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept override;
Error removePath(StringViewCR path, bool recursive) noexcept override;
Error writeFilePath(StringViewCR path, const void *buffer, uint64_t size, FileType fileType) noexcept override;
Error writeFileInode(uint64_t inode, const void *buffer, uint64_t size, FileType fileType) noexcept override;
@@ -92,11 +95,11 @@ template<typename F>
Error PassThroughFS::ls(StringViewCR dir, F cb) const noexcept {
std::error_code ec;
const auto di = std::filesystem::directory_iterator(m_path / stripSlash(dir), ec);
oxReturnError(OxError(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: ls failed"));
OX_RETURN_ERROR(ox::Error(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: ls failed"));
for (auto &p : di) {
oxReturnError(cb(p.path().filename().c_str(), 0));
OX_RETURN_ERROR(cb(p.path().filename().c_str(), 0));
}
return OxError(0);
return {};
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -13,6 +13,8 @@
#include "ptr.hpp"
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox::ptrarith {
template<typename size_t, typename Item>
@@ -282,14 +284,14 @@ Result<typename NodeBuffer<size_t, Item>::ItemPtr> NodeBuffer<size_t, Item>::mal
addr = m_header.firstItem;
} else {
oxTrace("ox.ptrarith.NodeBuffer.malloc.fail", "NodeBuffer is in invalid state.");
return OxError(1, "NodeBuffer is in invalid state.");
return ox::Error(1, "NodeBuffer is in invalid state.");
}
}
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");
return OxError(1, "NodeBuffer::malloc: unknown failure");
return ox::Error(1, "NodeBuffer::malloc: unknown failure");
}
ox::memset(out, 0, fullSize);
new (out) Item;
@@ -302,7 +304,7 @@ Result<typename NodeBuffer<size_t, Item>::ItemPtr> NodeBuffer<size_t, Item>::mal
first->prev = out.offset();
} else {
oxTrace("ox.ptrarith.NodeBuffer.malloc.fail", "NodeBuffer malloc failed due to invalid first element pointer.");
return OxError(1, "NodeBuffer malloc failed due to invalid first element pointer.");
return ox::Error(1, "NodeBuffer malloc failed due to invalid first element pointer.");
}
if (oldLast.valid()) {
@@ -312,7 +314,7 @@ Result<typename NodeBuffer<size_t, Item>::ItemPtr> NodeBuffer<size_t, Item>::mal
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.");
return OxError(1, "NodeBuffer malloc failed due to invalid last element pointer.");
return ox::Error(1, "NodeBuffer malloc failed due to invalid last element pointer.");
}
out->prev = out.offset();
}
@@ -321,7 +323,7 @@ Result<typename NodeBuffer<size_t, Item>::ItemPtr> NodeBuffer<size_t, Item>::mal
return out;
}
oxTracef("ox.ptrarith.NodeBuffer.malloc.fail", "Insufficient space: {} needed, {} available", fullSize, available());
return OxError(1);
return ox::Error(1);
}
template<typename size_t, typename Item>
@@ -344,15 +346,15 @@ Error NodeBuffer<size_t, Item>::free(ItemPtr item) noexcept {
} else {
if (!prev.valid()) {
oxTracef("ox.ptrarith.NodeBuffer.free.fail", "NodeBuffer free failed due to invalid prev element pointer: {}", prev.offset());
return OxError(1);
return ox::Error(1);
}
if (!next.valid()) {
oxTracef("ox.ptrarith.NodeBuffer.free.fail", "NodeBuffer free failed due to invalid next element pointer: {}", next.offset());
return OxError(1);
return ox::Error(1);
}
}
m_header.bytesUsed -= item.size();
return OxError(0);
return {};
}
template<typename size_t, typename Item>
@@ -363,12 +365,12 @@ Error NodeBuffer<size_t, Item>::setSize(std::size_t size) noexcept {
oxTracef("ox.ptrarith.NodeBuffer.setSize", "end: {}", end);
if (end > size) {
// resizing to less than buffer size
return OxError(1);
return ox::Error(1);
} else {
m_header.size = static_cast<size_t>(size);
auto data = reinterpret_cast<uint8_t*>(this) + end;
ox::memset(data, 0, size - end);
return OxError(0);
return {};
}
}
@@ -399,14 +401,14 @@ Error NodeBuffer<size_t, Item>::compact(F cb) noexcept {
auto dest = ptr(sizeof(*this));
while (dest.offset() <= src.offset()) {
if (!src.valid()) {
return OxError(1);
return ox::Error(1);
}
if (!dest.valid()) {
return OxError(2);
return ox::Error(2);
}
// move node
ox::memcpy(dest, src, src->fullSize());
oxReturnError(cb(src, dest));
OX_RETURN_ERROR(cb(src, dest));
// update surrounding nodes
auto prev = ptr(dest->prev);
if (prev.valid()) {
@@ -420,7 +422,7 @@ Error NodeBuffer<size_t, Item>::compact(F cb) noexcept {
src = ptr(dest->next);
dest = uninitializedPtr(dest.offset() + dest->fullSize());
}
return OxError(0);
return {};
}
template<typename size_t, typename Item>
@@ -449,3 +451,5 @@ struct OX_PACKED Item {
};
}
OX_CLANG_NOWARN_END
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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,6 +10,8 @@
#include <ox/std/std.hpp>
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox::ptrarith {
template<typename T, typename size_t, size_t minOffset = 1>
@@ -252,7 +254,9 @@ constexpr Result<Ptr<T, size_t, minOffset>> Ptr<T, size_t, minOffset>::validate(
if (valid()) {
return *this;
}
return OxError(1);
return ox::Error(1);
}
}
OX_CLANG_NOWARN_END
@@ -1,12 +1,12 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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 "filestoretemplate.hpp"
#include <ox/fs/filestore/filestoretemplate.hpp>
namespace ox {
@@ -1,12 +1,12 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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 "directory.hpp"
#include <ox/fs/filesystem/directory.hpp>
namespace ox {
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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,7 +8,7 @@
#include <ox/model/modelops.hpp>
#include "filelocation.hpp"
#include <ox/fs/filesystem/filelocation.hpp>
namespace ox {
@@ -31,8 +31,10 @@ FileAddress::FileAddress(uint64_t inode) noexcept {
FileAddress::FileAddress(ox::StringViewCR path) noexcept {
auto pathSize = path.bytes();
m_data.path = new char[pathSize + 1];
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
memcpy(m_data.path, path.data(), pathSize);
m_data.path[pathSize] = 0;
OX_ALLOW_UNSAFE_BUFFERS_END
m_type = FileAddressType::Path;
}
@@ -46,9 +48,11 @@ FileAddress &FileAddress::operator=(const FileAddress &other) noexcept {
case FileAddressType::Path:
{
if (other.m_data.path) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
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);
OX_ALLOW_UNSAFE_BUFFERS_END
} else {
m_data.constPath = "";
m_type = FileAddressType::ConstPath;
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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,7 +9,7 @@
#include <ox/std/error.hpp>
#include <ox/std/utility.hpp>
#include "filesystem.hpp"
#include <ox/fs/filesystem/filesystem.hpp>
namespace ox {
@@ -21,7 +21,7 @@ Result<const char*> MemFS::directAccess(const FileAddress &addr) const noexcept
case FileAddressType::Path:
return directAccess(StringView(addr.getPath().value));
default:
return OxError(1);
return ox::Error(1);
}
}
@@ -33,46 +33,73 @@ Error FileSystem::read(const FileAddress &addr, void *buffer, std::size_t size)
case FileAddressType::Path:
return readFilePath(StringView(addr.getPath().value), buffer, size);
default:
return OxError(1);
return ox::Error(1);
}
}
Result<Buffer> FileSystem::read(FileAddress const &addr, size_t const size) noexcept {
Result<Buffer> out;
out.value.resize(size);
switch (addr.type()) {
case FileAddressType::Inode:
OX_RETURN_ERROR(readFileInode(addr.getInode().value, out.value.data(), size));
break;
case FileAddressType::ConstPath:
case FileAddressType::Path:
OX_RETURN_ERROR(readFilePath(StringView{addr.getPath().value}, out.value.data(), size));
break;
default:
return ox::Error{1};
}
return out;
}
Result<Buffer> FileSystem::read(StringViewCR path, size_t const size) noexcept {
Result<Buffer> out;
out.value.resize(size);
OX_RETURN_ERROR(readFilePath(path, out.value.data(), size));
return out;
}
Result<Buffer> FileSystem::read(const FileAddress &addr) noexcept {
oxRequire(s, stat(addr));
OX_REQUIRE(s, stat(addr));
Buffer buff(static_cast<std::size_t>(s.size));
oxReturnError(read(addr, buff.data(), buff.size()));
OX_RETURN_ERROR(read(addr, buff.data(), buff.size()));
return buff;
}
Result<Buffer> FileSystem::read(StringViewCR path) noexcept {
oxRequire(s, statPath(path));
OX_REQUIRE(s, statPath(path));
Buffer buff(static_cast<std::size_t>(s.size));
oxReturnError(readFilePath(path, buff.data(), buff.size()));
OX_RETURN_ERROR(readFilePath(path, buff.data(), buff.size()));
return buff;
}
Error FileSystem::read(const FileAddress &addr, std::size_t readStart, std::size_t readSize, void *buffer, std::size_t *size) noexcept {
Error FileSystem::read(
FileAddress const &addr,
std::size_t const readStart,
std::size_t const readSize,
void *buffer,
std::size_t *size) noexcept {
switch (addr.type()) {
case FileAddressType::Inode:
return read(addr.getInode().value, readStart, readSize, buffer, size);
return readFileInodeRange(addr.getInode().value, readStart, readSize, buffer, size);
case FileAddressType::ConstPath:
case FileAddressType::Path:
return OxError(2, "Unsupported for path lookups");
return readFilePathRange(addr.getPath().value, readStart, readSize, buffer, size);
default:
return OxError(1);
return ox::Error(1);
}
}
Error FileSystem::remove(const FileAddress &addr, bool recursive) noexcept {
switch (addr.type()) {
case FileAddressType::Inode:
return remove(addr.getInode().value, recursive);
case FileAddressType::ConstPath:
case FileAddressType::Path:
return remove(StringView(addr.getPath().value), recursive);
default:
return OxError(1);
}
Result<size_t> FileSystem::read(
StringViewCR path,
std::size_t const readStart,
std::size_t const readSize,
Span<char> buff) noexcept {
size_t szOut{buff.size()};
OX_RETURN_ERROR(readFilePathRange(path, readStart, readSize, buff.data(), &szOut));
return szOut;
}
Error FileSystem::write(const FileAddress &addr, const void *buffer, uint64_t size, FileType fileType) noexcept {
@@ -83,7 +110,7 @@ Error FileSystem::write(const FileAddress &addr, const void *buffer, uint64_t si
case FileAddressType::Path:
return writeFilePath(StringView(addr.getPath().value), buffer, size, fileType);
default:
return OxError(1);
return ox::Error(1);
}
}
@@ -95,7 +122,7 @@ Result<FileStat> FileSystem::stat(const FileAddress &addr) const noexcept {
case FileAddressType::Path:
return statPath(StringView(addr.getPath().value));
default:
return OxError(1);
return ox::Error(1);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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,7 +8,7 @@
#include <ox/std/error.hpp>
#include "passthroughfs.hpp"
#include <ox/fs/filesystem/passthroughfs.hpp>
#if defined(OX_HAS_PASSTHROUGHFS)
@@ -39,7 +39,7 @@ Error PassThroughFS::mkdir(StringViewCR path, bool recursive) noexcept {
success = true;
} else {
success = std::filesystem::create_directories(p, ec);
oxReturnError(OxError(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: mkdir failed"));
OX_RETURN_ERROR(ox::Error(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: mkdir failed"));
}
} else {
std::error_code ec;
@@ -48,26 +48,26 @@ Error PassThroughFS::mkdir(StringViewCR path, bool recursive) noexcept {
success = true;
} else {
success = std::filesystem::create_directory(p, ec);
oxReturnError(OxError(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: mkdir failed"));
OX_RETURN_ERROR(ox::Error(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: mkdir failed"));
}
}
return OxError(success ? 0 : 1);
return ox::Error(success ? 0 : 1);
}
Error PassThroughFS::move(StringViewCR src, StringViewCR dest) noexcept {
std::error_code ec;
std::filesystem::rename(m_path / stripSlash(src), m_path / stripSlash(dest), ec);
if (ec.value()) {
return OxError(1);
return ox::Error(1);
}
return OxError(0);
return {};
}
Result<Vector<String>> PassThroughFS::ls(StringViewCR dir) const noexcept {
Vector<String> out;
std::error_code ec;
const auto di = std::filesystem::directory_iterator(m_path / stripSlash(dir), ec);
oxReturnError(OxError(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: ls failed"));
OX_RETURN_ERROR(ox::Error(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()));
@@ -75,22 +75,14 @@ Result<Vector<String>> PassThroughFS::ls(StringViewCR dir) const noexcept {
return out;
}
Error PassThroughFS::remove(StringViewCR path, bool recursive) noexcept {
if (recursive) {
return OxError(std::filesystem::remove_all(m_path / stripSlash(path)) != 0);
} else {
return OxError(std::filesystem::remove(m_path / stripSlash(path)) != 0);
}
}
Error PassThroughFS::resize(uint64_t, void*) noexcept {
// unsupported
return OxError(1, "resize is not supported by PassThroughFS");
return ox::Error(1, "resize is not supported by PassThroughFS");
}
Result<FileStat> PassThroughFS::statInode(uint64_t) const noexcept {
// unsupported
return OxError(1, "statInode(uint64_t) is not supported by PassThroughFS");
return ox::Error(1, "statInode(uint64_t) is not supported by PassThroughFS");
}
Result<FileStat> PassThroughFS::statPath(StringViewCR path) const noexcept {
@@ -101,7 +93,9 @@ Result<FileStat> PassThroughFS::statPath(StringViewCR path) const noexcept {
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.size", "{} {}", path, size);
oxReturnError(OxError(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: stat failed"));
if (auto err = ec.value()) {
return ox::Error{static_cast<ox::ErrorCode>(err), "PassThroughFS: stat failed"};
}
return FileStat{0, 0, size, type};
}
@@ -112,14 +106,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(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: could not get FS size"));
OX_RETURN_ERROR(ox::Error(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(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: could not get FS size"));
OX_RETURN_ERROR(ox::Error(static_cast<ox::ErrorCode>(ec.value()), "PassThroughFS: could not get FS size"));
return s.capacity;
}
@@ -128,7 +122,7 @@ char *PassThroughFS::buff() noexcept {
}
Error PassThroughFS::walk(Error(*)(uint8_t, uint64_t, uint64_t)) noexcept {
return OxError(1, "walk(Error(*)(uint8_t, uint64_t, uint64_t)) is not supported by PassThroughFS");
return ox::Error(1, "walk(Error(*)(uint8_t, uint64_t, uint64_t)) is not supported by PassThroughFS");
}
bool PassThroughFS::valid() const noexcept {
@@ -147,24 +141,51 @@ Error PassThroughFS::readFilePath(StringViewCR path, void *buffer, std::size_t b
file.seekg(0, std::ios::beg);
if (size > buffSize) {
oxTracef("ox.fs.PassThroughFS.read.error", "Read failed: Buffer too small: {}", path);
return OxError(1);
return ox::Error(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());
return OxError(2);
return ox::Error(2);
}
return OxError(0);
return {};
}
Error PassThroughFS::readFileInode(uint64_t, void*, std::size_t) noexcept {
// unsupported
return OxError(1, "readFileInode(uint64_t, void*, std::size_t) is not supported by PassThroughFS");
return ox::Error(1, "readFileInode(uint64_t, void*, std::size_t) is not supported by PassThroughFS");
}
Error PassThroughFS::readFilePathRange(
StringViewCR path, size_t const readStart, size_t readSize, void *buffer, size_t *buffSize) noexcept {
try {
std::ifstream file(m_path / stripSlash(path), std::ios::binary | std::ios::ate);
auto const size = static_cast<size_t>(file.tellg());
readSize = ox::min(readSize, size);
file.seekg(static_cast<off_t>(readStart), std::ios::beg);
if (readSize > *buffSize) {
oxTracef("ox.fs.PassThroughFS.read.error", "Read failed: Buffer too small: {}", path);
return ox::Error{1};
}
file.read(static_cast<char*>(buffer), static_cast<std::streamsize>(readSize));
return {};
} catch (std::fstream::failure const &f) {
oxTracef("ox.fs.PassThroughFS.read.error", "Read of {} failed: {}", path, f.what());
return ox::Error{2};
}
}
Error PassThroughFS::readFileInodeRange(uint64_t, std::size_t, std::size_t, void*, std::size_t*) noexcept {
// unsupported
return OxError(1, "read(uint64_t, std::size_t, std::size_t, void*, std::size_t*) is not supported by PassThroughFS");
return ox::Error(1, "read(uint64_t, std::size_t, std::size_t, void*, std::size_t*) is not supported by PassThroughFS");
}
Error PassThroughFS::removePath(StringViewCR path, bool const recursive) noexcept {
if (recursive) {
return ox::Error{std::filesystem::remove_all(m_path / stripSlash(path)) == 0};
} else {
return ox::Error{!std::filesystem::remove(m_path / stripSlash(path))};
}
}
Error PassThroughFS::writeFilePath(StringViewCR path, const void *buffer, uint64_t size, FileType) noexcept {
@@ -174,19 +195,18 @@ Error PassThroughFS::writeFilePath(StringViewCR path, const void *buffer, uint64
f.write(static_cast<const char*>(buffer), static_cast<std::streamsize>(size));
} catch (const std::fstream::failure &f) {
oxTracef("ox.fs.PassThroughFS.read.error", "Write of {} failed: {}", path, f.what());
return OxError(1);
return ox::Error(1);
}
return OxError(0);
return {};
}
Error PassThroughFS::writeFileInode(uint64_t, const void*, uint64_t, FileType) noexcept {
// unsupported
return OxError(1, "writeFileInode(uint64_t, void*, uint64_t, uint8_t) is not supported by PassThroughFS");
return ox::Error(1, "writeFileInode(uint64_t, void*, uint64_t, uint8_t) is not supported by PassThroughFS");
}
std::string_view PassThroughFS::stripSlash(StringView path) noexcept {
const auto pathLen = ox::strlen(path);
for (auto i = 0u; i < pathLen && path[0] == '/'; i++) {
for (auto i = 0u; i < path.size() && path[0] == '/'; i++) {
path = substr(path, 1);
}
return {path.data(), path.bytes()};
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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,7 +9,9 @@
#include <ox/std/memops.hpp>
#include <ox/std/strops.hpp>
#include <ox/std/trace.hpp>
#include "pathiterator.hpp"
#include <ox/fs/filesystem/pathiterator.hpp>
OX_CLANG_NOWARN_BEGIN(-Wunsafe-buffer-usage)
namespace ox {
@@ -30,13 +32,13 @@ PathIterator::PathIterator(StringViewCR path): PathIterator(path.data(), path.by
*/
Error PathIterator::dirPath(char *out, std::size_t outSize) {
const auto idx = ox::lastIndexOf(m_path, '/', m_maxSize);
const auto size = static_cast<std::size_t>(idx + 1);
const auto size = static_cast<std::size_t>(idx) + 1;
if (idx >= 0 && size < outSize) {
ox::memcpy(out, m_path, size);
out[size] = 0;
return OxError(0);
return {};
} else {
return OxError(1);
return ox::Error(1);
}
}
@@ -45,11 +47,11 @@ Error PathIterator::get(StringView &fileName) {
std::size_t size = 0;
if (m_iterator >= m_maxSize) {
oxTracef("ox.fs.PathIterator.get", "m_iterator ({}) >= m_maxSize ({})", m_iterator, m_maxSize);
return OxError(1);
return ox::Error(1);
}
if (!ox::strlen(&m_path[m_iterator])) {
oxTrace("ox.fs.PathIterator.get", "!ox::strlen(&m_path[m_iterator])");
return OxError(1);
return ox::Error(1);
}
auto start = m_iterator;
if (m_path[start] == '/') {
@@ -65,14 +67,14 @@ Error PathIterator::get(StringView &fileName) {
size = end - start;
// cannot fit the output in the output parameter
if (size >= MaxFileNameLength || size == 0) {
return OxError(1);
return ox::Error(1);
}
fileName = ox::substr(m_path, start, start + size);
// truncate trailing /
if (size && fileName[size - 1] == '/') {
fileName = ox::substr(m_path, start, start + size - 1);
}
oxAssert(fileName[fileName.len()-1] != '/', "name ends in /");
oxAssert(fileName[fileName.size()-1] != '/', "name ends in /");
return {};
}
@@ -81,9 +83,9 @@ Error PathIterator::get(StringView &fileName) {
*/
Error PathIterator::next(StringView &fileName) {
std::size_t size = 0;
auto retval = OxError(1);
auto retval = ox::Error(1);
if (m_iterator < m_maxSize && ox::strlen(&m_path[m_iterator])) {
retval = OxError(0);
retval = {};
if (m_path[m_iterator] == '/') {
m_iterator++;
}
@@ -98,25 +100,25 @@ Error PathIterator::next(StringView &fileName) {
size = end - start;
// cannot fit the output in the output parameter
if (size >= MaxFileNameLength) {
return OxError(1);
return ox::Error(1);
}
fileName = ox::substr(m_path, start, start + size);
// truncate trailing /
while (fileName.len() && fileName[fileName.len() - 1] == '/') {
while (fileName.size() && fileName[fileName.size() - 1] == '/') {
fileName = ox::substr(m_path, start, start + size);
}
m_iterator += size;
oxAssert(fileName.len() == 0 || fileName[fileName.len()-1] != '/', "name ends in /");
oxAssert(fileName.size() == 0 || fileName[fileName.size()-1] != '/', "name ends in /");
}
return retval;
}
Result<std::size_t> PathIterator::nextSize() const {
std::size_t size = 0;
auto retval = OxError(1);
auto retval = ox::Error(1);
auto it = m_iterator;
if (it < m_maxSize && ox::strlen(&m_path[it])) {
retval = OxError(0);
retval = {};
if (m_path[it] == '/') {
it++;
}
@@ -183,3 +185,5 @@ const char *PathIterator::fullPath() const {
}
}
OX_CLANG_NOWARN_END
+26 -23
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -20,7 +20,7 @@ static ox::Result<Buff> loadFsBuff(const char *path) noexcept {
std::ifstream file(path, std::ios::binary | std::ios::ate);
if (!file.good()) {
oxErrorf("Could not find OxFS file: {}", path);
return OxError(1, "Could not find OxFS file");
return ox::Error(1, "Could not find OxFS file");
}
try {
const auto size = static_cast<std::size_t>(file.tellg());
@@ -30,51 +30,54 @@ static ox::Result<Buff> loadFsBuff(const char *path) noexcept {
return Buff{buff, size};
} catch (const std::ios_base::failure &e) {
oxErrorf("Could not read OxFS file: {}", e.what());
return OxError(2, "Could not read OxFS file");
return ox::Error(2, "Could not read OxFS file");
}
}
static ox::Result<ox::UniquePtr<ox::FileSystem>> loadFs(const char *path) noexcept {
oxRequire(buff, loadFsBuff(path));
static ox::Result<ox::UPtr<ox::FileSystem>> loadFs(const char *path) noexcept {
OX_REQUIRE(buff, loadFsBuff(path));
return {ox::make_unique<ox::FileSystem32>(buff.data, buff.size)};
}
static ox::Error runLs(ox::FileSystem *fs, int argc, const char **argv) noexcept {
if (argc < 2) {
static ox::Error runLs(ox::FileSystem *fs, ox::Span<const char*> args) noexcept {
if (args.size() < 2) {
oxErr("Must provide a directory to ls\n");
return OxError(1);
return ox::Error(1);
}
oxRequire(files, fs->ls(argv[1]));
OX_REQUIRE(files, fs->ls(args[1]));
for (const auto &file : files) {
oxOutf("{}\n", file);
}
return OxError(0);
return {};
}
static ox::Error runRead(ox::FileSystem *fs, int argc, const char **argv) noexcept {
if (argc < 2) {
static ox::Error runRead(ox::FileSystem *fs, ox::Span<const char*> args) noexcept {
if (args.size() < 2) {
oxErr("Must provide a path to a file to read\n");
return OxError(1);
return ox::Error(1);
}
oxRequire(buff, fs->read(ox::StringView(argv[1])));
fwrite(buff.data(), sizeof(decltype(buff)::value_type), buff.size(), stdout);
return OxError(0);
OX_REQUIRE(buff, fs->read(ox::StringView(args[1])));
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
std::ignore = fwrite(buff.data(), sizeof(decltype(buff)::value_type), buff.size(), stdout);
OX_ALLOW_UNSAFE_BUFFERS_END
return {};
}
static ox::Error run(int argc, const char **argv) noexcept {
if (argc < 3) {
oxErr("OxFS file and subcommand arguments are required\n");
return OxError(1);
return ox::Error(1);
}
const auto fsPath = argv[1];
ox::String subCmd(argv[2]);
oxRequire(fs, loadFs(fsPath));
auto const args = ox::Span{argv, static_cast<size_t>(argc)};
auto const fsPath = args[1];
ox::String subCmd(args[2]);
OX_REQUIRE(fs, loadFs(fsPath));
if (subCmd == "ls") {
return runLs(fs.get(), argc - 2, argv + 2);
return runLs(fs.get(), args + 2);
} else if (subCmd == "read") {
return runRead(fs.get(), argc - 2, argv + 2);
return runRead(fs.get(), args + 2);
}
return OxError(1);
return ox::Error(1);
}
int main(int argc, const char **argv) {
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -52,19 +52,19 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
oxAssert(buffer->free(a1), "Free failed.");
oxAssert(buffer->free(a2), "Free failed.");
oxAssert(buffer->setSize(buffer->size() - buffer->available()), "Resize failed.");
return OxError(0);
return ox::Error(0);
}
},
{
"PathIterator::next1",
[](ox::StringView) {
auto constexpr path = ox::StringLiteral("/usr/share/charset.gbag");
ox::PathIterator it(path.c_str(), path.len());
ox::PathIterator it(path.c_str(), path.size());
ox::StringView 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);
return ox::Error(0);
}
},
{
@@ -74,20 +74,20 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
ox::PathIterator it(path);
ox::StringView buff;
oxAssert(it.next(buff), "PathIterator::next returned error");
oxExpect(buff, "usr");
ox::expect(buff, "usr");
oxAssert(it.next(buff), "PathIterator::next returned error");
oxExpect(buff, "share");
return OxError(0);
ox::expect(buff, "share");
return ox::Error(0);
}
},
{
"PathIterator::next3",
[](ox::StringView) {
auto const path = ox::String("/");
ox::PathIterator it(path.c_str(), path.len());
ox::PathIterator it(path.c_str(), path.size());
ox::StringView buff;
oxAssert(it.next(buff) == 0 && buff == "\0", "PathIterator shows wrong next");
return OxError(0);
return ox::Error(0);
}
},
{
@@ -99,38 +99,42 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
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);
return ox::Error(0);
}
},
{
"PathIterator::next5",
[](ox::StringView) {
auto const path = ox::String("usr/share/");
ox::PathIterator it(path.c_str(), path.len());
ox::PathIterator it(path.c_str(), path.size());
ox::StringView buff;
oxAssert(it.next(buff) == 0 && buff == "usr", "PathIterator shows wrong next");
oxAssert(it.next(buff) == 0 && buff == "share", "PathIterator shows wrong next");
return OxError(0);
return ox::Error(0);
}
},
{
"PathIterator::dirPath",
[] (ox::StringView) {
auto constexpr path = ox::StringLiteral("/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");
return OxError(0);
ox::PathIterator it(path.c_str(), path.size());
auto buff = static_cast<char*>(ox_alloca(path.size() + 1));
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
oxAssert(it.dirPath(buff, path.size()) == 0 && ox::strcmp(buff, "/usr/share/") == 0, "PathIterator shows incorrect dir path");
OX_ALLOW_UNSAFE_BUFFERS_END
return ox::Error(0);
}
},
{
"PathIterator::hasNext",
[](ox::StringView) {
const auto path = "/file1";
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::PathIterator it(path, ox::strlen(path));
OX_ALLOW_UNSAFE_BUFFERS_END
oxAssert(it.hasNext(), "PathIterator shows incorrect hasNext");
oxAssert(!it.next().hasNext(), "PathIterator shows incorrect hasNext");
return OxError(0);
return ox::Error(0);
}
},
{
@@ -142,7 +146,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
auto subPtr = p.subPtr<uint64_t>(50);
oxAssert(subPtr.valid(), "Ptr::subPtr: Ptr subPtr is invalid.");
return OxError(0);
return ox::Error(0);
}
},
{
@@ -155,7 +159,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
auto first = list->firstItem();
oxAssert(first.valid(), "NodeBuffer::insert: Could not access first item");
oxAssert(first->size() == 50, "NodeBuffer::insert: First item size invalid");
return OxError(0);
return ox::Error(0);
}
},
{
@@ -163,20 +167,22 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
[](ox::StringView) {
constexpr auto buffLen = 5000;
constexpr auto str1 = "Hello, World!";
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
constexpr auto str1Len = ox::strlen(str1) + 1;
constexpr auto str2 = "Hello, Moon!";
constexpr auto str2Len = ox::strlen(str2) + 1;
OX_ALLOW_UNSAFE_BUFFERS_END
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);
oxAssert(fileStore.write(4, const_cast<char*>(str1), str1Len, 1), "FileStore::write 1 failed.");
oxAssert(fileStore.write(5, const_cast<char*>(str2), str2Len, 1), "FileStore::write 2 failed.");
oxAssert(fileStore.write(4, str1, str1Len, 1), "FileStore::write 1 failed.");
oxAssert(fileStore.write(5, str2, str2Len, 1), "FileStore::write 2 failed.");
char str1Read[str1Len];
size_t str1ReadSize = 0;
oxAssert(fileStore.read(4, reinterpret_cast<void*>(str1Read), str1Len, &str1ReadSize), "FileStore::read 1 failed.");
return OxError(0);
return ox::Error(0);
}
},
{
@@ -203,7 +209,7 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
oxTrace("ox.fs.test.Directory") << "write 3";
oxAssert(dir.write("/file2", 2), "Directory write of file2 failed");
return OxError(0);
return ox::Error(0);
}
},
{
@@ -220,19 +226,20 @@ const std::map<ox::StringView, std::function<ox::Error(ox::StringView)>> tests =
oxAssert(fs.stat("/l1d1/l2d1/l3d1").error, "mkdir failed");
oxAssert(fs.mkdir("/l1d1/l2d2", true), "mkdir failed");
oxAssert(fs.stat("/l1d1/l2d2").error, "mkdir failed");
return OxError(0);
return ox::Error(0);
}
},
},
};
int main(int argc, const char **args) {
int main(int argc, const char **argv) {
if (argc < 2) {
oxError("Must specify test to run");
return -1;
}
auto const args = ox::Span{argv, static_cast<size_t>(argc)};
ox::StringView const testName = args[1];
ox::StringView const testArg = args[2] ? args[2] : nullptr;
ox::StringView const testArg = argc >= 3 ? args[2] : nullptr;
auto const func = tests.find(testName);
if (func != tests.end()) {
oxAssert(func->second(testArg), "Test returned Error");
@@ -2,7 +2,7 @@ cmake_minimum_required(VERSION 3.10)
add_library(
OxLogConn
logconn.cpp
src/logconn.cpp
)
set_property(
@@ -24,12 +24,16 @@ target_link_libraries(
$<$<BOOL:${OX_OS_WINDOWS}>:ws2_32>
)
target_include_directories(
OxLogConn PUBLIC
include
)
install(
FILES
circularbuff.hpp
logconn.hpp
DIRECTORY
include/ox
DESTINATION
include/ox/logconn
include
)
install(
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -34,7 +34,7 @@ class CirculerBuffer {
constexpr ox::Error put(char v) noexcept {
return write(&v, 1);
if (1 > avail()) {
return OxError(1, "Insufficient space in buffer");
return ox::Error(1, "Insufficient space in buffer");
}
m_buff[m_writePt] = v;
++m_writePt;
@@ -43,8 +43,9 @@ class CirculerBuffer {
constexpr ox::Error write(const char *buff, std::size_t sz) noexcept {
if (sz > avail()) {
return OxError(1, "Insufficient space in buffer");
return ox::Error(1, "Insufficient space in buffer");
}
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
// write seg 1
const auto seg1Sz = ox::min(sz, m_buff.size() - m_writePt);
ox::listcpy(&m_buff[m_writePt], &buff[0], seg1Sz);
@@ -56,12 +57,13 @@ class CirculerBuffer {
ox::listcpy(&m_buff[0], &buff[seg1Sz], seg2Sz);
oxAssert(m_buff[0] == buff[seg1Sz], "break");
}
OX_ALLOW_UNSAFE_BUFFERS_END
return {};
}
constexpr ox::Error seekp(std::size_t bytesFwd) noexcept {
if (bytesFwd > avail()) {
return OxError(1, "Insufficient space in buffer to seek that far ahead");
return ox::Error(1, "Insufficient space in buffer to seek that far ahead");
}
m_writePt += bytesFwd;
if (m_writePt > m_buff.size()) {
@@ -71,7 +73,7 @@ class CirculerBuffer {
}
constexpr ox::Error seekp(int, ios_base::seekdir) noexcept {
return OxError(1, "Unimplemented");
return ox::Error(1, "Unimplemented");
}
[[nodiscard]]
@@ -90,7 +92,9 @@ class CirculerBuffer {
m_readPt -= m_buff.size();
// read seg 2
const auto seg2Sz = bytesRead - seg1Sz;
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::listcpy(&out[seg1Sz], &m_buff[0], seg2Sz);
OX_ALLOW_UNSAFE_BUFFERS_END
}
return bytesRead;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -14,7 +14,7 @@
{ \
const auto loggerErr = (loggerName).initConn(appName); \
if (loggerErr) { \
oxErrf("Could not connect to logger: {} ({}:{})\n", toStr(loggerErr), loggerErr.file, loggerErr.line); \
oxErrf("Could not connect to logger: {} ({}:{})\n", toStr(loggerErr), loggerErr.src.file_name(), loggerErr.src.line()); \
} else { \
ox::trace::setLogger(&(loggerName)); \
} \
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -45,13 +45,13 @@ class LoggerConn: public trace::Logger {
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));
OX_RETURN_ERROR(ox::writeMC(&buff[0], buff.size(), msg, &sz));
//std::printf("sz: %lu\n", sz);
oxRequire(szBuff, serialize(static_cast<uint32_t>(sz)));
OX_REQUIRE(szBuff, serialize(static_cast<uint32_t>(sz)));
std::unique_lock buffLk(m_buffMut);
oxReturnError(m_buff.put(static_cast<char>(msgId)));
oxReturnError(m_buff.write(szBuff.data(), szBuff.size()));
oxReturnError(m_buff.write(buff.data(), sz));
OX_RETURN_ERROR(m_buff.put(static_cast<char>(msgId)));
OX_RETURN_ERROR(m_buff.write(szBuff.data(), szBuff.size()));
OX_RETURN_ERROR(m_buff.write(buff.data(), sz));
buffLk.unlock();
m_waitCond.notify_one();
return {};
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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,8 +9,8 @@
#ifdef OX_USE_STDLIB
#include <cstdio>
#include <sys/types.h>
#ifndef _WIN32
#include <sys/types.h>
#include <sys/socket.h>
#include <arpa/inet.h>
#include <netinet/in.h>
@@ -23,17 +23,24 @@
#endif
#include "logconn.hpp"
#include <ox/logconn/logconn.hpp>
#include <ox/std/bit.hpp>
namespace ox {
#ifdef _WIN32
using Socket = SOCKET;
using LenType = int;
#else
using Socket = int;
using LenType = size_t;
#endif
using namespace trace;
void closeSock(auto s) noexcept {
static void closeSock(auto s) noexcept {
#ifdef _WIN32
closesocket(s);
closesocket(static_cast<Socket>(s));
#else
close(s);
#endif
@@ -56,8 +63,8 @@ ox::Error LoggerConn::initConn(ox::StringViewCR appName) noexcept {
addr.sin_family = AF_INET;
addr.sin_addr.s_addr = htonl(INADDR_LOOPBACK);
addr.sin_port = htons(5590);
m_socket = socket(AF_INET, SOCK_STREAM, IPPROTO_TCP);
oxReturnError(OxError(static_cast<ox::ErrorCode>(connect(m_socket, reinterpret_cast<sockaddr*>(&addr), sizeof(addr)))));
m_socket = static_cast<int>(socket(AF_INET, SOCK_STREAM, IPPROTO_TCP));
OX_RETURN_ERROR(ox::Error(static_cast<ox::ErrorCode>(connect(static_cast<Socket>(m_socket), reinterpret_cast<sockaddr*>(&addr), sizeof(addr)))));
return sendInit({.appName = ox::BasicString<128>(appName)});
}
@@ -65,10 +72,10 @@ ox::Error LoggerConn::send(const char *buff, std::size_t len) const noexcept {
std::size_t totalSent = 0;
while (totalSent < len) {
//std::fprintf(stdout, "Sending %lu/%lu bytes on socket %d\n", len, totalSent, m_socket);
const auto sent = ::send(m_socket, buff, len, 0);
const auto sent = ::send(static_cast<Socket>(m_socket), buff, static_cast<LenType>(len), 0);
if (sent < 0) {
std::fprintf(stderr, "Could not send msg\n");
return OxError(1, "Could not send msg");
std::ignore = std::fprintf(stderr, "Could not send msg\n");
return ox::Error(1, "Could not send msg");
}
totalSent += static_cast<std::size_t>(sent);
}
@@ -84,23 +91,29 @@ ox::Error LoggerConn::sendInit(const InitTraceMsg &msg) noexcept {
}
void LoggerConn::msgSend() noexcept {
try {
while (true) {
std::unique_lock lk(m_waitMut);
m_waitCond.wait(lk);
if (!m_running) {
break;
}
std::lock_guard buffLk(m_buffMut);
std::lock_guard const buffLk(m_buffMut);
while (true) {
ox::Array<char, ox::units::KB> tmp;
Array<char, units::KB> tmp;
const auto read = m_buff.read(tmp.data(), tmp.size());
if (!read) {
break;
}
oxAssert(read <= tmp.size(), "logger trying to read too much data");
//std::printf("LoggerConn: sending %lu bytes\n", read);
std::ignore = send(tmp.data(), read);
}
}
} catch (std::exception const &e) {
oxErrf("Exception in logger thread: {}\n", e.what());
oxAssert(false, "logger thread exception");
}
}
}
@@ -1,8 +1,7 @@
add_library(
OxMetalClaw
presenceindicator.cpp
read.cpp
write.cpp
src/read.cpp
src/write.cpp
)
if(NOT MSVC)
@@ -25,20 +24,20 @@ if(NOT OX_BARE_METAL)
)
endif()
install(
FILES
intops.hpp
err.hpp
mc.hpp
presenceindicator.hpp
read.hpp
types.hpp
write.hpp
DESTINATION
include/ox/mc
target_include_directories(
OxMetalClaw PUBLIC
include
)
install(TARGETS OxMetalClaw
install(
DIRECTORY
include/ox
DESTINATION
include
)
install(
TARGETS OxMetalClaw
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
+199
View File
@@ -0,0 +1,199 @@
/*
* Copyright 2015 - 2025 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/std/array.hpp>
#include <ox/std/assert.hpp>
#include <ox/std/bit.hpp>
#include <ox/std/byteswap.hpp>
#include <ox/std/math.hpp>
#include <ox/std/memops.hpp>
#include <ox/std/reader.hpp>
namespace ox::mc {
template<Integer_c T>
static constexpr auto Bits = sizeof(T) << 3;
/**
* Returns highest bit other than possible signed bit.
* Bit numbering starts at 0.
*/
template<Integer_c I>
[[nodiscard]]
constexpr size_t highestBit(I const val) noexcept {
unsigned shiftStart = sizeof(I) * 8 - 1;
// find the most significant non-sign indicator bit
size_t highestBit = 0;
// start at one bit lower if signed
if constexpr(is_signed_v<I>) {
--shiftStart;
}
for (auto i = shiftStart; i > 0; --i) {
auto const bitValue = (val >> i) & 1;
if (bitValue) {
highestBit = i;
break;
}
}
return highestBit;
}
static_assert(highestBit(static_cast<int8_t>(0b10000000)) == 0);
static_assert(highestBit(~static_cast<int8_t>(-1)) == 0);
static_assert(highestBit(~static_cast<int8_t>(-2)) == 0);
static_assert(highestBit(~static_cast<int8_t>(-3)) == 1);
static_assert(highestBit(1) == 0);
static_assert(highestBit(2) == 1);
static_assert(highestBit(4) == 2);
static_assert(highestBit(8) == 3);
static_assert(highestBit(static_cast<uint64_t>(1) << 31) == 31);
static_assert(highestBit(static_cast<uint64_t>(1) << 63) == 63);
struct McInt {
Array<uint8_t, 9> data{};
// length of integer in bytes
size_t length = 0;
};
template<Integer_c I>
[[nodiscard]]
constexpr McInt encodeInteger(I const pInput) noexcept {
auto const input = ResizedInt_t<I, 64>{pInput};
McInt out;
auto const inputNegative = is_signed_v<I> && input < 0;
// move input to uint64_t to allow consistent bit manipulation and to avoid
// overflow concerns
auto const val = std::bit_cast<uint64_t>(input);
if (val) {
// bits needed to represent number factoring in space possibly
// needed for signed bit
auto const highBit = inputNegative ? highestBit(~val) : highestBit(val);
auto const bits = highBit + 1 + (is_signed_v<I> ? 1 : 0);
// bytes needed to store value
size_t bytes = bits / 8 + (bits % 8 != 0);
auto const bitsAvailable = bytes * 8; // bits available to integer value
auto const bitsNeeded = bits + bytes;
// factor in bits needed for bytesIndicator (does not affect bytesIndicator)
// bits for integer + bits needed to represent bytes > bits available
if (bitsNeeded > bitsAvailable && bytes != 9) {
++bytes;
}
auto const bytesIndicator = onMask<uint8_t>(bytes - 1);
// ensure we are copying from little endian representation
LittleEndian<uint64_t> leVal = val;
if (inputNegative) {
leVal |= static_cast<uint64_t>(1 << (bitsNeeded - 1));
}
if (bytes == 9) {
out.data[0] = bytesIndicator;
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::memcpy(&out.data[1], &leVal, 8);
OX_ALLOW_UNSAFE_BUFFERS_END
if (inputNegative) {
out.data[1] |= 0b1000'0000;
}
} else {
auto const valBits = bytes * 8;
uint64_t const negBit = inputNegative ? 1 : 0;
auto const intermediate =
static_cast<uint64_t>(leVal.raw() | (negBit << (valBits - 1))) << bytes |
static_cast<uint64_t>(bytesIndicator);
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::memcpy(&out.data[0], &intermediate, sizeof(intermediate));
OX_ALLOW_UNSAFE_BUFFERS_END
}
out.length = bytes;
}
return out;
}
/**
* Returns the number of bytes indicated by the bytes indicator of a variable
* length integer.
*/
[[nodiscard]]
constexpr size_t countBytes(unsigned const b) noexcept {
size_t i = 0;
while ((b >> i) & 1) ++i;
return i + 1;
}
static_assert(countBytes(0b0000'0000) == 1);
static_assert(countBytes(0b0000'0001) == 2);
static_assert(countBytes(0b0000'0011) == 3);
static_assert(countBytes(0b0000'0111) == 4);
static_assert(countBytes(0b0000'1111) == 5);
static_assert(countBytes(0b0001'1111) == 6);
static_assert(countBytes(0b0011'1111) == 7);
static_assert(countBytes(0b0111'1111) == 8);
static_assert(countBytes(0b1111'1111) == 9);
template<Integer_c I>
constexpr Result<I> decodeInteger(Reader_c auto &rdr, size_t &bytesRead) noexcept {
uint8_t firstByte = 0;
OX_RETURN_ERROR(rdr.read(&firstByte, 1));
OX_RETURN_ERROR(rdr.seekg(-1, ox::ios_base::cur));
auto const bytes = countBytes(firstByte);
if (bytes == 9) {
bytesRead = bytes;
I out = 0;
OX_RETURN_ERROR(rdr.seekg(1, ox::ios_base::cur));
OX_RETURN_ERROR(rdr.read(&out, sizeof(I)));
return fromLittleEndian<I>(out);
}
bytesRead = bytes;
uint64_t decoded = 0;
OX_RETURN_ERROR(rdr.read(&decoded, bytes));
decoded >>= bytes;
// move sign bit
if constexpr(is_signed_v<I>) {
auto const negBit = bytes * 8 - bytes - 1;
// move sign
auto const 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
Array<uint32_t, 2> d = {};
//d[0] = decoded & 0xffff'ffff;
//d[1] = decoded >> 32;
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::memcpy(&d[0], &decoded, sizeof(decoded));
OX_ALLOW_UNSAFE_BUFFERS_END
auto bit = negBit;
for (; bit < ox::min<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) {
auto const d0Tmp = d[0];
d[0] = d[1];
d[1] = d0Tmp;
}
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
ox::memcpy(&out, &d[0], sizeof(out));
OX_ALLOW_UNSAFE_BUFFERS_END
return out;
}
}
return static_cast<I>(decoded);
}
template<Integer_c I>
Result<I> decodeInteger(McInt const &m) noexcept {
size_t bytesRead{};
BufferReader br({reinterpret_cast<const char*>(m.data.data()), 9});
return decodeInteger<I>(br, bytesRead);
}
}
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
+122
View File
@@ -0,0 +1,122 @@
/*
* Copyright 2015 - 2025 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/std/array.hpp>
#include <ox/std/bit.hpp>
#include <ox/std/error.hpp>
#include <ox/std/span.hpp>
#include <ox/std/types.hpp>
#include <ox/std/reader.hpp>
#include "err.hpp"
namespace ox {
template<Reader_c Reader>
class FieldBitmapReader {
protected:
mutable size_t m_mapBlockIdx = ~size_t{};
mutable uint64_t m_mapBlock{};
size_t m_mapStart{};
Reader &m_reader;
public:
explicit constexpr FieldBitmapReader(Reader &reader) noexcept:
m_mapStart(reader.tellg()),
m_reader(reader) {
}
constexpr Result<bool> get(size_t idx) const noexcept {
constexpr auto blockBits = sizeof(m_mapBlock);
auto const blockIdx = idx / blockBits;
if (m_mapBlockIdx != blockIdx) [[unlikely]] {
OX_RETURN_ERROR(loadMapBlock(blockIdx));
}
idx %= blockBits;
return (m_mapBlock >> idx) & 1;
}
private:
constexpr Error loadMapBlock(size_t const idx) const noexcept {
OX_REQUIRE(g, m_reader.tellg());
OX_RETURN_ERROR(m_reader.seekg(static_cast<int>(m_mapStart + idx), ox::ios_base::beg));
Array<char, sizeof(m_mapBlock)> mapBlock{};
OX_RETURN_ERROR(m_reader.read(mapBlock.data(), sizeof(m_mapBlock)));
// Warning: narrow-conv
OX_RETURN_ERROR(m_reader.seekg(static_cast<int>(g), ox::ios_base::beg));
m_mapBlock = 0;
for (uint64_t i{}; auto b : mapBlock) {
m_mapBlock |= static_cast<uint64_t>(std::bit_cast<uint8_t>(b)) << i;
i += 8;
}
m_mapBlockIdx = idx;
return {};
}
};
class FieldBitmapWriter {
protected:
Span<char> m_map;
size_t m_mapLen{};
public:
explicit constexpr FieldBitmapWriter(Span<char> const &map) noexcept:
m_map(map),
m_mapLen(m_map.size()) {
}
constexpr auto setBuffer(Span<char> const &map) noexcept {
m_map = map;
m_mapLen = map.size();
}
constexpr Result<bool> get(size_t const i) const noexcept {
if (i / 8 < m_mapLen) {
return (std::bit_cast<uint8_t>(m_map[i / 8]) >> (i % 8)) & 1;
}
return Error{McPresenceMapOverflow};
}
constexpr Error setFields(int const fields) noexcept {
m_mapLen = static_cast<size_t>((fields / 8 + 1) - (fields % 8 == 0));
if (m_mapLen > m_map.size()) [[unlikely]] {
return Error{McPresenceMapOverflow};
}
return {};
}
constexpr void setMaxLen(int const maxLen) noexcept {
m_mapLen = static_cast<size_t>(maxLen);
}
constexpr int64_t getMaxLen() const noexcept {
return static_cast<int64_t>(m_mapLen);
}
constexpr Error set(size_t const i, bool const on) noexcept {
if (i / 8 < m_mapLen) {
char &actual = m_map[i / 8];
uint8_t v = std::bit_cast<uint8_t>(actual);
if (on) {
v |= 1 << (i % 8);
} else {
v &= ~static_cast<uint8_t>(1 << (i % 8));
}
actual = std::bit_cast<char>(v);
return {};
}
return Error{McPresenceMapOverflow};
}
};
}
+558
View File
@@ -0,0 +1,558 @@
/*
* Copyright 2015 - 2025 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/model/fieldcounter.hpp>
#include <ox/model/modelhandleradaptor.hpp>
#include <ox/model/optype.hpp>
#include <ox/model/typenamecatcher.hpp>
#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>
#include "err.hpp"
#include "intops.hpp"
#include "presenceindicator.hpp"
#include "types.hpp"
namespace ox {
template<Reader_c Reader>
class MetalClawReaderTemplate: public ModelHandlerBase<MetalClawReaderTemplate<Reader>, ox::OpType::Read> {
private:
FieldBitmapReader<Reader> m_fieldPresence;
size_t m_fields{};
size_t m_field{};
Optional<int> const m_unionIdx{};
Reader &m_reader;
public:
explicit constexpr MetalClawReaderTemplate(
Reader &reader,
Optional<int> const &unionIdx = {}) noexcept;
constexpr ~MetalClawReaderTemplate() noexcept;
constexpr Error field(CString, int8_t *val) noexcept;
constexpr Error field(CString, int16_t *val) noexcept;
constexpr Error field(CString, int32_t *val) noexcept;
constexpr Error field(CString, int64_t *val) noexcept;
constexpr Error field(CString, uint8_t *val) noexcept;
constexpr Error field(CString, uint16_t *val) noexcept;
constexpr Error field(CString, uint32_t *val) noexcept;
constexpr Error field(CString, uint64_t *val) noexcept;
constexpr Error field(CString, bool *val) noexcept;
// array handler
constexpr Error field(CString, auto *val, size_t valLen) noexcept;
// map handler
template<typename T>
constexpr Error field(CString, HashMap<String, T> *val) noexcept;
// array handler, with callback to allow handling individual elements
template<typename T, typename CB>
constexpr Error field(CString, CB cb) noexcept;
template<typename T>
constexpr Error field(CString, T *val) noexcept;
template<typename U, bool force>
constexpr Error field(CString, UnionView<U, force> val) noexcept;
template<size_t SmallStringSize>
constexpr Error field(CString, BasicString<SmallStringSize> *val) noexcept;
template<size_t L>
constexpr Error field(CString, IString<L> *val) noexcept;
constexpr Error fieldCString(CString, char *val, size_t buffLen) noexcept;
constexpr Error fieldCString(CString, char **val) noexcept;
constexpr Error fieldCString(CString, char **val, size_t buffLen) noexcept;
/**
* Reads an array length from the current location in the buffer.
* @param pass indicates that the parsing should iterate past the array length
*/
constexpr Result<ArrayLength> arrayLength(const char *name, bool pass = true) noexcept;
/**
* Reads an string length from the current location in the buffer.
*/
constexpr Result<StringLength> stringLength(const char *name) noexcept;
template<typename T = std::nullptr_t>
constexpr ox::Error setTypeInfo(
const char *name = T::TypeName,
int version = T::TypeVersion,
const Vector<String>& = {},
size_t fields = ModelFieldCount_v<T>) noexcept;
/**
* Returns a MetalClawReader to parse a child object.
*/
[[nodiscard]]
constexpr MetalClawReaderTemplate<Reader> child(const char *name, Optional<int> unionIdx = {}) noexcept;
/**
* Indicates whether or not the next field to be read is present.
*/
[[nodiscard]]
constexpr bool fieldPresent(const char *name) const noexcept;
/**
* Indicates whether or not the given field is present.
*/
[[nodiscard]]
constexpr bool fieldPresent(int fieldNo) const noexcept;
[[nodiscard]]
constexpr int whichFieldPresent(const char *name, ModelUnion const&) const noexcept;
constexpr void nextField() noexcept;
private:
template<typename I>
constexpr Error readInteger(I &val) noexcept;
};
template<Reader_c Reader>
constexpr MetalClawReaderTemplate<Reader>::MetalClawReaderTemplate(
Reader &reader,
Optional<int> const &unionIdx) noexcept:
m_fieldPresence(reader),
m_unionIdx(unionIdx),
m_reader(reader) {
}
template<Reader_c Reader>
constexpr MetalClawReaderTemplate<Reader>::~MetalClawReaderTemplate() noexcept {
if (m_field != m_fields) {
oxTrace("ox.mc.MetalClawReader.error") << "MetalClawReader: incorrect fields number given";
}
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int8_t *val) noexcept {
return readInteger(*val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int16_t *val) noexcept {
return readInteger(*val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int32_t *val) noexcept {
return readInteger(*val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, int64_t *val) noexcept {
return readInteger(*val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint8_t *val) noexcept {
return readInteger(*val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint16_t *val) noexcept {
return readInteger(*val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint32_t *val) noexcept {
return readInteger(*val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, uint64_t *val) noexcept {
return readInteger(*val);
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, bool *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
auto const result = m_fieldPresence.get(static_cast<size_t>(m_field));
*val = result.value;
OX_RETURN_ERROR(result);
}
++m_field;
return {};
}
// array handler
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::field(
const char *name, auto *val, size_t const valLen) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length
size_t bytesRead = 0;
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
// read the list
if (valLen >= len) {
auto reader = child({});
auto &handler = *reader.interface();
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<size_t>(len)));
for (size_t i = 0; i < len; ++i) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
OX_RETURN_ERROR(handler.field({}, &val[i]));
OX_ALLOW_UNSAFE_BUFFERS_END
}
} else {
oxTracef("ox.mc.read.field(T)", "{}, length: {}", name, valLen);
return ox::Error(McOutputBuffEnded);
}
}
}
++m_field;
return {};
}
template<Reader_c Reader>
template<typename T>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, HashMap<String, T> *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length
OX_REQUIRE(g, m_reader.tellg());
size_t bytesRead = 0;
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
OX_RETURN_ERROR(m_reader.seekg(g));
// read the list
auto reader = child("");
auto &handler = *reader.interface();
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<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) {
OX_REQUIRE(keyLen, handler.stringLength(nullptr));
auto wkey = ox_malloca(keyLen + 1, char, 0);
auto wkeyPtr = wkey.get();
OX_RETURN_ERROR(handler.fieldCString("", &wkeyPtr, keyLen + 1));
return handler.field("", &val[wkeyPtr]);
};
for (size_t i = 0; i < len; ++i) {
OX_RETURN_ERROR(loopBody(handler, *val));
}
}
}
++m_field;
return {};
}
template<Reader_c Reader>
template<typename T>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val) noexcept {
if constexpr(isVector_v<T>) {
if (!m_unionIdx.has_value() || static_cast<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<size_t>(m_field))) {
OX_REQUIRE(len, arrayLength(name, false));
OX_RETURN_ERROR(ox::resizeVector(*val, len));
return field(name, val->data(), val->size());
}
OX_RETURN_ERROR(ox::resizeVector(*val, 0));
}
++m_field;
return {};
} else if constexpr(isArray_v<T>) {
if (!m_unionIdx.has_value() || static_cast<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<size_t>(m_field))) {
OX_REQUIRE(len, arrayLength(name, false));
if (len > val->size()) {
return ox::Error(1, "Input array is too long");
}
}
return field(name, val->data(), val->size());
}
++m_field;
return {};
} else {
if ((!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) && val) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
auto reader = child("");
OX_RETURN_ERROR(model(reader.interface(), val));
}
}
++m_field;
return {};
}
}
template<Reader_c Reader>
template<typename U, bool force>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, UnionView<U, force> val) noexcept {
if ((!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) && val.get()) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
auto reader = child("", ox::Optional<int>(ox::in_place, val.idx()));
OX_RETURN_ERROR(model(reader.interface(), val.get()));
}
}
++m_field;
return {};
}
template<Reader_c Reader>
template<size_t SmallStringSize>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, BasicString<SmallStringSize> *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length
size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
const auto cap = size;
*val = BasicString<SmallStringSize>(cap);
auto data = val->data();
// read the string
OX_RETURN_ERROR(m_reader.read(data, size));
} else {
*val = "";
}
}
++m_field;
return {};
}
template<Reader_c Reader>
template<size_t L>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, IString<L> *val) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length
size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
*val = IString<L>();
OX_RETURN_ERROR(val->resize(size));
auto const data = val->data();
// read the string
OX_RETURN_ERROR(m_reader.read(data, size));
} else {
*val = "";
}
}
++m_field;
return {};
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(
CString, char *val, size_t const buffLen) noexcept {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length
size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
if (size > buffLen) {
return ox::Error(McOutputBuffEnded);
}
// re-allocate in case too small
auto data = val;
// read the string
OX_RETURN_ERROR(m_reader.read(data, size));
data[size] = 0;
}
++m_field;
return {};
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(CString, char **val) noexcept {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length
size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
// re-allocate in case too small
safeDelete(*val);
*val = new char[size + 1];
auto data = ox::Span{*val, size + 1};
// read the string
OX_RETURN_ERROR(m_reader.read(data.data(), size));
data[size] = 0;
}
++m_field;
return {};
}
template<Reader_c Reader>
constexpr Error MetalClawReaderTemplate<Reader>::fieldCString(CString, char **val, size_t buffLen) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length
size_t bytesRead = 0;
OX_REQUIRE(size, mc::decodeInteger<StringLength>(m_reader, bytesRead));
// re-allocate if too small
if (buffLen < size + 1) {
safeDelete(*val);
*val = new char[size + 1];
buffLen = size + 1;
}
auto data = ox::Span{*val, size + 1};
// read the string
OX_RETURN_ERROR(m_reader.read(data.data(), size));
data[size] = 0;
} else {
auto data = *val;
if (data) {
data[0] = 0;
}
}
}
++m_field;
return {};
}
template<Reader_c Reader>
constexpr Result<ArrayLength> MetalClawReaderTemplate<Reader>::arrayLength(CString, bool const pass) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length
size_t bytesRead = 0;
OX_REQUIRE(g, m_reader.tellg());
OX_REQUIRE(out, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
if (!pass) {
OX_RETURN_ERROR(m_reader.seekg(g));
}
return out;
}
}
return ox::Error(1);
}
template<Reader_c Reader>
constexpr Result<StringLength> MetalClawReaderTemplate<Reader>::stringLength(CString) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length
size_t bytesRead = 0;
auto len = mc::decodeInteger<StringLength>(m_reader, bytesRead);
OX_RETURN_ERROR(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<Reader>::readInteger(I &val) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
size_t bytesRead = 0;
auto const result = mc::decodeInteger<I>(m_reader, bytesRead);
OX_RETURN_ERROR(result);
val = result.value;
} else {
val = 0;
}
}
++m_field;
return {};
}
template<Reader_c Reader>
template<typename T, typename CB>
constexpr Error MetalClawReaderTemplate<Reader>::field(CString, CB cb) noexcept {
if (!m_unionIdx.has_value() || static_cast<size_t>(*m_unionIdx) == m_field) {
if (m_fieldPresence.get(static_cast<size_t>(m_field))) {
// read the length
size_t bytesRead = 0;
OX_REQUIRE(len, mc::decodeInteger<ArrayLength>(m_reader, bytesRead));
// read the list
auto reader = child("");
auto &handler = *reader.interface();
OX_RETURN_ERROR(handler.setTypeInfo("List", 0, {}, static_cast<size_t>(len)));
for (size_t i = 0; i < len; ++i) {
T val;
OX_RETURN_ERROR(handler.field("", &val));
OX_RETURN_ERROR(cb(i, &val));
}
}
}
++m_field;
return {};
}
template<Reader_c Reader>
template<typename T>
constexpr ox::Error MetalClawReaderTemplate<Reader>::setTypeInfo(
CString, int, const Vector<String>&, size_t const fields) noexcept {
m_fields = fields;
// Warning: narrow-conv
return m_reader.seekg(
static_cast<int>((fields / 8 + 1) - (fields % 8 == 0)),
ox::ios_base::cur);
}
template<Reader_c Reader>
constexpr MetalClawReaderTemplate<Reader> MetalClawReaderTemplate<Reader>::child(
CString,
Optional<int> const unionIdx) noexcept {
return MetalClawReaderTemplate<Reader>(m_reader, unionIdx);
}
template<Reader_c Reader>
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(CString) const noexcept {
return m_fieldPresence.get(static_cast<size_t>(m_field)).value;
}
template<Reader_c Reader>
constexpr bool MetalClawReaderTemplate<Reader>::fieldPresent(int const fieldNo) const noexcept {
return m_fieldPresence.get(static_cast<size_t>(fieldNo)).value;
}
template<Reader_c Reader>
[[nodiscard]]
constexpr int MetalClawReaderTemplate<Reader>::whichFieldPresent(CString, ModelUnion const &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);
}
}
return -1;
}
template<Reader_c Reader>
constexpr void MetalClawReaderTemplate<Reader>::nextField() noexcept {
++m_field;
}
using MetalClawReader = MetalClawReaderTemplate<ox::BufferReader>;
template<typename T>
Error readMC(ox::BufferView const buff, T &val) noexcept {
BufferReader br(buff);
MetalClawReader reader(br);
return model(reader.interface(), &val);
}
template<typename T>
Result<T> readMC(ox::BufferView buff) noexcept {
Result<T> val;
OX_RETURN_ERROR(readMC(buff, val.value));
return val;
}
extern template class ModelHandlerInterface<MetalClawReaderTemplate<BufferReader>>;
}
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
+401
View File
@@ -0,0 +1,401 @@
/*
* Copyright 2015 - 2025 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/model/fieldcounter.hpp>
#include <ox/model/modelhandleradaptor.hpp>
#include <ox/model/optype.hpp>
#include <ox/model/types.hpp>
#include <ox/std/bit.hpp>
#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>
#include "intops.hpp"
#include "err.hpp"
#include "presenceindicator.hpp"
#include "types.hpp"
namespace ox {
template<Writer_c Writer>
class MetalClawWriter: public ModelHandlerBase<MetalClawWriter<Writer>, OpType::Write> {
private:
Vector<char, 16> m_presenceMapBuff{};
FieldBitmapWriter m_fieldPresence{m_presenceMapBuff};
int m_field{};
Optional<int> m_unionIdx;
size_t m_writerBeginP{};
Writer &m_writer;
public:
constexpr explicit MetalClawWriter(Writer &writer, Optional<int> const &unionIdx = {}) noexcept;
constexpr ~MetalClawWriter() noexcept = default;
constexpr Error field(CString, int8_t const *val) noexcept;
constexpr Error field(CString, int16_t const *val) noexcept;
constexpr Error field(CString, int32_t const *val) noexcept;
constexpr Error field(CString, int64_t const *val) noexcept;
constexpr Error field(CString, uint8_t const *val) noexcept;
constexpr Error field(CString, uint16_t const *val) noexcept;
constexpr Error field(CString, uint32_t const *val) noexcept;
constexpr Error field(CString, uint64_t const *val) noexcept;
constexpr Error field(CString, bool const *val) noexcept;
template<typename T>
constexpr Error field(CString, T const *val, size_t len) noexcept;
template<typename T>
constexpr Error field(CString name, HashMap<String, T> const *val) noexcept;
template<size_t SmallStringSize>
constexpr Error field(CString, BasicString<SmallStringSize> const *val) noexcept;
template<size_t L>
constexpr Error field(CString, IString<L> const *val) noexcept;
constexpr Error fieldCString(CString name, CString const*val, size_t buffLen) noexcept;
constexpr Error fieldCString(CString name, CString *val) noexcept;
constexpr Error fieldCString(CString name, CString const*val) noexcept;
constexpr Error fieldCString(CString name, CString val, size_t strLen) noexcept;
template<typename T>
constexpr Error field(CString, T const *val) noexcept;
template<typename U, bool force = false>
constexpr Error field(CString, UnionView<U, force> val) noexcept;
template<typename T = std::nullptr_t>
constexpr Error setTypeInfo(
CString name = T::TypeName,
int version = T::TypeVersion,
Vector<String> const& = {},
size_t fields = ModelFieldCount_v<T>) noexcept;
/**
* stringLength is not implemented in MetalClawWriter
*/
[[nodiscard]]
constexpr auto stringLength(CString) noexcept {
return 0;
}
/**
* stringLength is not implemented in MetalClawWriter
*/
[[nodiscard]]
constexpr auto arrayLength(CString, bool = true) noexcept {
return 0;
}
constexpr Error finalize() noexcept;
private:
constexpr Error appendInteger(Integer_c auto val) noexcept {
bool fieldSet = false;
if (val && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
auto mi = mc::encodeInteger(val);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(mi.data.data()), mi.length));
fieldSet = true;
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
++m_field;
return {};
}
};
extern template class ModelHandlerInterface<MetalClawWriter<BufferWriter>>;
extern template class ModelHandlerInterface<MetalClawWriter<CharBuffWriter>>;
template<Writer_c Writer>
constexpr MetalClawWriter<Writer>::MetalClawWriter(Writer &writer, Optional<int> const &unionIdx) noexcept:
m_unionIdx(unionIdx),
m_writerBeginP(writer.tellp()),
m_writer(writer) {
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, int8_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, int16_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, int32_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, int64_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, uint8_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, uint16_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, uint32_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, uint64_t const *val) noexcept {
return appendInteger(*val);
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::field(CString, bool const *val) noexcept {
if (!m_unionIdx.has_value() || *m_unionIdx == m_field) {
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), *val));
}
++m_field;
return {};
}
template<Writer_c Writer>
template<size_t SmallStringSize>
constexpr Error MetalClawWriter<Writer>::field(CString, BasicString<SmallStringSize> const *val) noexcept {
bool fieldSet = false;
if (val->size() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
auto const strLen = mc::encodeInteger(val->size());
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(strLen.data.data()), strLen.length));
// write the string
OX_RETURN_ERROR(m_writer.write(val->c_str(), static_cast<size_t>(val->size())));
fieldSet = true;
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
++m_field;
return {};
}
template<Writer_c Writer>
template<size_t L>
constexpr Error MetalClawWriter<Writer>::field(CString name, IString<L> const *val) noexcept {
return fieldCString(name, val->data(), val->size());
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(CString, CString const *val, size_t) noexcept {
bool fieldSet = false;
if (!m_unionIdx.has_value() || *m_unionIdx == m_field) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
// this strlen is tolerated because sometimes 0 gets passed to
// the size param, which is a lie
// this code should be cleaned up at some point...
auto const strLen = *val ? ox::strlen(*val) : 0;
OX_ALLOW_UNSAFE_BUFFERS_END
// write the length
auto const strLenBuff = mc::encodeInteger(strLen);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(strLenBuff.data.data()), strLenBuff.length));
// write the string
OX_RETURN_ERROR(m_writer.write(*val, static_cast<size_t>(strLen)));
fieldSet = true;
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
++m_field;
return {};
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(CString const name, CString *val) noexcept {
return fieldCString(name, val, {});
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(CString const name, CString const *val) noexcept {
return fieldCString(name, val, {});
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::fieldCString(CString, CString const val, size_t const strLen) noexcept {
bool fieldSet = false;
if (strLen && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
auto const strLenBuff = mc::encodeInteger(strLen);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(strLenBuff.data.data()), strLenBuff.length));
// write the string
OX_RETURN_ERROR(m_writer.write(val, static_cast<size_t>(strLen)));
fieldSet = true;
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
++m_field;
return {};
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter<Writer>::field(CString, T const *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.has_value() || *m_unionIdx == m_field)) {
auto const writeIdx = m_writer.tellp();
MetalClawWriter writer(m_writer);
OX_RETURN_ERROR(model(writer.interface(), val));
OX_RETURN_ERROR(writer.finalize());
fieldSet = writeIdx != m_writer.tellp();
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
++m_field;
return {};
}
}
template<Writer_c Writer>
template<typename U, bool force>
constexpr Error MetalClawWriter<Writer>::field(CString, UnionView<U, force> val) noexcept {
bool fieldSet = false;
if (val.get() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
auto const writeIdx = m_writer.tellp();
MetalClawWriter writer(m_writer, Optional<int>(in_place, val.idx()));
OX_RETURN_ERROR(model(writer.interface(), val.get()));
OX_RETURN_ERROR(writer.finalize());
fieldSet = writeIdx != m_writer.tellp();
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
++m_field;
return {};
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter<Writer>::field(CString, T const *val, size_t const len) noexcept {
bool fieldSet = false;
if (len && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
auto const arrLen = mc::encodeInteger(len);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(arrLen.data.data()), arrLen.length));
auto const writeIdx = m_writer.tellp();
MetalClawWriter writer(m_writer);
OX_RETURN_ERROR(writer.interface()->template setTypeInfo<T>("List", 0, {}, static_cast<size_t>(len)));
// write the array
for (size_t i{}; i < len; ++i) {
OX_ALLOW_UNSAFE_BUFFERS_BEGIN
OX_RETURN_ERROR(writer.interface()->field("", &val[i]));
OX_ALLOW_UNSAFE_BUFFERS_END
}
OX_RETURN_ERROR(writer.finalize());
fieldSet = writeIdx != m_writer.tellp();
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
++m_field;
return {};
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter<Writer>::field(CString, HashMap<String, T> const *val) noexcept {
auto const &keys = val->keys();
auto const len = keys.size();
bool fieldSet = false;
if (len && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
// write the length
auto const arrLen = mc::encodeInteger(len);
OX_RETURN_ERROR(m_writer.write(reinterpret_cast<CString>(arrLen.data.data()), arrLen.length));
// write map
MetalClawWriter writer(m_writer);
// double len for both key and value
OX_RETURN_ERROR(writer.interface()->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) -> Error {
auto const keyLen = key.size();
auto wkey = ox_malloca(keyLen + 1, char, 0);
memcpy(wkey.get(), key.c_str(), keyLen + 1);
OX_RETURN_ERROR(handler.fieldCString("", wkey.get(), keyLen));
OX_REQUIRE_M(value, val.at(key));
return handler.field("", value);
};
// write the array
for (size_t i{}; i < len; ++i) {
auto const &key = keys[i];
OX_RETURN_ERROR(loopBody(*writer.interface(), key, *val));
}
OX_RETURN_ERROR(writer.finalize());
fieldSet = true;
}
OX_RETURN_ERROR(m_fieldPresence.set(static_cast<size_t>(m_field), fieldSet));
++m_field;
return {};
}
template<Writer_c Writer>
template<typename T>
constexpr Error MetalClawWriter<Writer>::setTypeInfo(
CString,
int,
Vector<String> const&,
size_t const fields) noexcept {
auto const fieldPresenceLen = (fields - 1) / 8 + 1;
OX_RETURN_ERROR(m_writer.write(nullptr, fieldPresenceLen));
m_presenceMapBuff.resize(fieldPresenceLen);
m_fieldPresence.setBuffer(m_presenceMapBuff);
return m_fieldPresence.setFields(static_cast<int>(fields));
}
template<Writer_c Writer>
constexpr Error MetalClawWriter<Writer>::finalize() noexcept {
auto const end = m_writer.tellp();
OX_RETURN_ERROR(m_writer.seekp(m_writerBeginP));
OX_RETURN_ERROR(m_writer.write(
m_presenceMapBuff.data(),
m_presenceMapBuff.size()));
OX_RETURN_ERROR(m_writer.seekp(end));
return {};
}
Result<Buffer> writeMC(Writer_c auto &writer, auto const &val) noexcept {
MetalClawWriter mcWriter(writer);
OX_RETURN_ERROR(model(mcWriter.interface(), &val));
OX_RETURN_ERROR(mcWriter.finalize());
return {};
}
Result<Buffer> writeMC(auto const &val, size_t const buffReserveSz = 2 * units::KB) noexcept {
Buffer buff(buffReserveSz);
BufferWriter bw(&buff, 0);
OX_RETURN_ERROR(writeMC(bw, val));
buff.resize(bw.tellp());
return buff;
}
Error writeMC(char *buff, size_t const buffLen, auto const &val, size_t *sizeOut = nullptr) noexcept {
CharBuffWriter bw{{buff, buffLen}};
OX_RETURN_ERROR(writeMC(bw, val));
if (sizeOut) {
*sizeOut = bw.tellp();
}
return {};
}
}
+2 -2
View File
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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,7 +10,7 @@
#include <ox/std/buffer.hpp>
#include <ox/std/reader.hpp>
#include "read.hpp"
#include <ox/mc/read.hpp>
namespace ox {
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -11,7 +11,7 @@
#include <ox/std/memops.hpp>
#include <ox/std/trace.hpp>
#include "write.hpp"
#include <ox/mc/write.hpp>
namespace ox {
@@ -1,5 +1,5 @@
/*
* Copyright 2015 - 2024 gary@drinkingtea.net
* Copyright 2015 - 2025 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
@@ -62,47 +62,47 @@ struct TestStruct {
template<typename T>
constexpr ox::Error model(T *io, ox::CommonPtrWith<TestUnion> auto *obj) noexcept {
oxReturnError(io->template setTypeInfo<TestUnion>());
oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int));
oxReturnError(io->fieldCString("CString", &obj->CString));
return OxError(0);
OX_RETURN_ERROR(io->template setTypeInfo<TestUnion>());
OX_RETURN_ERROR(io->field("Bool", &obj->Bool));
OX_RETURN_ERROR(io->field("Int", &obj->Int));
OX_RETURN_ERROR(io->fieldCString("CString", &obj->CString));
return ox::Error(0);
}
oxModelBegin(TestStructNest)
oxModelField(Bool)
oxModelField(Int)
oxModelField(IString)
oxModelEnd()
OX_MODEL_BEGIN(TestStructNest)
OX_MODEL_FIELD(Bool)
OX_MODEL_FIELD(Int)
OX_MODEL_FIELD(IString)
OX_MODEL_END()
template<typename T>
constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) noexcept {
oxReturnError(io->template setTypeInfo<TestStruct>());
oxReturnError(io->field("Bool", &obj->Bool));
oxReturnError(io->field("Int", &obj->Int));
oxReturnError(io->field("Int1", &obj->Int1));
oxReturnError(io->field("Int2", &obj->Int2));
oxReturnError(io->field("Int3", &obj->Int3));
oxReturnError(io->field("Int4", &obj->Int4));
oxReturnError(io->field("Int5", &obj->Int5));
oxReturnError(io->field("Int6", &obj->Int6));
oxReturnError(io->field("Int7", &obj->Int7));
oxReturnError(io->field("Int8", &obj->Int8));
oxReturnError(io->field("unionIdx", &obj->unionIdx));
OX_RETURN_ERROR(io->template setTypeInfo<TestStruct>());
OX_RETURN_ERROR(io->field("Bool", &obj->Bool));
OX_RETURN_ERROR(io->field("Int", &obj->Int));
OX_RETURN_ERROR(io->field("Int1", &obj->Int1));
OX_RETURN_ERROR(io->field("Int2", &obj->Int2));
OX_RETURN_ERROR(io->field("Int3", &obj->Int3));
OX_RETURN_ERROR(io->field("Int4", &obj->Int4));
OX_RETURN_ERROR(io->field("Int5", &obj->Int5));
OX_RETURN_ERROR(io->field("Int6", &obj->Int6));
OX_RETURN_ERROR(io->field("Int7", &obj->Int7));
OX_RETURN_ERROR(io->field("Int8", &obj->Int8));
OX_RETURN_ERROR(io->field("unionIdx", &obj->unionIdx));
if constexpr(T::opType() == ox::OpType::Reflect) {
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 0}));
OX_RETURN_ERROR(io->field("Union", ox::UnionView{&obj->Union, 0}));
} else {
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, obj->unionIdx}));
OX_RETURN_ERROR(io->field("Union", ox::UnionView{&obj->Union, obj->unionIdx}));
}
oxReturnError(io->field("String", &obj->String));
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("Struct", &obj->Struct));
oxReturnError(io->field("EmptyStruct", &obj->EmptyStruct));
return OxError(0);
OX_RETURN_ERROR(io->field("String", &obj->String));
OX_RETURN_ERROR(io->field("IString", &obj->IString));
OX_RETURN_ERROR(io->field("List", obj->List, 4));
OX_RETURN_ERROR(io->field("Vector", &obj->Vector));
OX_RETURN_ERROR(io->field("Vector2", &obj->Vector2));
OX_RETURN_ERROR(io->field("Map", &obj->Map));
OX_RETURN_ERROR(io->field("Struct", &obj->Struct));
OX_RETURN_ERROR(io->field("EmptyStruct", &obj->EmptyStruct));
return ox::Error(0);
}
std::map<ox::StringView, ox::Error(*)()> tests = {
@@ -114,9 +114,9 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
// doesn't segfault
ox::Array<char, 1024> buff;
TestStruct ts;
oxReturnError(ox::writeMC(buff.data(), buff.size(), ts));
oxReturnError(ox::writeMC(ts));
return OxError(0);
OX_RETURN_ERROR(ox::writeMC(buff.data(), buff.size(), ts));
OX_RETURN_ERROR(ox::writeMC(ts));
return ox::Error(0);
}
},
@@ -157,8 +157,7 @@ std::map<ox::StringView, 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");
oxDebugf("{}", testOut.IString.len());
oxExpect(testIn.IString, testOut.IString);
ox::expect(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");
@@ -176,7 +175,7 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
oxAssert(testIn.Struct.Int == testOut.Struct.Int, "Struct.Int 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);
return ox::Error(0);
}
},
@@ -189,28 +188,28 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
static constexpr auto check = [](McInt val, const ox::Vector<uint8_t, 9> &expected) {
if (val.length != expected.size()) {
std::cout << "val.length: " << val.length << ", expected: " << expected.size() << '\n';
return OxError(1);
return ox::Error(1);
}
for (std::size_t i = 0; i < expected.size(); i++) {
if (expected[i] != val.data[i]) {
std::cout << "decoded: " << static_cast<uint32_t>(val.data[i]) << ", expected: " << static_cast<uint32_t>(expected[i]) << '\n';
std::cout << "decoded: " << i << ": " << static_cast<uint32_t>(val.data[i]) << '\n';
return OxError(1);
return ox::Error(1);
}
}
return OxError(0);
return ox::Error(0);
};
constexpr auto check64 = [](McInt val, auto expected) {
if (val.length != 9) {
std::cout << "val.length: " << val.length << '\n';
return OxError(1);
return ox::Error(1);
}
ox::LittleEndian<decltype(expected)> decoded = *reinterpret_cast<decltype(expected)*>(&val.data[1]);
if (expected != decoded) {
std::cout << "decoded: " << decoded << ", expected: " << expected << '\n';
return OxError(1);
return ox::Error(1);
}
return OxError(0);
return ox::Error(0);
};
// signed positive
oxAssert(check(encodeInteger(int64_t(1)), {0b000'0001'0}), "Encode 1 fail");
@@ -247,7 +246,7 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
// code deduplication
oxAssert(check64(encodeInteger(MaxValue<int64_t>), MaxValue<int64_t>), "Encode MaxValue<int64_t> fail");
oxAssert(check64(encodeInteger(MaxValue<uint64_t>), MaxValue<uint64_t>), "Encode MaxValue<uint64_t> fail");
return OxError(0);
return ox::Error(0);
}
},
@@ -260,12 +259,12 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
using ox::mc::decodeInteger;
static constexpr auto check = [](auto val) {
auto result = decodeInteger<decltype(val)>(encodeInteger(val));
oxReturnError(result.error);
OX_RETURN_ERROR(result.error);
if (result.value != val) {
std::cout << "Bad value: " << result.value << ", expected: " << val << '\n';
return OxError(1);
return ox::Error(1);
}
return OxError(0);
return ox::Error(0);
};
oxAssert(check(uint32_t(14)), "Decode of 14 failed.");
oxAssert(check(int8_t(-1)), "Decode of -1 failed.");
@@ -291,7 +290,7 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
oxAssert(check(0xffffffff), "Decode of 0xffffffff failed.");
oxAssert(check(0xffffffffffff), "Decode of 0xffffffffffff failed.");
oxAssert(check(0xffffffffffffffff), "Decode of U64 max failed.");
return OxError(0);
return ox::Error(0);
}
},
@@ -316,10 +315,10 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
testIn.Union.Int = 93;
oxAssert(ox::writeMC(dataBuff.data(), dataBuff.size(), testIn), "Data generation failed");
ox::TypeStore typeStore;
const auto [type, typeErr] = ox::buildTypeDef(&typeStore, &testIn);
const auto [type, typeErr] = ox::buildTypeDef(typeStore, testIn);
oxAssert(typeErr, "Descriptor write failed");
ox::ModelObject testOut;
oxReturnError(testOut.setType(type));
OX_RETURN_ERROR(testOut.setType(type));
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");
@@ -344,7 +343,7 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
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);
return ox::Error(0);
}
},
@@ -368,10 +367,10 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
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);
const auto [type, typeErr] = ox::buildTypeDef(typeStore, testIn);
oxAssert(typeErr, "Descriptor write failed");
ox::BufferReader br({dataBuff, dataBuffLen});
oxReturnError(ox::walkModel<ox::MetalClawReader>(type, br,
OX_RETURN_ERROR(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();
@@ -454,10 +453,10 @@ std::map<ox::StringView, ox::Error(*)()> tests = {
case ox::PrimitiveType::Union:
break;
}
return OxError(0);
return ox::Error(0);
}
));
return OxError(0);
return ox::Error(0);
}
},
}
+45
View File
@@ -0,0 +1,45 @@
add_library(
OxModel
src/desctypes.cpp
src/descwrite.cpp
src/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
)
if(NOT OX_BARE_METAL)
set_property(
TARGET
OxModel
PROPERTY
POSITION_INDEPENDENT_CODE ON
)
endif()
target_link_libraries(
OxModel PUBLIC
OxStd
)
target_include_directories(
OxModel PUBLIC
include
)
install(
TARGETS OxModel
LIBRARY DESTINATION lib
ARCHIVE DESTINATION lib
)
if(OX_RUN_TESTS)
add_subdirectory(test)
endif()
+19
View File
@@ -0,0 +1,19 @@
/*
* Copyright 2015 - 2025 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include <ox/std/concepts.hpp>
// oxModelFwdDecl is necessary because Apple-Clang is broken...
#define OX_MODEL_FWD_DECL(modelName) constexpr ox::Error model(auto *io, ox::CommonPtrWith<modelName> auto *o) noexcept
#define OX_MODEL_BEGIN(modelName) constexpr ox::Error model(auto *io, [[maybe_unused]] ox::CommonPtrWith<modelName> auto *o) noexcept { OX_RETURN_ERROR(io->template setTypeInfo<modelName>());
#define OX_MODEL_END() return {}; }
#define OX_MODEL_FIELD(fieldName) OX_RETURN_ERROR(io->field(#fieldName, &o->fieldName));
#define OX_MODEL_FIELD_RENAME(objFieldName, serFieldName) OX_RETURN_ERROR(io->field(#serFieldName, &o->objFieldName));
#define OX_MODEL_FRIEND(modelName) friend constexpr ox::Error model(auto *io, ox::CommonPtrWith<modelName> auto *o) noexcept
@@ -0,0 +1,7 @@
<Type> : <TypeName><FieldList>
<FieldList> : <FieldList> | <FieldList><Field>
<Field> : <FieldType><TypeID><FieldName>
<TypeID> : <TypeName> | <TypeName><Type>
<TypeName> : <string>
<FieldType> : <0: single> | <1: list>
<FieldName> : <string>

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