diff --git a/xo-object2/include/xo/object2/DList.hpp b/xo-object2/include/xo/object2/DList.hpp index 58de0750..eecb4310 100644 --- a/xo-object2/include/xo/object2/DList.hpp +++ b/xo-object2/include/xo/object2/DList.hpp @@ -25,27 +25,20 @@ namespace xo { DList(xo::obj h, DList * r) : head_{h}, rest_{r} {} - /** sentinel for null list **/ + /** sentinel for null list. + * Application code may prefer ListOps::nil() + **/ static DList * _nil(); /** list with first element @p car, * followed by contents of list @p cdr. * Shares structure with @p cdr + * Application code may prefer ListOps::cons() **/ static DList * _cons(obj mm, obj car, DList * cdr); -#ifdef OBSOLETE - /** list with one element @p h1, allocated from @p mm **/ - static DList * list(obj mm, - obj h1); - /** list with two elements @p h1, @p h2, allocated from @p mm **/ - static DList * list(obj mm, - obj h1, - obj h2); -#endif - /** DList length is at least 1 **/ bool is_empty() const noexcept; /** DList models a finite sequence **/ diff --git a/xo-object2/include/xo/object2/DString.hpp b/xo-object2/include/xo/object2/DString.hpp new file mode 100644 index 00000000..6333f7a4 --- /dev/null +++ b/xo-object2/include/xo/object2/DString.hpp @@ -0,0 +1,58 @@ +/** @file DString.hpp +* + * @author Roland Conybeare, Jan 2026 + **/ + +#pragma once + +#include +#include +#include + +namespace xo { + namespace scm { + /** @class DString + * @brief String implementation with gc hooks + * + * String implementation for Schematika. + * Size-prefixed and null-terminated. + * Note however that string length != size for utf-8. + * + * Uses flexible array for chars, + * with string contents in memory immediately + * following the DString itself + **/ + struct DString { + public: + using size_type = std::uint32_t; + using AAllocator = xo::mm::AAllocator; + + /** create empty string with space for @cap chars + * (including null terminator). + * Use memory from allocator @p mm + **/ + static DString * empty(obj mm, + size_type cap); + + /** create string containing a copy of null-terminated @p cstr. + * Use memory from allocator @p mm + **/ + static DString * from_cstr(obj mm, + const char * cstr); + + size_type capacity() const noexcept { return capacity_; } + size_type size() const noexcept { return size_; } + const char * chars() const noexcept { return chars_; } + + private: + /** extent of @ref chars_ array **/ + size_type capacity_ = 0; + /** null terminator at @c chars_[size_] **/ + size_type size_ = 0; + /** string contents **/ + char chars_[]; + }; + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DString.hpp */ diff --git a/xo-object2/include/xo/object2/IPrintable_DInteger.hpp b/xo-object2/include/xo/object2/IPrintable_DInteger.hpp index d18b25ab..60c9821c 100644 --- a/xo-object2/include/xo/object2/IPrintable_DInteger.hpp +++ b/xo-object2/include/xo/object2/IPrintable_DInteger.hpp @@ -14,7 +14,6 @@ #pragma once #include -#include #include "DInteger.hpp" namespace xo { namespace scm { class IPrintable_DInteger; } } diff --git a/xo-object2/src/object2/CMakeLists.txt b/xo-object2/src/object2/CMakeLists.txt index fc4c2d8e..a3658925 100644 --- a/xo-object2/src/object2/CMakeLists.txt +++ b/xo-object2/src/object2/CMakeLists.txt @@ -13,6 +13,7 @@ set(SELF_SRCS DList.cpp DFloat.cpp DInteger.cpp + DString.cpp object2_register_types.cpp object2_register_facets.cpp ) diff --git a/xo-object2/src/object2/DString.cpp b/xo-object2/src/object2/DString.cpp new file mode 100644 index 00000000..0fad514e --- /dev/null +++ b/xo-object2/src/object2/DString.cpp @@ -0,0 +1,37 @@ +/** @file DString.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include "DString.hpp" + +namespace xo { + using xo::facet::typeseq; + + namespace scm { + DString * + DString::empty(obj mm, + size_type cap) + { + assert(cap > 0); + + DString * result = nullptr; + + if (cap > 0) { + void * mem = mm.alloc(typeseq::id(), + sizeof(DString) + cap); + + result = new (mem) DString(); + result->capacity_ = cap; + result->size_ = 0; + if (cap > 0) { + result->chars_[0] = '\0'; + } + } + + return result; + } + } /*namespace scm*/ +} /*namespace xo*/ + +/* end DString.cpp */ diff --git a/xo-object2/utest/CMakeLists.txt b/xo-object2/utest/CMakeLists.txt index 70544571..a681e52c 100644 --- a/xo-object2/utest/CMakeLists.txt +++ b/xo-object2/utest/CMakeLists.txt @@ -3,6 +3,7 @@ set(UTEST_EXE utest.object2) set(UTEST_SRCS object2_utest_main.cpp + DString.test.cpp X1Collector.test.cpp Printable.test.cpp ) diff --git a/xo-object2/utest/DString.test.cpp b/xo-object2/utest/DString.test.cpp new file mode 100644 index 00000000..da4d8ca4 --- /dev/null +++ b/xo-object2/utest/DString.test.cpp @@ -0,0 +1,36 @@ +/** @file DString.test.cpp + * + * @author Roland Conybeare, Jan 2026 + **/ + +#include +#include +#include + +namespace xo { + using xo::scm::DString; + using xo::mm::AAllocator; + using xo::mm::DArena; + using xo::mm::ArenaConfig; + using xo::facet::with_facet; + using xo::facet::obj; + + namespace ut { + TEST_CASE("DString-empty", "[object2][DString]") + { + ArenaConfig cfg { .name_ = "testarena", + .size_ = 4*1024 }; + DArena arena = DArena::map(cfg); + auto alloc = with_facet::mkobj(&arena); + + DString * s = DString::empty(alloc, 16); + + REQUIRE(s != nullptr); + REQUIRE(s->capacity() == 16); + REQUIRE(s->size() == 0); + REQUIRE(s->chars()[0] == '\0'); + } + } /*namespace ut*/ +} /*namespace xo*/ + +/* end DString.test.cpp */