[ox/model] Fix infinite recursion caused by have a vector of the same type in ModelValue

This commit is contained in:
Gary Talent 2023-12-22 19:44:04 -06:00
parent 80d0df2f46
commit ef6e3af735
5 changed files with 33 additions and 22 deletions

View File

@ -265,10 +265,10 @@ constexpr Error MetalClawReaderTemplate<Reader>::field(const char *name, T *val)
// set size of val if the field is present, don't worry about it if not // set size of val if the field is present, don't worry about it if not
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
oxRequire(len, arrayLength(name, false)); oxRequire(len, arrayLength(name, false));
val->resize(len); oxReturnError(ox::resizeVector(*val, len));
return field(name, val->data(), val->size()); return field(name, val->data(), val->size());
} }
val->resize(0); oxReturnError(ox::resizeVector(*val, 0));
} }
++m_field; ++m_field;
return {}; return {};
@ -302,12 +302,12 @@ template<typename U, bool force>
constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, UnionView<U, force> val) noexcept { constexpr Error MetalClawReaderTemplate<Reader>::field(const char*, UnionView<U, force> val) noexcept {
if ((!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) && val.get()) { if ((!m_unionIdx.has_value() || static_cast<std::size_t>(*m_unionIdx) == m_field) && val.get()) {
if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) { if (m_fieldPresence.get(static_cast<std::size_t>(m_field))) {
auto reader = child("", ox::Optional<int>(ox::in_place_t{}, val.idx())); auto reader = child("", ox::Optional<int>(ox::in_place, val.idx()));
oxReturnError(model(reader.interface(), val.get())); oxReturnError(model(reader.interface(), val.get()));
} }
} }
++m_field; ++m_field;
return OxError(0); return {};
} }
template<Reader_c Reader> template<Reader_c Reader>

View File

@ -261,15 +261,16 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const T *val) noexce
} else { } else {
bool fieldSet = false; bool fieldSet = false;
if (val && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) { if (val && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
auto const writeIdx = m_writer.tellp();
MetalClawWriter<Writer> writer(m_writer); MetalClawWriter<Writer> writer(m_writer);
ModelHandlerInterface<MetalClawWriter<Writer>> handler{&writer}; ModelHandlerInterface<MetalClawWriter<Writer>> handler{&writer};
oxReturnError(model(&handler, val)); oxReturnError(model(&handler, val));
oxReturnError(writer.finalize()); oxReturnError(writer.finalize());
fieldSet = true; fieldSet = writeIdx != m_writer.tellp();
} }
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field; ++m_field;
return OxError(0); return {};
} }
} }
@ -278,15 +279,16 @@ template<typename U, bool force>
constexpr Error MetalClawWriter<Writer>::field(const char*, UnionView<U, force> val) noexcept { constexpr Error MetalClawWriter<Writer>::field(const char*, UnionView<U, force> val) noexcept {
bool fieldSet = false; bool fieldSet = false;
if (val.get() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) { if (val.get() && (!m_unionIdx.has_value() || *m_unionIdx == m_field)) {
auto const writeIdx = m_writer.tellp();
MetalClawWriter<Writer> writer(m_writer, ox::Optional<int>(ox::in_place, val.idx())); MetalClawWriter<Writer> writer(m_writer, ox::Optional<int>(ox::in_place, val.idx()));
ModelHandlerInterface handler{&writer}; ModelHandlerInterface handler{&writer};
oxReturnError(model(&handler, val.get())); oxReturnError(model(&handler, val.get()));
oxReturnError(writer.finalize()); oxReturnError(writer.finalize());
fieldSet = true; fieldSet = writeIdx != m_writer.tellp();
} }
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field; ++m_field;
return OxError(0); return {};
} }
template<Writer_c Writer> template<Writer_c Writer>
@ -297,15 +299,16 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const T *val, std::s
// write the length // write the length
const auto arrLen = mc::encodeInteger(len); const auto arrLen = mc::encodeInteger(len);
oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data), arrLen.length)); oxReturnError(m_writer.write(reinterpret_cast<const char*>(arrLen.data), arrLen.length));
auto const writeIdx = m_writer.tellp();
MetalClawWriter<Writer> writer(m_writer); MetalClawWriter<Writer> writer(m_writer);
ModelHandlerInterface handler{&writer}; ModelHandlerInterface handler{&writer};
oxReturnError(handler.template setTypeInfo<T>("List", 0, {}, static_cast<std::size_t>(len))); oxReturnError(handler.template setTypeInfo<T>("List", 0, {}, static_cast<std::size_t>(len)));
// write the array // write the array
for (std::size_t i = 0; i < len; i++) { for (std::size_t i = 0; i < len; ++i) {
oxReturnError(handler.field("", &val[i])); oxReturnError(handler.field("", &val[i]));
} }
oxReturnError(writer.finalize()); oxReturnError(writer.finalize());
fieldSet = true; fieldSet = writeIdx != m_writer.tellp();
} }
oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet)); oxReturnError(m_fieldPresence.set(static_cast<std::size_t>(m_field), fieldSet));
++m_field; ++m_field;
@ -337,7 +340,7 @@ constexpr Error MetalClawWriter<Writer>::field(const char*, const HashMap<String
return handler.field("", value); return handler.field("", value);
}; };
// write the array // write the array
for (std::size_t i = 0; i < len; i++) { for (std::size_t i = 0; i < len; ++i) {
auto const&key = keys[i]; auto const&key = keys[i];
oxReturnError(loopBody(handler, key, *val)); oxReturnError(loopBody(handler, key, *val));
} }

View File

@ -196,7 +196,6 @@ class ModelHandlerInterface {
constexpr auto handler() noexcept { constexpr auto handler() noexcept {
return m_handler; return m_handler;
} }
}; };
template<typename Handler, ox::OpType opType_v = Handler::opType()> template<typename Handler, ox::OpType opType_v = Handler::opType()>
@ -215,7 +214,16 @@ class ModelHandlerBase {
static constexpr ox::OpType opType() noexcept { static constexpr ox::OpType opType() noexcept {
return opType_v; return opType_v;
} }
}; };
constexpr ox::Error resizeVector(auto &vec, size_t sz) {
if constexpr(ox::is_same_v<decltype(vec.resize(0)), ox::Error>) {
return vec.resize(sz);
} else {
vec.resize(sz);
return {};
}
}
} }

View File

@ -202,7 +202,8 @@ class ModelValue {
class ModelValueVector { class ModelValueVector {
private: private:
Vector<ModelValue> m_vec; Vector<ModelValue> m_vec;
ModelValue m_templateValue; const DescriptorType *m_type = nullptr;
int m_typeSubscriptLevels = 0;
String m_typeName; String m_typeName;
int m_typeVersion = 0; int m_typeVersion = 0;
@ -227,14 +228,15 @@ class ModelValueVector {
return m_vec.data(); return m_vec.data();
} }
constexpr void resize(std::size_t sz) noexcept { constexpr ox::Error resize(std::size_t sz) noexcept {
const auto oldSz = m_vec.size(); const auto oldSz = m_vec.size();
m_vec.resize(sz); m_vec.resize(sz);
if (sz > oldSz) { if (sz > oldSz) {
for (auto i = oldSz; i < sz; ++i) { for (auto i = oldSz; i < sz; ++i) {
m_vec[i] = m_templateValue; oxReturnError(m_vec[i].setType(m_type, m_typeSubscriptLevels));
} }
} }
return {};
} }
[[nodiscard]] [[nodiscard]]
@ -248,7 +250,9 @@ class ModelValueVector {
} }
constexpr Error setType(const DescriptorType *type, int subscriptLevels) noexcept { constexpr Error setType(const DescriptorType *type, int subscriptLevels) noexcept {
return m_templateValue.setType(type, subscriptLevels); m_type = type;
m_typeSubscriptLevels = subscriptLevels;
return {};
} }
[[nodiscard]] [[nodiscard]]
@ -1089,14 +1093,12 @@ constexpr ModelValueVector::ModelValueVector(const ModelValueVector &other) noex
for (auto &v : other.m_vec) { for (auto &v : other.m_vec) {
m_vec.emplace_back(v); m_vec.emplace_back(v);
} }
m_templateValue = other.m_templateValue;
m_typeName = other.m_typeName; m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion; m_typeVersion = other.m_typeVersion;
} }
constexpr ModelValueVector::ModelValueVector(ModelValueVector &&other) noexcept { constexpr ModelValueVector::ModelValueVector(ModelValueVector &&other) noexcept {
m_vec = std::move(other.m_vec); m_vec = std::move(other.m_vec);
m_templateValue = std::move(other.m_templateValue);
m_typeName = std::move(other.m_typeName); m_typeName = std::move(other.m_typeName);
m_typeVersion = other.m_typeVersion; m_typeVersion = other.m_typeVersion;
} }
@ -1108,7 +1110,6 @@ constexpr ModelValueVector &ModelValueVector::operator=(const ModelValueVector &
for (auto &v : other.m_vec) { for (auto &v : other.m_vec) {
m_vec.emplace_back(v); m_vec.emplace_back(v);
} }
m_templateValue = other.m_templateValue;
m_typeName = other.m_typeName; m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion; m_typeVersion = other.m_typeVersion;
return *this; return *this;
@ -1119,7 +1120,6 @@ constexpr ModelValueVector &ModelValueVector::operator=(ModelValueVector &&other
return *this; return *this;
} }
m_vec = std::move(other.m_vec); m_vec = std::move(other.m_vec);
m_templateValue = std::move(other.m_templateValue);
m_typeName = std::move(other.m_typeName); m_typeName = std::move(other.m_typeName);
m_typeVersion = other.m_typeVersion; m_typeVersion = other.m_typeVersion;
return *this; return *this;

View File

@ -147,7 +147,7 @@ Error OrganicClawReader::field(const char *key, T *val) noexcept {
if constexpr(isVector_v<T>) { if constexpr(isVector_v<T>) {
const auto &srcVal = value(key); const auto &srcVal = value(key);
const auto srcSize = srcVal.size(); const auto srcSize = srcVal.size();
val->resize(srcSize); oxReturnError(ox::resizeVector(*val, srcSize));
err = field(key, val->data(), val->size()); err = field(key, val->data(), val->size());
} else if constexpr(isArray_v<T>) { } else if constexpr(isArray_v<T>) {
const auto &srcVal = value(key); const auto &srcVal = value(key);