载入中...
搜索中...
未找到
Params.cpp
浏览该文件的文档.
1#include "procgen/Params.h"
2
3#include <algorithm>
4#include <cmath>
5#include <limits>
6#include <locale>
7#include <optional>
8#include <sstream>
9#include <string_view>
10
11namespace eve::procgen {
12namespace {
13
14constexpr std::string_view kSeedKey = "seed";
15constexpr std::string_view kWidthKey = "width";
16constexpr std::string_view kHeightKey = "height";
17
18void appendLength(std::string& output, std::string_view value) {
19 output += std::to_string(value.size());
20 output.push_back(':');
21 output.append(value.data(), value.size());
22}
23
24std::string doubleToken(double value) {
25 if (std::isnan(value)) return "nan";
26 if (std::isinf(value)) return std::signbit(value) ? "-inf" : "+inf";
27
28 std::ostringstream stream;
29 stream.imbue(std::locale::classic());
30 stream.precision(std::numeric_limits<double>::max_digits10);
31 stream << value;
32 return stream.str();
33}
34
35std::string canonicalValue(const eve::Value& value) {
36 switch (value.type()) {
37 case eve::Value::Type::Null: return "null";
38 case eve::Value::Type::Bool: return std::string("bool:") + (value.asBool() ? "1" : "0");
39 case eve::Value::Type::Int64: return "int:" + std::to_string(value.asInt());
40 case eve::Value::Type::Double: return "double:" + doubleToken(value.asDouble());
42 const std::string& text = value.asString();
43 std::string result = "string:";
44 appendLength(result, text);
45 return result;
46 }
48 std::string result = "array:";
49 const auto* array = value.getIf<eve::Value::Array>();
50 result += std::to_string(array ? array->size() : 0);
51 result.push_back(':');
52 if (array) {
53 for (const eve::Value& element : *array) {
54 const std::string encoded = canonicalValue(element);
55 appendLength(result, encoded);
56 }
57 }
58 return result;
59 }
61 std::string result = "object:";
62 const auto* object = value.getIf<eve::Value::Object>();
63 result += std::to_string(object ? object->size() : 0);
64 result.push_back(':');
65 if (object) {
66 for (const auto& [key, member] : *object) {
67 appendLength(result, key);
68 const std::string encoded = canonicalValue(member);
69 appendLength(result, encoded);
70 }
71 }
72 return result;
73 }
74 }
75 return "null";
76}
77
78const eve::Value* findValue(const eve::Value::Object& values, const std::string& key) noexcept {
79 const auto it = values.find(key);
80 return it == values.end() ? nullptr : &it->second;
81}
82
83std::optional<int> asInt(const eve::Value& value) {
84 if (const auto* integer = value.getIf<std::int64_t>()) {
85 if (*integer < std::numeric_limits<int>::lowest() || *integer > std::numeric_limits<int>::max())
86 return std::nullopt;
87 return static_cast<int>(*integer);
88 }
89 if (const auto* boolean = value.getIf<bool>()) return *boolean ? 1 : 0;
90 if (const auto* number = value.getIf<double>()) {
91 if (!std::isfinite(*number) || std::trunc(*number) != *number ||
92 *number < static_cast<double>(std::numeric_limits<int>::lowest()) ||
93 *number > static_cast<double>(std::numeric_limits<int>::max()))
94 return std::nullopt;
95 return static_cast<int>(*number);
96 }
97 return std::nullopt;
98}
99
100std::optional<float> asFloat(const eve::Value& value) {
101 if (const auto* boolean = value.getIf<bool>()) return *boolean ? 1.f : 0.f;
102 if (const auto* integer = value.getIf<std::int64_t>()) {
103 const float converted = static_cast<float>(*integer);
104 return std::isfinite(converted) ? std::optional<float>(converted) : std::nullopt;
105 }
106 if (const auto* number = value.getIf<double>()) {
107 if (!std::isfinite(*number)) return std::nullopt;
108 const float converted = static_cast<float>(*number);
109 return std::isfinite(converted) ? std::optional<float>(converted) : std::nullopt;
110 }
111 return std::nullopt;
112}
113
114std::optional<bool> asBool(const eve::Value& value) {
115 if (const auto* boolean = value.getIf<bool>()) return *boolean;
116 if (const auto* integer = value.getIf<std::int64_t>()) {
117 if (*integer == 0) return false;
118 if (*integer == 1) return true;
119 return std::nullopt;
120 }
121 if (const auto* number = value.getIf<double>()) {
122 if (!std::isfinite(*number)) return std::nullopt;
123 if (*number == 0.0) return false;
124 if (*number == 1.0) return true;
125 }
126 return std::nullopt;
127}
128
129void appendField(std::string& output, std::string_view domain, std::string_view key, const eve::Value& value) {
130 appendLength(output, domain);
131 appendLength(output, key);
132 const std::string encoded = canonicalValue(value);
133 appendLength(output, encoded);
134 output.push_back(';');
135}
136
137} // namespace
138
139void Params::setSeed(uint32_t seed) { seed_ = seed; }
140uint32_t Params::getSeed() const { return seed_; }
141
143 width_ = width > 0 ? width : 1;
144 height_ = height > 0 ? height : 1;
145}
146int Params::getWidth() const { return width_; }
147int Params::getHeight() const { return height_; }
148
149void Params::setInt(const std::string& key, int value) {
150 if (key == kSeedKey) {
151 seed_ = static_cast<uint32_t>(std::max(0, value));
152 return;
153 }
154 if (key == kWidthKey) {
155 width_ = value > 0 ? value : 1;
156 return;
157 }
158 if (key == kHeightKey) {
159 height_ = value > 0 ? value : 1;
160 return;
161 }
162 values_[key] = eve::Value(static_cast<std::int64_t>(value));
163}
164
165void Params::setFloat(const std::string& key, float value) { values_[key] = eve::Value(static_cast<double>(value)); }
166
167void Params::setBool(const std::string& key, bool value) { values_[key] = eve::Value(value); }
168
169void Params::setString(const std::string& key, const std::string& value) { values_[key] = eve::Value(value); }
170
171bool Params::has(const std::string& key) const {
172 if (key == kSeedKey || key == kWidthKey || key == kHeightKey) return true;
173 return values_.find(key) != values_.end();
174}
175
176int Params::getInt(const std::string& key, int defaultValue) const {
177 if (key == kSeedKey) {
178 return seed_ <= static_cast<uint32_t>(std::numeric_limits<int>::max()) ? static_cast<int>(seed_) : defaultValue;
179 }
180 if (key == kWidthKey) return width_;
181 if (key == kHeightKey) return height_;
182 const eve::Value* value = findValue(values_, key);
183 if (!value) return defaultValue;
184 const auto converted = asInt(*value);
185 return converted ? *converted : defaultValue;
186}
187
188float Params::getFloat(const std::string& key, float defaultValue) const {
189 const eve::Value* value = findValue(values_, key);
190 if (!value) return defaultValue;
191 const auto converted = asFloat(*value);
192 return converted ? *converted : defaultValue;
193}
194
195bool Params::getBool(const std::string& key, bool defaultValue) const {
196 const eve::Value* value = findValue(values_, key);
197 if (!value) return defaultValue;
198 const auto converted = asBool(*value);
199 return converted ? *converted : defaultValue;
200}
201
202std::string Params::getString(const std::string& key, const std::string& defaultValue) const {
203 const eve::Value* value = findValue(values_, key);
204 if (!value) return defaultValue;
205 const auto* text = value->getIf<std::string>();
206 return text ? *text : defaultValue;
207}
208
209std::string Params::canonicalString() const {
210 std::string result = "params:v2;";
211 // Dimensions live in their own domain so an algorithm parameter named
212 // "width" or "height" cannot collide with setSize().
213 appendField(result, "dimension", kHeightKey, eve::Value(static_cast<std::int64_t>(height_)));
214 appendField(result, "dimension", kSeedKey, eve::Value(static_cast<std::int64_t>(seed_)));
215 appendField(result, "dimension", kWidthKey, eve::Value(static_cast<std::int64_t>(width_)));
216 for (const auto& [key, value] : values_) appendField(result, "parameter", key, value);
217 return result;
218}
219
220} // namespace eve::procgen
double value
std::string output
std::map< std::string, Var > values
std::uint32_t key
std::uint32_t height
std::uint32_t width
std::string text
std::uint32_t seed
Definition PointSet.cpp:807
double number
bool boolean
std::string element
Json object
float(ui::Theme::* member)[4]
The canonical owning dynamic value used by data-facing protocols.
Definition Value.h:31
std::map< std::string, Value > Object
Definition Value.h:34
std::vector< Value > Array
Definition Value.h:33
Value * find(const std::string &key) noexcept
Return an object member, or nullptr when absent.
Definition Value.cpp:124
uint32_t getSeed() const
Return the deterministic generation seed.
Definition Params.cpp:140
void setSize(int width, int height)
Set the generation dimensions, clamping each non-positive value to one.
Definition Params.cpp:142
bool getBool(const std::string &key, bool defaultValue) const
Read a boolean parameter without parsing text.
Definition Params.cpp:195
void setInt(const std::string &key, int value)
Store an Int64 parameter, preserving its numeric Value kind.
Definition Params.cpp:149
int getHeight() const
Return the generation height.
Definition Params.cpp:147
int getWidth() const
Return the generation width.
Definition Params.cpp:146
void setBool(const std::string &key, bool value)
Stores a boolean generation parameter.
Definition Params.cpp:167
bool has(const std::string &key) const
Return whether a parameter or one of the three dimensions exists.
Definition Params.cpp:171
float getFloat(const std::string &key, float defaultValue) const
Read a floating parameter with explicit numeric conversion rules.
Definition Params.cpp:188
std::string canonicalString() const
Return a deterministic serialization of all generation parameters.
Definition Params.cpp:209
void setSeed(uint32_t seed)
Set the deterministic seed used by generation.
Definition Params.cpp:139
void setFloat(const std::string &key, float value)
Store a finite or non-finite floating parameter as Value::Double without text conversion.
Definition Params.cpp:165
std::string getString(const std::string &key, const std::string &defaultValue) const
Read only a Value::String parameter; numeric/bool values are not stringified.
Definition Params.cpp:202
int getInt(const std::string &key, int defaultValue) const
Read an integer parameter with explicit numeric conversion rules.
Definition Params.cpp:176
void setString(const std::string &key, const std::string &value)
Store an owning string parameter as Value::String.
Definition Params.cpp:169
const char * defaultValue