xo-expression2: + DUniqueString, use in StringTable

This commit is contained in:
Roland Conybeare 2026-01-16 13:05:58 -05:00
commit 0ae4b1528f
6 changed files with 255 additions and 20 deletions

View file

@ -7,6 +7,7 @@ set(SELF_SRCS
IExpression_Any.cpp
IExpression_DConstant.cpp
StringTable.cpp
DUniqueString.cpp
expression2_register_facets.cpp
)

View file

@ -0,0 +1,95 @@
/** @file DUniqueString.cpp
*
* @author Roland Conybeare, Jan 2026
**/
#include "DUniqueString.hpp"
#include <xo/arena/padding.hpp>
#include <xo/indentlog/scope.hpp>
namespace xo {
using xo::mm::padding;
using xo::facet::typeseq;
namespace scm {
const DString *
DUniqueString::_text() const noexcept
{
// location of paired DString is chosen
// by allocator (DArena, probably).
//
// In general allocator alignment more conservative
// than C++ alignment
//
// Remmebr also: although DUniqueString has zero members,
// C++ requires it to behave asif size at least 1 byte
// for iterator consistency
// (e.g. because c++ would support iterating over
// std::vector<EmptyStruct>)
//
size_t offset = padding::with_padding(sizeof(*this));
assert(offset > 0);
return (const DString *)(((std::byte *)this) + offset);
}
DUniqueString *
DUniqueString::from_view(obj<AAllocator> mm,
std::string_view sv)
{
scope log(XO_DEBUG(false));
/** fine point: choosing to allocate DUniqueString ahead of DString,
* so it comes first in bump allocator
**/
void * mem = mm.super_alloc(typeseq::id<DUniqueString>(),
sizeof(DUniqueString));
DUniqueString * result = new (mem) DUniqueString();
/** allocated in memory immediate following @p result.
* This optimization saves us one pointer (8 bytes) in DUniqueString
* itself, plus one allocation header (8 bytes) for 16 bytes total
**/
DString * text = DString::from_view_suballoc(mm, sv);
log && log(xtag("result", result), xtag("result.text", result->_text()), xtag("text", text));
assert(text);
assert(text == result->_text());
/** must finish super-allocation before next alloc **/
mm.sub_alloc(0, true);
return result;
}
size_t
DUniqueString::shallow_size() const noexcept
{
return sizeof(DUniqueString);
}
DUniqueString *
DUniqueString::shallow_copy(obj<AAllocator> mm) const noexcept
{
// well-posed, but not expected to be used.
assert(false);
DUniqueString * copy = (DUniqueString *)mm.alloc_copy((std::byte *)this);
if (copy)
*copy = *this;
return copy;
}
size_t
DUniqueString::forward_children(obj<ACollector>) noexcept
{
return shallow_size();
}
} /*namespace scm*/
} /*namespace xo*/
/* end DUniqueString.cpp */

View file

@ -23,7 +23,7 @@ namespace xo {
(void)debug_flag;
}
const DString *
const DUniqueString *
StringTable::lookup(std::string_view key) const
{
auto ix = map_.find(key);
@ -34,7 +34,7 @@ namespace xo {
return nullptr;
}
const DString *
const DUniqueString *
StringTable::intern(std::string_view key)
{
// 1a. lookup key in map_.
@ -49,9 +49,9 @@ namespace xo {
//
// 2d. return key2 address
// 2a. allocate DString copy 'interned' of key in strings_
// 2a. allocate DUniqueString copy 'interned' of key in strings_
auto mm = with_facet<AAllocator>::mkobj(&strings_);
DString * interned = DString::from_view(mm, key);
DUniqueString * interned = DUniqueString::from_view(mm, key);
assert(interned);
if (interned) {
@ -90,7 +90,7 @@ namespace xo {
/* ST2: for each entry, key points to value's string data */
for (const auto & kv : map_) {
const std::string_view & key = kv.first;
const DString * value = kv.second;
const DUniqueString * value = kv.second;
/* ST2.1: value is not null */
if (value == nullptr) {