19 switch (column.type) {
25 switch (column.bits) {
36 void storePodInt(std::byte* p,
AccessKind kind, std::int64_t v) {
39 auto x =
static_cast<std::int8_t
>(v);
40 std::memcpy(p, &x,
sizeof x);
44 auto x =
static_cast<std::uint8_t
>(v);
45 std::memcpy(p, &x,
sizeof x);
49 auto x =
static_cast<std::int16_t
>(v);
50 std::memcpy(p, &x,
sizeof x);
54 auto x =
static_cast<std::uint16_t
>(v);
55 std::memcpy(p, &x,
sizeof x);
59 auto x =
static_cast<std::int32_t
>(v);
60 std::memcpy(p, &x,
sizeof x);
64 auto x =
static_cast<std::uint32_t
>(v);
65 std::memcpy(p, &x,
sizeof x);
69 auto x =
static_cast<std::int64_t
>(v);
70 std::memcpy(p, &x,
sizeof x);
74 auto x =
static_cast<std::uint64_t
>(v);
75 std::memcpy(p, &x,
sizeof x);
87 std::int64_t loadPodInt(
const std::byte* p,
AccessKind kind) {
91 std::memcpy(&x, p,
sizeof x);
96 std::memcpy(&x, p,
sizeof x);
101 std::memcpy(&x, p,
sizeof x);
106 std::memcpy(&x, p,
sizeof x);
111 std::memcpy(&x, p,
sizeof x);
116 std::memcpy(&x, p,
sizeof x);
122 std::memcpy(&x, p,
sizeof x);
135 _facts.reserve(
schema.size());
136 _cols.resize(
schema.size());
137 for (std::size_t c = 0; c <
schema.size(); ++c) {
140 f.
kind = kindOf(col);
159 if (col.
isId && _idColumn == SIZE_MAX) _idColumn = c;
163 std::byte* ColumnRows::_podPtr(std::size_t record, std::size_t column, std::size_t element) {
164 const Facts& f = _facts[column];
165 return _cols[column].pod.data() + (record * f.podSlots + element) * f.elemBytes;
168 const std::byte* ColumnRows::_podPtr(std::size_t record, std::size_t column, std::size_t element)
const {
169 const Facts& f = _facts[column];
170 return _cols[column].pod.data() + (record * f.podSlots + element) * f.elemBytes;
174 for (Store& s : _cols) {
183 for (std::size_t c = 0; c < _cols.size(); ++c) {
184 const Facts& f = _facts[c];
187 if (f.
hasFlags) _cols[c].flags.reserve(n);
192 for (std::size_t c = 0; c < _cols.size(); ++c) {
193 const Facts& f = _facts[c];
195 _cols[c].pod.resize(_cols[c].pod.size() + std::size_t{f.podSlots} * f.
elemBytes, std::byte{0});
196 if (f.
strSlots != 0) _cols[c].strs.resize(_cols[c].strs.size() + f.
strSlots);
197 if (f.
hasFlags) _cols[c].flags.push_back(0);
205 if (_idColumn == SIZE_MAX)
return 0;
206 return static_cast<std::uint32_t
>(loadPodInt(_podPtr(record, _idColumn, 0), _facts[_idColumn].kind));
209 void ColumnRows::setInt(std::size_t record, std::size_t column, std::size_t element, std::int64_t value) {
210 const Facts& f = _facts[column];
212 _cols[column].flags[record] =
static_cast<std::uint32_t
>(value);
220 if (_facts[column].kind ==
AccessKind::F32) std::memcpy(_podPtr(record, column, element), &value,
sizeof value);
224 const Facts& f = _facts[column];
225 if (f.
strSlots != 0) _cols[column].strs[record * f.
strSlots + element] = std::string{value};
229 const std::size_t fresh =
add();
230 for (std::size_t c = 0; c < _cols.size(); ++c) {
231 const Facts& f = _facts[c];
235 std::memcpy(s.pod.data() + fresh * stride, s.pod.data() + src * stride, stride);
238 if (f.
hasFlags) s.flags[fresh] = s.flags[src];
240 if (_idColumn != SIZE_MAX)
241 storePodInt(_podPtr(fresh, _idColumn, 0), _facts[_idColumn].kind, newId);
245 for (std::size_t r = 0; r < _rows; ++r)
246 if (
idOf(r) ==
id)
return r;
251 const Facts& f = _facts[column];
255 return loadPodInt(_podPtr(record, column, element), f.
kind);
259 const Facts& f = _facts[column];
263 std::memcpy(&x, _podPtr(record, column, element),
sizeof x);
270 return static_cast<std::uint32_t
>(loadPodInt(_podPtr(record, column, element), f.
kind));
275 const Facts& f = _facts[column];
277 return _cols[column].strs[record * f.
strSlots + element];
281 for (std::size_t c = 0; c < _cols.size(); ++c) {
282 const Facts& f = _facts[c];
286 s.pod.erase(s.pod.begin() +
static_cast<std::ptrdiff_t
>(record * stride),
287 s.pod.begin() +
static_cast<std::ptrdiff_t
>((record + 1) * stride));
290 s.strs.erase(s.strs.begin() +
static_cast<std::ptrdiff_t
>(record * f.
strSlots),
291 s.strs.begin() +
static_cast<std::ptrdiff_t
>((record + 1) * f.
strSlots));
292 if (f.
hasFlags) s.flags.erase(s.flags.begin() +
static_cast<std::ptrdiff_t
>(record));
298 return _cols[column].strs[record * _facts[column].strSlots + element];
302 return _cols[column].flags[record];
306 return _cols[column].flags[record];
312#if WOWLIB_DB_SCHEMA_EMBEDDED
314 DynTable::open(std::string_view table,
ClientVersion version) {
326 out._diskName =
schema.diskName;
332 :
TableBase{other}, _rows{other._rows}, _version{other._version}, _name{other._name}, _diskName{other._diskName} {
337 if (
this == &other)
return *
this;
338 TableBase::operator=(other);
340 _version = other._version;
342 _diskName = other._diskName;
349 _rows{std::move(other._rows)},
350 _version{other._version},
352 _diskName{other._diskName} {
357 if (
this == &other)
return *
this;
358 TableBase::operator=(std::move(other));
359 _rows = std::move(other._rows);
360 _version = other._version;
362 _diskName = other._diskName;
368 const std::span<const Column>
schema = _rows.schema();
369 if (column >=
schema.size())
371 std::format(
"{}: column {} out of range ({} columns)", _name, column,
schema.size()));
376 const std::span<const Column>
schema = _rows.schema();
380 for (std::size_t c = 0; c <
schema.size(); ++c)
382 for (std::size_t c = 0; c <
schema.size(); ++c)
383 if (!
schema[c].dbdNameView().empty() &&
schema[c].dbdNameView() ==
name)
return c;
388 if (row >= _rows.size())
390 std::format(
"{}: row {} out of range ({} rows)", _name, row, _rows.size()));
396 const std::size_t at = _rows.findById(recordId);
397 if (at == _rows.size())
407 if (row >= _rows.
size() || column >=
schema.size())
409 std::format(
"{}: cell ({}, {}) out of range ({} rows, " "{} columns)", _name, row, column,
412 if (col.
type != expected)
418 if (element >= slots)
420 std::format(
"{}.{}: element {} out of range ({} slots)", _name, col.
nameView(), element,
426 return _checkCell(row, column, element,
ColumnType::Int).transform([&](
auto) {
427 return _rows.getInt(row, column, element);
432 return _checkCell(row, column, element,
ColumnType::Int).transform([&](
auto) {
433 _rows.setInt(row, column, element, value);
440 std::memcpy(&out, _rows.podBytes(column).data() + (row * _rows.facts(column).podSlots + element) * 4,
448 _rows.setFloat(row, column, element, value);
454 if (str)
return _rows.getString(row, column, element);
457 return _rows.getString(row, column, element);
464 _rows.setString(row, column, element, value);
468 _rows.setString(row, column, element, value);
474 return _rows.flagsSlot(row, column);
480 _rows.flagsSlot(row, column) = flags;
485 const std::span<const Column>
schema = _rows.schema();
486 if (column >=
schema.size())
488 std::format(
"{}: column {} out of range ({} columns)", _name, column,
schema.size()));
492 std::format(
"{}.{}: only numeric columns have a " "zero-copy view", _name, col.
nameView()));
495 out.
bytes = _rows.podBytes(column);
Result< void > setString(std::size_t row, std::size_t column, std::string_view value, std::size_t element=0)
Write a string element.
Result< Column > columnInfo(std::size_t column) const
Column column's schema entry, by value (the welded metadata face of schema).
static DynTable fromSchema(const TableSchema &schema, ClientVersion version)
Open a table over an explicitly resolved schema — the caller guarantees the schema's backing catalog ...
Result< std::string_view > getString(std::size_t row, std::size_t column, std::size_t element=0) const
Read a string element (String columns: the array element; LocString columns: the locale slot).
Result< void > setFloat(std::size_t row, std::size_t column, float value, std::size_t element=0)
Write a float element.
Result< PodColumnView > podColumn(std::size_t column) const
The zero-copy view of numeric/float column column.
Result< std::int64_t > getInt(std::size_t row, std::size_t column, std::size_t element=0) const
Read an integer element.
Result< std::uint32_t > locstringFlags(std::size_t row, std::size_t column) const
Read a LocString column's flags word.
std::string_view name() const
The table name (WoWDBDefs identifier).
Result< void > setLocstringFlags(std::size_t row, std::size_t column, std::uint32_t flags)
Write a LocString column's flags word.
DynTable()=default
An unwired table: every inherited operation reports InvalidEntityState until one is opened properly.
Result< void > eraseRow(std::size_t row)
Remove row row.
Result< void > setInt(std::size_t row, std::size_t column, std::int64_t value, std::size_t element=0)
Write an integer element (truncates to the column's exact width, as the typed member assignment did).
Result< float > getFloat(std::size_t row, std::size_t column, std::size_t element=0) const
Read a float element.
DynTable & operator=(const DynTable &other)
std::span< const Column > schema() const
ClientVersion version() const
The client version the table serializes for.
Result< std::size_t > columnIndex(std::string_view name) const
The index of column name.
Result< std::size_t > findById(std::uint32_t id) const
The first row whose $id$ equals id.
The welded supertype of every generated table class: the whole table surface — decode,...
The column-store row storage: one exact-width POD buffer per numeric column, one string vector per st...
std::uint32_t getSlot(std::size_t record, std::size_t column, std::size_t element) const override
std::size_t size() const override
One override serves both interfaces (identical signatures).
std::size_t findById(std::uint32_t id) const override
The first record whose id equals id, or size() when none (copy source lookup).
void setInt(std::size_t record, std::size_t column, std::size_t element, std::int64_t value) override
std::int64_t getInt(std::size_t record, std::size_t column, std::size_t element) const override
std::string_view getString(std::size_t record, std::size_t column, std::size_t element) const override
std::uint32_t & flagsSlot(std::size_t record, std::size_t column)
The LocString flags of record in column.
void setFloat(std::size_t record, std::size_t column, std::size_t element, float value) override
const Facts & facts(std::size_t column) const
void cloneWithId(std::size_t src, std::uint32_t newId) override
Clone record src into a fresh record and set its id column to newId (WDC copy-table materialization).
void reserve(std::size_t n) override
void setString(std::size_t record, std::size_t column, std::size_t element, std::string_view value) override
std::uint32_t idOf(std::size_t record) const override
std::size_t add() override
std::span< const Column > schema() const
std::string & stringSlot(std::size_t record, std::size_t column, std::size_t element)
Mutable string slot access (the public setter's target).
void eraseRow(std::size_t record)
Remove row record (all columns' slices).
DynTable — the generic, runtime-schema client-database table: the ONE table class every binding welds...
AccessKind
The storage kind of one record member, as the erased accessors see it: exact width and signedness for...
@ U64
Integer elements, by shape.
@ LocStr
A LocString<N>: strings at offset, flags on the side.
@ Str
A std::string element.
ColumnType
The logical value class of a column.
@ Int
An integer column; Column::bits / Column::isSigned give the shape.
@ Float
A 32-bit IEEE float column.
@ String
A string-block reference column (u32 offset on disk).
@ LocString
A pre-Cataclysm localized string column (see LocString).
std::expected< T, Error > Result
Every fallible wowlib operation returns Result<T>; bindings translate the error branch into a target-...
std::unexpected< Error > makeError(ErrorCode code, std::string message, std::uint32_t nativeError=0)
Shorthand for constructing the error branch of a Result.
@ TableUnknown
The schema catalog knows no table of the requested name.
@ SchemaMismatch
A client-database record layout disagrees with the generated WoWDBDefs schema.
@ OffsetOutOfBounds
An offset array (M2Array) points outside its base buffer.
constexpr std::string_view enumName(E value)
The enumerator name of value, straight from reflection — no handwritten stringification tables anywhe...
One column of a record schema, derived from a record member by reflection (typed records) or from the...
constexpr std::string_view nameView() const
The member spelling as a view.
std::uint8_t localeCount
LocString language slots (8 or 16); 0 otherwise.
bool isId
Whether this is the table's primary key ($id$).
std::uint16_t arrayLen
Element count; 1 for scalar columns.
ColumnType type
The logical value class.
std::uint8_t bits
Integer element width in bits; 32 for float/string refs.
bool isSigned
Integer signedness; false for non-Int columns.
A scalar column's whole storage, for zero-copy array views: the raw exact-width buffer plus the facts...
std::span< const std::byte > bytes
The buffer, row-major.
bool isFloat
float32 elements.
bool isSigned
Integer signedness.
std::uint16_t elemsPerRow
Array length (1 = scalar).
std::uint8_t elemBytes
element width in bytes.
One resolved (table, client version) schema: what SchemaCatalog::lookup hands the engine.
The per-column access facts, derived from the schema at bind.
std::uint8_t elemBytes
POD element width; 0 for strings.
AccessKind kind
The element storage kind.
bool hasFlags
LocString: a flags word per row.
std::uint16_t strSlots
String slots per row.
std::uint16_t podSlots
POD elements per row (arrayLen).