载入中...
搜索中...
未找到
AttributeTable.cpp
浏览该文件的文档.
2
3#include <algorithm>
4#include <utility>
5
6namespace eve::procgen {
7namespace {
8
9} // namespace
10
11std::size_t AttributeTable::rowCount() const noexcept { return rows_; }
12void AttributeTable::resize(std::size_t rows) {
13 for (auto& entry : columns_) std::visit([rows](auto& values) { values.resize(rows); }, entry.second.storage);
14 rows_ = rows;
15}
17 const std::size_t row = rows_;
18 resize(rows_ + 1);
19 return row;
20}
22 if (sourceRow >= source.rows_)
24 Diagnostic::error(DiagnosticCode::InvalidArgument, "source attribute row is out of range", "sourceRow"));
25
26 for (const std::string& name : source.order_) {
27 const auto sourceColumn = source.columns_.find(name);
28 const auto targetColumn = columns_.find(name);
29 if (targetColumn != columns_.end() && targetColumn->second.type != sourceColumn->second.type)
32 "attribute '" + name + "' has incompatible source and target schema types", "name"));
33 }
34
35 AttributeTable staged = *this;
36 const std::size_t row = staged.appendRow();
37 for (const std::string& name : source.order_) {
38 const auto& sourceColumn = source.columns_.at(name);
39 auto ensured = staged.ensureColumn(name, sourceColumn.type);
40 if (!ensured.ok()) return Result<std::size_t>::failure(ensured.status());
41 Column& targetColumn = *ensured.value();
42 std::visit(
43 [sourceRow, row, &sourceColumn](auto& targetValues) {
44 using Values = std::decay_t<decltype(targetValues)>;
45 const auto& sourceValues = std::get<Values>(sourceColumn.storage);
46 targetValues[row] = sourceValues[sourceRow];
47 },
48 targetColumn.storage);
49 }
50 *this = std::move(staged);
52}
54 if (row >= rows_) return Result<void>::failure(
55 Diagnostic::error(DiagnosticCode::InvalidArgument, "attribute row is out of range", "row"));
56 for (auto& entry : columns_) std::visit([row](auto& values) { values[row].reset(); }, entry.second.storage);
57 return Result<void>::success();
58}
59void AttributeTable::clear() noexcept {
60 rows_ = 0;
61 columns_.clear();
62 order_.clear();
63}
64std::size_t AttributeTable::columnCount() const noexcept { return order_.size(); }
65std::string_view AttributeTable::columnName(std::size_t index) const noexcept {
66 return index < order_.size() ? std::string_view(order_[index]) : std::string_view{};
67}
68std::optional<ProcgenAttributeType> AttributeTable::typeOf(std::string_view name) const {
69 const auto found = columns_.find(std::string(name));
70 return found == columns_.end() ? std::nullopt : std::optional<ProcgenAttributeType>{found->second.type};
71}
72bool AttributeTable::has(std::size_t row, std::string_view name) const {
73 const auto found = columns_.find(std::string(name));
74 if (found == columns_.end() || row >= rows_) return false;
75 return std::visit([row](const auto& values) { return values[row].has_value(); }, found->second.storage);
76}
77
78Result<void> AttributeTable::renameColumn(std::string_view from, std::string_view to) {
79 if (from.empty() || to.empty()) return Result<void>::failure(
80 Diagnostic::error(DiagnosticCode::InvalidArgument, "attribute name must not be empty", "name"));
81 if (!from.empty() && from.front() == '$')
83 Diagnostic::error(DiagnosticCode::InvalidArgument, "builtin selectors cannot be renamed", "from"));
84 if (!to.empty() && to.front() == '$')
86 Diagnostic::error(DiagnosticCode::InvalidArgument, "builtin selectors cannot be rename targets", "to"));
87 if (from == to) return Result<void>::success();
88 const std::string fromKey(from);
89 const std::string toKey(to);
90 const auto source = columns_.find(fromKey);
91 if (source == columns_.end())
93 Diagnostic::error(DiagnosticCode::NotFound, "attribute '" + fromKey + "' does not exist", "from"));
94 if (columns_.find(toKey) != columns_.end())
96 Diagnostic::error(DiagnosticCode::AlreadyExists, "attribute '" + toKey + "' already exists", "to"));
97
98 AttributeTable staged = *this;
99 auto moved = staged.columns_.extract(fromKey);
100 moved.key() = toKey;
101 staged.columns_.insert(std::move(moved));
102 for (std::string& name : staged.order_)
103 if (name == fromKey) {
104 name = toKey;
105 break;
106 }
107 *this = std::move(staged);
108 return Result<void>::success();
109}
110
112 if (name.empty()) return Result<void>::failure(
113 Diagnostic::error(DiagnosticCode::InvalidArgument, "attribute name must not be empty", "name"));
114 if (name.front() == '$') return Result<void>::failure(
115 Diagnostic::error(DiagnosticCode::InvalidArgument, "builtin selectors cannot be deleted", "name"));
116 const std::string key(name);
117 if (columns_.find(key) == columns_.end())
119 Diagnostic::error(DiagnosticCode::NotFound, "attribute '" + key + "' does not exist", "name"));
120
121 AttributeTable staged = *this;
122 staged.columns_.erase(key);
123 staged.order_.erase(std::remove(staged.order_.begin(), staged.order_.end(), key), staged.order_.end());
124 *this = std::move(staged);
125 return Result<void>::success();
126}
127
128Result<void> AttributeTable::copyColumn(std::string_view from, std::string_view to) {
129 if (from.empty() || to.empty()) return Result<void>::failure(
130 Diagnostic::error(DiagnosticCode::InvalidArgument, "attribute name must not be empty", "name"));
131 if (from.front() == '$' || to.front() == '$')
133 Diagnostic::error(DiagnosticCode::InvalidArgument, "copyColumn only supports metadata column names", "name"));
134 if (from == to) return Result<void>::success();
135 const std::string fromKey(from);
136 const std::string toKey(to);
137 const auto source = columns_.find(fromKey);
138 if (source == columns_.end())
140 Diagnostic::error(DiagnosticCode::NotFound, "attribute '" + fromKey + "' does not exist", "from"));
141
142 AttributeTable staged = *this;
143 auto ensured = staged.ensureColumn(toKey, source->second.type);
144 if (!ensured.ok()) return Result<void>::failure(ensured.status());
145 const auto stagedSource = staged.columns_.find(fromKey);
146 std::visit(
147 [&](auto& targetValues) {
148 using Values = std::decay_t<decltype(targetValues)>;
149 const auto& sourceValues = std::get<Values>(stagedSource->second.storage);
150 targetValues = sourceValues;
151 },
152 ensured.value()->storage);
153 *this = std::move(staged);
154 return Result<void>::success();
155}
156
157Result<AttributeTable::Column*> AttributeTable::ensureColumn(std::string_view name, ProcgenAttributeType type) {
158 const std::string key(name);
159 auto found = columns_.find(key);
160 if (found != columns_.end()) {
161 if (found->second.type != type) {
163 "attribute '" + std::string(name) + "' has schema type " +
164 std::string(procgenAttributeTypeName(found->second.type)) + ", not " +
165 std::string(procgenAttributeTypeName(type)),
166 "name"));
167 return Result<Column*>::failure(mismatch.status());
168 }
169 return Result<Column*>::success(&found->second);
170 }
171 Column replacement;
172 replacement.type = type;
173 switch (type) {
174 case ProcgenAttributeType::Float: replacement.storage = std::vector<std::optional<float>>(rows_); break;
175 case ProcgenAttributeType::Int: replacement.storage = std::vector<std::optional<std::int64_t>>(rows_); break;
176 case ProcgenAttributeType::Bool: replacement.storage = std::vector<std::optional<bool>>(rows_); break;
178 replacement.storage = std::vector<std::optional<ProcgenAttributeVector>>(rows_);
179 break;
180 case ProcgenAttributeType::String: replacement.storage = std::vector<std::optional<std::string>>(rows_); break;
181 }
182 auto inserted = columns_.emplace(key, std::move(replacement));
183 try {
184 order_.push_back(key);
185 } catch (...) {
186 columns_.erase(inserted.first);
187 throw;
188 }
189 return Result<Column*>::success(&inserted.first->second);
190}
191
192template <class T>
193Result<void> AttributeTable::set(std::size_t row, std::string_view name, ProcgenAttributeType type, T value) {
194 if (name.empty()) return Result<void>::failure(
195 Diagnostic::error(DiagnosticCode::InvalidArgument, "attribute name must not be empty", "name"));
196 if (row >= rows_) return Result<void>::failure(
197 Diagnostic::error(DiagnosticCode::InvalidArgument, "attribute row is out of range", "row"));
198 auto column = ensureColumn(name, type);
199 if (!column.ok()) return Result<void>::failure(column.status());
200 std::get<std::vector<std::optional<T>>>(column.value()->storage)[row] = std::move(value);
201 return Result<void>::success();
202}
203
204template <class T>
205std::optional<T> AttributeTable::get(std::size_t row, std::string_view name, ProcgenAttributeType type) const {
206 const auto found = columns_.find(std::string(name));
207 if (found == columns_.end() || found->second.type != type || row >= rows_) return std::nullopt;
208 return std::get<std::vector<std::optional<T>>>(found->second.storage)[row];
209}
210
211Result<void> AttributeTable::setFloat(std::size_t row, std::string_view name, float value) {
212 return set(row, name, ProcgenAttributeType::Float, value);
213}
214Result<void> AttributeTable::setInt(std::size_t row, std::string_view name, std::int64_t value) {
215 return set(row, name, ProcgenAttributeType::Int, value);
216}
217Result<void> AttributeTable::setBool(std::size_t row, std::string_view name, bool value) {
218 return set(row, name, ProcgenAttributeType::Bool, value);
219}
221 return set(row, name, ProcgenAttributeType::Vector, value);
222}
223Result<void> AttributeTable::setString(std::size_t row, std::string_view name, std::string value) {
224 return set(row, name, ProcgenAttributeType::String, std::move(value));
225}
226std::optional<float> AttributeTable::getFloat(std::size_t row, std::string_view name) const {
227 return get<float>(row, name, ProcgenAttributeType::Float);
228}
229std::optional<std::int64_t> AttributeTable::getInt(std::size_t row, std::string_view name) const {
230 return get<std::int64_t>(row, name, ProcgenAttributeType::Int);
231}
232std::optional<bool> AttributeTable::getBool(std::size_t row, std::string_view name) const {
233 return get<bool>(row, name, ProcgenAttributeType::Bool);
234}
235std::optional<ProcgenAttributeVector> AttributeTable::getVector(std::size_t row, std::string_view name) const {
236 return get<ProcgenAttributeVector>(row, name, ProcgenAttributeType::Vector);
237}
238std::optional<std::string_view> AttributeTable::getString(std::size_t row, std::string_view name) const {
239 const auto found = columns_.find(std::string(name));
240 if (found == columns_.end() || found->second.type != ProcgenAttributeType::String || row >= rows_)
241 return std::nullopt;
242 const auto& value = std::get<StringColumn>(found->second.storage)[row];
243 return value ? std::optional<std::string_view>(*value) : std::nullopt;
244}
245
247 switch (type) {
248 case ProcgenAttributeType::Float: return "float";
249 case ProcgenAttributeType::Int: return "int";
250 case ProcgenAttributeType::Bool: return "bool";
251 case ProcgenAttributeType::Vector: return "vector";
252 case ProcgenAttributeType::String: return "string";
253 }
254 return {};
255}
256
257} // namespace eve::procgen
double value
std::string from
int column
std::map< std::string, Var > values
int rows
std::uint32_t key
HexCoordinates to
Cell the unit walks towards on this segment.
Definition HexUnits.cpp:64
std::string name
bool found
uint32_t index
const UnitySourceAsset & source
static Diagnostic error(DiagnosticCode code, std::string message, std::string path={}, DiagnosticDetails details={}, std::string source={})
Construct an error diagnostic with the standard error severity.
Definition Diagnostic.h:125
Move-only operation result carrying either a value or Status.
Definition Result.h:155
static Result success(T value)
Construct a successful result owning value.
Definition Result.h:164
static Result failure(Status status)
Construct a failed result from a structured status.
Definition Result.h:175
Schema-bearing column store aligned with a PointSet's point rows.
std::optional< std::string_view > getString(std::size_t row, std::string_view name) const
Borrow a string value until the next table mutation, or return no value.
Result< void > copyColumn(std::string_view from, std::string_view to)
Copy one typed column onto another name, creating or overwriting a compatible target.
std::optional< std::int64_t > getInt(std::size_t row, std::string_view name) const
Read an integer value, or no value for an absent row, name, or type.
bool has(std::size_t row, std::string_view name) const
Return whether a row contains a value in the named column.
std::optional< ProcgenAttributeVector > getVector(std::size_t row, std::string_view name) const
Read a vector value, or no value for an absent row, name, or type.
std::size_t appendRow()
Append one empty row and return its stable row index.
std::size_t columnCount() const noexcept
Return the number of declared columns.
std::size_t rowCount() const noexcept
Return the number of aligned point rows.
std::optional< bool > getBool(std::size_t row, std::string_view name) const
Read a Boolean value, or no value for an absent row, name, or type.
Result< void > removeColumn(std::string_view name)
Remove one metadata column and its values from every row.
Result< void > setBool(std::size_t row, std::string_view name, bool value)
Set a Boolean value, rejecting an incompatible existing schema.
void clear() noexcept
Remove all rows and schema columns.
Result< void > setInt(std::size_t row, std::string_view name, std::int64_t value)
Set an integer value, rejecting an incompatible existing schema.
Result< void > setFloat(std::size_t row, std::string_view name, float value)
Set a float value, rejecting an incompatible existing schema.
Result< std::size_t > appendRowFrom(const AttributeTable &source, std::size_t sourceRow)
Append one row copied from another table, merging compatible schema columns.
std::string_view columnName(std::size_t index) const noexcept
Return a stable insertion-ordered column name or an empty string.
Result< void > setVector(std::size_t row, std::string_view name, ProcgenAttributeVector value)
Set a vector value, rejecting an incompatible existing schema.
Result< void > renameColumn(std::string_view from, std::string_view to)
Rename one metadata column without changing values or type.
Result< void > setString(std::size_t row, std::string_view name, std::string value)
Set a string value, rejecting an incompatible existing schema.
void resize(std::size_t rows)
Resize every column to the same row count.
Result< void > clearRow(std::size_t row)
Clear every value in one row while preserving the table schema.
std::optional< float > getFloat(std::size_t row, std::string_view name) const
Read a float value, or no value for an absent row, name, or type.
std::optional< ProcgenAttributeType > typeOf(std::string_view name) const
Return the declared type for a name, or no value when absent.
ProcgenAttributeType
Closed set of column types supported by procedural point metadata.
std::string_view procgenAttributeTypeName(ProcgenAttributeType type) noexcept
Return the stable script/persistence name for an attribute type.
@ TypeMismatch
A stable reference resolved to a different canonical domain type.
Compact three-component value used by typed procedural metadata.