{"id":25117842,"url":"https://github.com/the-argus/okaylib","last_synced_at":"2025-04-02T12:19:01.447Z","repository":{"id":275705143,"uuid":"906527223","full_name":"the-argus/okaylib","owner":"the-argus","description":"C++17/20 STL replacement for realtime and memory-constrained domains","archived":false,"fork":false,"pushed_at":"2025-03-25T01:56:28.000Z","size":732,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"main","last_synced_at":"2025-03-25T02:37:56.725Z","etag":null,"topics":["cpp17","cpp20","game-development","iterators"],"latest_commit_sha":null,"homepage":"","language":"C++","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/the-argus.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2024-12-21T06:30:34.000Z","updated_at":"2025-03-25T01:56:31.000Z","dependencies_parsed_at":"2025-02-27T20:25:59.746Z","dependency_job_id":"df1781b6-a079-4e59-82f6-7854133a101a","html_url":"https://github.com/the-argus/okaylib","commit_stats":null,"previous_names":["the-argus/okaylib"],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/the-argus%2Fokaylib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/the-argus%2Fokaylib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/the-argus%2Fokaylib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/the-argus%2Fokaylib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/the-argus","download_url":"https://codeload.github.com/the-argus/okaylib/tar.gz/refs/heads/main","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":246811315,"owners_count":20837753,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["cpp17","cpp20","game-development","iterators"],"created_at":"2025-02-08T03:25:57.949Z","updated_at":"2025-04-02T12:19:01.436Z","avatar_url":"https://github.com/the-argus.png","language":"C++","funding_links":[],"categories":[],"sub_categories":[],"readme":"# okaylib\n\nC++17/20 STL replacement for realtime and memory-constrained domains.\n\n## goals\n\nReplace some of the C++17 STL with absolutely no concern for backwards compatibility.\nBackport and improve `std::ranges` ranges and range adaptors such as `enumerate`,\n`sliding_window`, etc. Provide a variety of containers which all use polymorphic\nallocators by default, and error by value instead of using exceptions. Additionally\nprovide multithreading primitives for C++20 users, such as a thread pool and coroutine\nruntime. Optionally make use of C++20 modules for improved compile times without\nwaiting for C++23 `import std`. Provide serialization to string and JSON for all\ntypes. Do bounds / error checking in both release and debug mode specifically to\ndetect undefined behavior (with an `OKAYLIB_FAST_UNSAFE` macro to disable it).\n\nokaylib is a personal project which is intended to focus many disparate\nefforts of mine to make C and C++ libraries into one mega-project. I have plan to\nuse it myself in some of my other projects, but any actual releases (along with\nsupport for build systems that people actually use, like CMake) are a ways off.\n\n## examples\n\nA demonstration of `ok::enumerate`, `ok::for_each` and the `ok::slice`. All C++17.\n\n```cpp\nint main(int argc, char* argv[])\n{\n    using namespace ok;\n    slice\u003cconst char*\u003e arguments = raw_slice(*argv, size_t(argc));\n\n    // print out arguments with their indices\n    arguments | enumerate | for_each([](auto\u0026 pair){\n        auto [ arg, index ] = pair;\n        fmt::println(\"Argument {}: {}\", index, arg);\n    });\n\n    // equivalent code, using some macros instead\n    ok_foreach(ok_pair(arg, index), arguments | enumerate)\n    {\n        fmt::println(\"Argument {}: {}\", index, arg);\n    }\n\n    // yet another option, the std_for view which provides compatbility with\n    // the language range based for loop\n    for(auto [ arg, index ] : arguments | enumerate | std_for) {\n        fmt::println(\"Argument {}: {}\", index, arg);\n    }\n}\n```\n\nDemonstration of allocators (non-polymorphic usage, static dispatch), and\n`arraylist_t`.\n\n```cpp\nint main() {\n    using namespace ok;\n    c_allocator_t working_allocator;\n    ooming_allocator_t failing_allocator; // for testing purposes\n\n    // no need to do error handling with `arraylist::empty` constructor, which does no allocation\n    arraylist_t alist = arraylist::empty\u003carraylist_t\u003cint, ooming_allocator_t\u003e\u003e(working_allocator);\n\n    // to demonstrate that c_allocator_t works, just allocate some unused space\n    const auto status = alist.increase_capacity_by(10);\n    if (!status.okay()) {\n        // c_allocator_t (which calls malloc and free) must have failed.\n        fmt::println(\"Arraylist capacity increase error: {}\", status);\n        return -1;\n    }\n\n    // arraylist has a constructor, `arraylist::copy_items_from_range`. Pass in\n    // that constructor followed by its arguments (the allocator that the sub-arraylist\n    // should use, and the items to copy into it).\n    const auto append_status =\n        alist.append(arraylist::copy_items_from_range, failing_allocator, array_t{1, 2, 3, 4, 5, 6});\n\n    // The above operation should fail because we gave the sub arraylist the failing allocator.\n    fmt::println(\"Tried to create a new array inside of `alist`, got return code {}\", append_status);\n    fmt::println(\"Size of `alist`: {}\", alist.size());\n}\n```\n\nOutputs:\n\n```txt\nTried to create a new array inside of `alist`, got return code [status::alloc::error::oom]\nSize of `alist`: 0\n```\n\n## todo\n\n- [x] polymorphic allocator interface\n- [x] arena allocator\n- [ ] linked arena allocator (arena but it uses a backward linked list of separate\n      blocks)\n- [x] block allocator\n- [x] slab allocator\n- [x] page allocator\n- [x] remapping page allocator\n- [x] `\u003cmemory_resource\u003e` wrapper allocator\n- [x] linked blockpool allocator (like block allocator but noncontiguous buffer)\n- [ ] linked slab allocator (like slab allocator but implemented with linked\n      blockpools instead of block allocators)\n- [ ] wrapper / import of jemalloc\n- [x] \"result\" type: optional with enum error value. like `std::expected`, kind of\n- [x] \"opt\" type: optional but supports reference types with rebinding assignment\n- [x] opt and result are constexpr + trivial, if their payloads are\n- [x] slice type: like span but not nullable\n- [x] defer statement\n- [x] stdmem: functions for checking if slices are overlapping, contained\n      within, etc\n- [x] new iterators, with lower barrier to entry. c++17 compatible but not backwards\n      compatible with algorithms that use legacy iterators or c++20 iterators. Designed\n      for easy implementation, good codegen, and immediate rangelike support (type\n      with iterator stuff should also be a range)\n- [ ] [WIP](https://github.com/the-argus/vmath/tree/vector2-special-ops) SIMD vector\n      and matrix types, explicit by default but with optional operator overloading.\n      inspired by DirectXMath\n- [ ] A dynamic bit array and a static bit array with boolean-like iterators, to\n      prove capability of new iterators\n- [x] `std::ranges` reimplementation, with some new views. enumerate, zip, take,\n      drop, join, keep_if, reverse, transform. Template specialization / optimization\n      when the viewed type is array-like.\n- [ ] More views (which will require allocation + error handling): sliding window,\n      chunking view, split view.\n- [ ] Add user-defined error values to the result. Also add some kind of anyhow\n      error type result, and some initialization at program startup to pre-reserve\n      space for errors.\n- [ ] implicit `context()` for allocators, random number generators, current error\n      message, etc.\n- [ ] modify context with `context_switch` type, which always restores changes when\n      it is destroyed. it cannot be moved.\n- [ ] \"cresult\" type, exactly like optional internally but with a different interface.\n      On construction, it stores an info string in the thread context. Has a getter\n      which returns a reference to the string in the context. Stands for \"context\n      result\". Maybe instead \"lresult\" for \"local result?\". Potentially a debugmode\n      check to make sure you haven't overwritten the value in the context when you\n      access it from the result.\n- [ ] context handle: serializable replacement for a reference which is a unique\n      index of an allocation along with a generation / magic value. when dereferencing,\n      it asks the context for the corresponding memory and compares magic number\n      to try to detect invalid allocator or use-after-free.\n- [ ] variants of context handle: explicit handle (dereferencing requires passing\n      the allocator) and unique context handle\n- [ ] sane `std::string` replacement, inspired a bit by Godot's `String`\n- [ ] `static_string`: `const char*` replacement which stores its length and has\n      a lot of nice string operations. never does allocation.\n- [ ] A low friction variant which is something like `std::variant\u003cint, float, string\u003e`\n- [ ] A fast hashmap, maybe one of the flat hash sets / maps from Google, with\n      support for emplace_back which can error by value\n- [ ] A `std::vector` replacement with a better name (`ok::arraylist`?) which\n      does not throw and supports emplace_back or push_back erroring by value. can\n      yield its contents with some `slice\u003cT\u003e release()` function\n- [x] A collection whose items can be accessed by a stable handle, instead of\n      index, but keeps items in contiguous memory for fast iteration. Includes\n      generation information in handle for lock and key type memory saftey and\n      debugging.\n- [ ] An arraylist type which does not store its elements contiguously but rather\n      in roughly cache-line-sized blocks, then has an array of pointers to blocks.\n      constant time lookup and less memory fragementation\n- [ ] fold/reduce function(s) compatible with above views\n- [ ] reimplementation of `\u003calgorithm\u003e` stuff: `stable_sort`, `sort`, `copy_if`,\n      `copy`, `move`, `count`, `count_if` `mismatch` `find`, `starts_with`, `ends_with`,\n      `contains`, `fill`, `find_if`, `any_of`, `all_of`, `is_sorted`, `unique`, `shuffle`,\n      `rotate`, `reverse`, `swap`, `binary_search`, `equal`, `max_element`, `max`,\n      `min`, `min_element`, `minmax_element`, `clamp`, and copying vs. in-place\n      variants for all algorithms. This is rangelike though- no need for\n      begin() and end() as separate arguments\n- [ ] threadpool compatibility for some views which are embarassingly parellel,\n      like `count*` or `max_element`. Specific threadsafe container iterator type?\n      iterables are all extremely templated, so this will be interesting.\n- [ ] standard coroutine types: task, generator\n- [ ] coroutines which can use thread's context allocator\n- [ ] coroutine-running threadpool with work queues and task stealing, for\n      copying off Go's homework. (potentially put threadpool and runtime into\n      context for submitting coroutines upon construction?)\n- [ ] fmtlib included for IO, all types mentioned above include formatters\n- [ ] all okaylib types have nlohmann json (or rapidjson?) serialization defined\n- [ ] Zig buildsystem module which makes it easy to import it into a zig project\n      and propagate up information about compilation flags (get an error if you\n      do something like enable bounds checking but a library youre calling into\n      explicitly disables them)\n- [ ] One day, far down the line: c++ modules support for zig build system, add\n      c++ modules support to okaylib.\n- [ ] (maybe) context contains an array of allocators so you can refer to allocators\n      in a serializable way (not by pointer)? Could be possible for users who\n      don't use pointers and only allocator handles to trivially serialize their\n      whole program to binary\n\n## misc improvements / backlog\n\n- [ ] Remove dependency on `\u003cmemory\u003e` header from `okay/detail/addressof.h`\n- [ ] Add option to disable undefined behavior checks which are normally on in\n      both release and debug mode (such as array bounds checks on iterators)\n- [ ] Offer alternative version of (or redo) `*_arc_t` types so that weak pointers\n      also keep the object alive. Maybe change the name of \"weak\" arc to\n      something like \"frozen\" arc.\n- [ ] Create \"minimum viable\" ranges for forward, multipass, bidirectional,\n      random access, and contiguous ranges, to test conformance of all the views\n- [ ] Add tests for all the views with a finite + random access range\n- [ ] Make sure every constructor of opt and res (converting constructors esp.)\n      have test coverage\n- [ ] Add better static asserts for when you use an invalid range with a pipe operator-\n      right now errors come from inside the range adaptor closure\n- [ ] Add some concept of being infinite _and_ arraylike. Currently infinite ranges\n      like `ok::indices` are not arraylike, which makes `enumerate(array)` more\n      space efficient than `zip(array, indices)`.\n- [ ] Add something like `alloc::flags::allow_overlapping` for when the user\n      wants to grow the buffer as much as possible in one atomic operation, allowing\n      for the allocator to figure out if maybe expanding back is a good way to\n      achieve that. The user can find out if the returned memory is overlapping\n      by calling `ok::memoverlaps`\n\n## relevant papers\n\n- **Improving STL Allocators**: [https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2045.html](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n2045.html)\n- **Upgrading the Interface of Allocators using API Versioning** [https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1953.html](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2006/n1953.html)\n  - Referenced by **Improving STL Allocators**\n- **Size feedback in operator new** [https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0901r5.html](https://www.open-std.org/jtc1/sc22/wg21/docs/papers/2019/p0901r5.html)\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthe-argus%2Fokaylib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fthe-argus%2Fokaylib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fthe-argus%2Fokaylib/lists"}