[nostalgia/studio] Add ClawViewer for unknown types

This commit is contained in:
Gary Talent 2022-12-15 01:36:55 -06:00
parent 79d255b63f
commit 44f45e64e9
16 changed files with 505 additions and 75 deletions

View File

@ -44,7 +44,7 @@ else()
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat=2") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat=2")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-field-initializers") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-field-initializers")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor")
#set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnull-dereference") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wno-null-dereference")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")

View File

@ -56,7 +56,7 @@ if(NOT MSVC)
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat=2") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wformat=2")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-field-initializers") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wmissing-field-initializers")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnon-virtual-dtor")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnull-dereference") #set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wnull-dereference")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wold-style-cast")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Woverloaded-virtual")
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic") set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Wpedantic")

View File

@ -13,6 +13,7 @@
#include <ox/std/string.hpp> #include <ox/std/string.hpp>
#include <ox/std/trace.hpp> #include <ox/std/trace.hpp>
#include <ox/std/types.hpp> #include <ox/std/types.hpp>
#include <ox/std/utility.hpp>
#include <ox/std/vector.hpp> #include <ox/std/vector.hpp>
#include "def.hpp" #include "def.hpp"
@ -279,6 +280,11 @@ class ModelValueVector {
return m_vec.begin(); return m_vec.begin();
} }
[[nodiscard]]
auto begin() const noexcept {
return m_vec.cbegin();
}
[[nodiscard]] [[nodiscard]]
auto cbegin() const noexcept { auto cbegin() const noexcept {
return m_vec.cbegin(); return m_vec.cbegin();
@ -299,6 +305,11 @@ class ModelValueVector {
return m_vec.end(); return m_vec.end();
} }
[[nodiscard]]
auto end() const noexcept {
return m_vec.cend();
}
[[nodiscard]] [[nodiscard]]
auto cend() const noexcept { auto cend() const noexcept {
return m_vec.cend(); return m_vec.cend();
@ -321,18 +332,17 @@ consteval bool isVector(const ModelValueVector*) noexcept {
} }
class ModelObject { class ModelObject {
protected: public:
struct Field { struct Field {
String name; String name;
ModelValue value; ModelValue value;
}; };
protected:
oxModelFriend(ModelObject); oxModelFriend(ModelObject);
friend ModelValue; friend ModelValue;
Vector<UniquePtr<Field>> m_fieldsOrder; Vector<UniquePtr<Field>> m_fieldsOrder;
HashMap<String, ModelValue*> m_fields; HashMap<String, ModelValue*> m_fields;
const DescriptorType *m_type = nullptr; const DescriptorType *m_type = nullptr;
String m_typeName;
int m_typeVersion = 0;
public: public:
constexpr ModelObject() noexcept = default; constexpr ModelObject() noexcept = default;
@ -343,16 +353,12 @@ class ModelObject {
m_fields[field->name] = &field->value; m_fields[field->name] = &field->value;
} }
m_type = other.m_type; m_type = other.m_type;
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
} }
constexpr ModelObject(ModelObject &&other) noexcept { constexpr ModelObject(ModelObject &&other) noexcept {
m_fields = std::move(other.m_fields); m_fields = std::move(other.m_fields);
m_type = other.m_type; m_type = other.m_type;
m_fieldsOrder = std::move(other.m_fieldsOrder); m_fieldsOrder = std::move(other.m_fieldsOrder);
m_typeName = std::move(other.m_typeName);
m_typeVersion = other.m_typeVersion;
} }
[[nodiscard]] [[nodiscard]]
@ -424,8 +430,6 @@ class ModelObject {
m_fields[field->name] = &field->value; m_fields[field->name] = &field->value;
} }
m_type = other.m_type; m_type = other.m_type;
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
return *this; return *this;
} }
@ -436,17 +440,35 @@ class ModelObject {
m_type = other.m_type; m_type = other.m_type;
m_fields = std::move(other.m_fields); m_fields = std::move(other.m_fields);
m_fieldsOrder = std::move(other.m_fieldsOrder); m_fieldsOrder = std::move(other.m_fieldsOrder);
m_typeName = std::move(other.m_typeName);
m_typeVersion = other.m_typeVersion;
return *this; return *this;
} }
constexpr auto &operator[](const std::size_t &i) noexcept { template<typename T>
return *m_fieldsOrder[i]; constexpr auto set(const std::size_t &i, T &&val) noexcept {
auto &f = *m_fieldsOrder[i];
f = val;
}
constexpr Result<const ModelValue*> get(const String &k) const noexcept {
if (m_fields.contains(k)) {
return *m_fields.at(k).value;
}
return OxError(1);
}
template<typename T>
constexpr Error set(const String &k, T &&val) noexcept {
oxRequire(t, m_fields.at(k));
*t = ox::forward<T>(val);
return {};
} }
constexpr auto &operator[](const String &k) noexcept { constexpr auto &operator[](const String &k) noexcept {
return *m_fields[k]; auto [v, err] = m_fields.at(k);
if (err) [[unlikely]] {
oxPanic(err, ox::sfmt("field {} does not exist in type {}", k, buildTypeId(*m_type)).c_str());
}
return **v;
} }
constexpr auto &operator[](const std::size_t i) noexcept { constexpr auto &operator[](const std::size_t i) noexcept {
@ -454,13 +476,13 @@ class ModelObject {
} }
[[nodiscard]] [[nodiscard]]
constexpr StringView typeName() const noexcept { constexpr CRString typeName() const noexcept {
return m_typeName; return m_type->typeName;
} }
[[nodiscard]] [[nodiscard]]
constexpr int typeVersion() const noexcept { constexpr int typeVersion() const noexcept {
return m_typeVersion; return m_type->typeVersion;
} }
[[nodiscard]] [[nodiscard]]
@ -473,8 +495,6 @@ class ModelObject {
return OxError(1, "Cannot load a non-struct type to ModelObject"); return OxError(1, "Cannot load a non-struct type to ModelObject");
} }
m_type = type; m_type = type;
m_typeName = type->typeName;
m_typeVersion = type->typeVersion;
for (const auto &f : type->fieldList) { for (const auto &f : type->fieldList) {
auto field = make_unique<Field>(); auto field = make_unique<Field>();
field->name = f.fieldName; field->name = f.fieldName;
@ -498,8 +518,7 @@ class ModelUnion {
friend ModelValue; friend ModelValue;
Vector<UniquePtr<Field>> m_fieldsOrder; Vector<UniquePtr<Field>> m_fieldsOrder;
HashMap<String, Field*> m_fields; HashMap<String, Field*> m_fields;
String m_typeName; const DescriptorType *m_type = nullptr;
int m_typeVersion = 0;
int m_unionIdx = -1; int m_unionIdx = -1;
private: private:
@ -512,16 +531,12 @@ class ModelUnion {
m_fields[field->name] = field.get(); m_fields[field->name] = field.get();
++i; ++i;
} }
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
m_unionIdx = other.m_unionIdx; m_unionIdx = other.m_unionIdx;
} }
constexpr ModelUnion(ModelUnion &&other) noexcept { constexpr ModelUnion(ModelUnion &&other) noexcept {
m_fieldsOrder = std::move(other.m_fieldsOrder); m_fieldsOrder = std::move(other.m_fieldsOrder);
m_fields = std::move(other.m_fields); m_fields = std::move(other.m_fields);
m_typeName = std::move(other.m_typeName);
m_typeVersion = other.m_typeVersion;
m_unionIdx = other.m_unionIdx; m_unionIdx = other.m_unionIdx;
} }
@ -536,7 +551,11 @@ class ModelUnion {
} }
constexpr auto &operator[](const String &k) noexcept { constexpr auto &operator[](const String &k) noexcept {
return m_fields[k]->value; const auto [v, err] = m_fields.at(k);
if (err) [[unlikely]] {
oxPanic(err, ox::sfmt("field {} does not exist in type {}", k, buildTypeId(*m_type)).c_str());
}
return (*v)->value;
} }
constexpr auto &operator[](const std::size_t i) noexcept { constexpr auto &operator[](const std::size_t i) noexcept {
@ -558,13 +577,17 @@ class ModelUnion {
} }
[[nodiscard]] [[nodiscard]]
constexpr ModelValue &get(std::size_t i) noexcept { constexpr Result<const ModelValue*> get(std::size_t i) const noexcept {
return m_fieldsOrder[i]->value; if (i < m_fieldsOrder.size()) {
return &m_fieldsOrder[i]->value;
}
return {};
} }
[[nodiscard]] [[nodiscard]]
constexpr ModelValue &get(const String &k) noexcept { constexpr Result<const ModelValue*> get(const String &k) const noexcept {
return (*m_fields.at(k).value)->value; oxRequire(t, m_fields.at(k));
return &(*t)->value;
} }
[[nodiscard]] [[nodiscard]]
@ -580,12 +603,12 @@ class ModelUnion {
[[nodiscard]] [[nodiscard]]
constexpr const String &typeName() const noexcept { constexpr const String &typeName() const noexcept {
return m_typeName; return m_type->typeName;
} }
[[nodiscard]] [[nodiscard]]
constexpr int typeVersion() const noexcept { constexpr int typeVersion() const noexcept {
return m_typeVersion; return m_type->typeVersion;
} }
constexpr Error setType(const DescriptorType *type) noexcept { constexpr Error setType(const DescriptorType *type) noexcept {
@ -594,8 +617,7 @@ class ModelUnion {
} }
m_fields.clear(); m_fields.clear();
m_fieldsOrder.clear(); m_fieldsOrder.clear();
m_typeName = type->typeName; m_type = type;
m_typeVersion = type->typeVersion;
for (auto i = 0; const auto &f : type->fieldList) { for (auto i = 0; const auto &f : type->fieldList) {
auto field = make_unique<Field>(); auto field = make_unique<Field>();
field->name = f.fieldName; field->name = f.fieldName;
@ -744,7 +766,7 @@ constexpr std::size_t alignOf(const ModelValue &t) noexcept {
} }
constexpr Error model(auto *h, CommonPtrWith<ModelObject> auto *obj) noexcept { constexpr Error model(auto *h, CommonPtrWith<ModelObject> auto *obj) noexcept {
h->template setTypeInfo<ModelObject>(obj->m_typeName.c_str(), obj->m_typeVersion, {}, static_cast<int>(obj->m_fieldsOrder.size())); h->template setTypeInfo<ModelObject>(obj->typeName().c_str(), obj->typeVersion(), {}, static_cast<int>(obj->m_fieldsOrder.size()));
for (auto &f : obj->m_fieldsOrder) { for (auto &f : obj->m_fieldsOrder) {
oxReturnError(h->field(f->name.c_str(), &f->value)); oxReturnError(h->field(f->name.c_str(), &f->value));
} }
@ -752,7 +774,7 @@ constexpr Error model(auto *h, CommonPtrWith<ModelObject> auto *obj) noexcept {
} }
constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept { constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept {
h->template setTypeInfo<ModelUnion>(obj->m_typeName.c_str(), obj->m_typeVersion, {}, static_cast<int>(obj->m_fieldsOrder.size())); h->template setTypeInfo<ModelUnion>(obj->typeName().c_str(), obj->typeVersion(), {}, static_cast<int>(obj->m_fieldsOrder.size()));
for (auto &f : obj->m_fieldsOrder) { for (auto &f : obj->m_fieldsOrder) {
oxReturnError(h->field(f->name.c_str(), &f->value)); oxReturnError(h->field(f->name.c_str(), &f->value));
} }

View File

@ -25,7 +25,7 @@ struct TypeNameCatcher {
constexpr TypeNameCatcher() noexcept = default; constexpr TypeNameCatcher() noexcept = default;
template<typename T = std::nullptr_t> template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *n = T::TypeName, const Vector<String>& = {}, int v = 0) noexcept { constexpr void setTypeInfo(const char *n = T::TypeName, int v = T::TypeVersion, const Vector<String>& = {}, int = 0) noexcept {
this->name = n; this->name = n;
this->version = v; this->version = v;
} }

View File

@ -29,7 +29,7 @@ class TypeStore {
constexpr virtual ~TypeStore() noexcept = default; constexpr virtual ~TypeStore() noexcept = default;
constexpr Result<const DescriptorType*> get(const auto &name, int typeVersion, constexpr Result<const DescriptorType*> get(const auto &name, int typeVersion,
const Vector<String> &typeParams) const noexcept { const TypeParamPack &typeParams) const noexcept {
const auto typeId = buildTypeId(name, typeVersion, typeParams); const auto typeId = buildTypeId(name, typeVersion, typeParams);
oxRequire(out, m_cache.at(typeId)); oxRequire(out, m_cache.at(typeId));
return out->get(); return out->get();
@ -71,7 +71,7 @@ class TypeStore {
} }
constexpr Result<const DescriptorType*> getLoad(const auto &typeName, auto typeVersion, constexpr Result<const DescriptorType*> getLoad(const auto &typeName, auto typeVersion,
const Vector<String> &typeParams = {}) noexcept { const TypeParamPack &typeParams = {}) noexcept {
return getLoad(buildTypeId(typeName, typeVersion, typeParams)); return getLoad(buildTypeId(typeName, typeVersion, typeParams));
} }
@ -95,7 +95,7 @@ class TypeStore {
const auto &keys = m_cache.keys(); const auto &keys = m_cache.keys();
ox::Vector<DescriptorType*> descs; ox::Vector<DescriptorType*> descs;
for (const auto &k : keys) { for (const auto &k : keys) {
descs.emplace_back(m_cache.at(k).value->get()); descs.emplace_back(m_cache.at(k).unwrap()->get());
} }
return descs; return descs;
} }
@ -106,7 +106,7 @@ class TypeStore {
} }
Result<UniquePtr<DescriptorType>> loadDescriptor(ox::CRStringView name, int version, Result<UniquePtr<DescriptorType>> loadDescriptor(ox::CRStringView name, int version,
const Vector<String> &typeParams) noexcept { const ox::TypeParamPack &typeParams) noexcept {
const auto typeId = buildTypeId(name, version, typeParams); const auto typeId = buildTypeId(name, version, typeParams);
return loadDescriptor(typeId); return loadDescriptor(typeId);
} }

View File

@ -14,6 +14,14 @@
#include <ox/oc/oc.hpp> #include <ox/oc/oc.hpp>
#include <ox/std/std.hpp> #include <ox/std/std.hpp>
template<typename T>
union U {
T t;
int i;
};
U<short> u;
union TestUnion { union TestUnion {
static constexpr auto TypeName = "TestUnion"; static constexpr auto TypeName = "TestUnion";
static constexpr auto TypeVersion = 1; static constexpr auto TypeVersion = 1;
@ -204,26 +212,26 @@ const std::map<std::string_view, ox::Error(*)()> tests = {
ox::ModelObject testOut; ox::ModelObject testOut;
oxReturnError(testOut.setType(type.value)); oxReturnError(testOut.setType(type.value));
oxAssert(ox::readOC(dataBuff.data(), dataBuff.size(), &testOut), "Data read failed"); oxAssert(ox::readOC(dataBuff.data(), dataBuff.size(), &testOut), "Data read failed");
oxAssert(testOut["Int"].get<int>() == testIn.Int, "testOut.Int failed"); oxAssert(testOut.get("Int").unwrap()->get<int>() == testIn.Int, "testOut.Int failed");
oxAssert(testOut["Bool"].get<bool>() == testIn.Bool, "testOut.Bool failed"); oxAssert(testOut.get("Bool").unwrap()->get<bool>() == testIn.Bool, "testOut.Bool failed");
oxAssert(testOut["String"].get<ox::String>() == testIn.String, "testOut.String failed"); oxAssert(testOut.get("String").unwrap()->get<ox::String>() == testIn.String, "testOut.String failed");
auto &testOutStruct = testOut["Struct"].get<ox::ModelObject>(); auto &testOutStruct = testOut.get("Struct").unwrap()->get<ox::ModelObject>();
auto &testOutUnion = testOut["Union"].get<ox::ModelUnion>(); auto &testOutUnion = testOut.get("Union").unwrap()->get<ox::ModelUnion>();
auto &testOutList = testOut["List"].get<ox::ModelValueVector>(); auto &testOutList = testOut.get("List").unwrap()->get<ox::ModelValueVector>();
auto testOutStructCopy = testOut["Struct"].get<ox::ModelObject>(); auto testOutStructCopy = testOut.get("Struct").unwrap()->get<ox::ModelObject>();
auto testOutUnionCopy = testOut["Union"].get<ox::ModelUnion>(); auto testOutUnionCopy = testOut.get("Union").unwrap()->get<ox::ModelUnion>();
auto testOutListCopy = testOut["List"].get<ox::ModelValueVector>(); auto testOutListCopy = testOut.get("List").unwrap()->get<ox::ModelValueVector>();
oxAssert(testOutStruct.typeName() == TestStructNest::TypeName, "ModelObject TypeName failed"); oxAssert(testOutStruct.typeName() == TestStructNest::TypeName, "ModelObject TypeName failed");
oxAssert(testOutStruct.typeVersion() == TestStructNest::TypeVersion, "ModelObject TypeVersion failed"); oxAssert(testOutStruct.typeVersion() == TestStructNest::TypeVersion, "ModelObject TypeVersion failed");
oxAssert(testOutStruct["Bool"].get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool failed"); oxAssert(testOutStruct.get("Bool").unwrap()->get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool failed");
oxAssert(testOutStruct["String"].get<ox::String>() == testIn.Struct.String.c_str(), "testOut.Struct.String failed"); oxAssert(testOutStruct.get("String").unwrap()->get<ox::String>() == testIn.Struct.String.c_str(), "testOut.Struct.String failed");
oxAssert(testOut["unionIdx"].get<int>() == testIn.unionIdx, "testOut.unionIdx failed"); oxAssert(testOut.get("unionIdx").unwrap()->get<int>() == testIn.unionIdx, "testOut.unionIdx failed");
oxAssert(testOutUnion.unionIdx() == testIn.unionIdx, "testOut.Union idx wrong"); oxAssert(testOutUnion.unionIdx() == testIn.unionIdx, "testOut.Union idx wrong");
oxAssert(testOutUnion["Int"].get<uint32_t>() == testIn.Union.Int, "testOut.Union.Int failed"); oxAssert(testOutUnion.get("Int").unwrap()->get<uint32_t>() == testIn.Union.Int, "testOut.Union.Int failed");
oxAssert(testOutList[0].get<uint32_t>() == testIn.List[0], "testOut.List[0] failed"); oxAssert(testOutList[0].get<uint32_t>() == testIn.List[0], "testOut.List[0] failed");
oxAssert(testOutList[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] failed"); oxAssert(testOutList[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] failed");
oxAssert(testOutStructCopy["Bool"].get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool (copy) failed"); oxAssert(testOutStructCopy.get("Bool").unwrap()->get<bool>() == testIn.Struct.Bool, "testOut.Struct.Bool (copy) failed");
oxAssert(testOutStructCopy["String"].get<ox::String>() == testIn.Struct.String.c_str(), "testOut.Struct.String (copy) failed"); oxAssert(testOutStructCopy.get("String").unwrap()->get<ox::String>() == testIn.Struct.String.c_str(), "testOut.Struct.String (copy) failed");
oxAssert(testOutListCopy[0].get<uint32_t>() == testIn.List[0], "testOut.Struct.List[0] (copy) failed"); oxAssert(testOutListCopy[0].get<uint32_t>() == testIn.List[0], "testOut.Struct.List[0] (copy) failed");
oxAssert(testOutListCopy[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] (copy) failed"); oxAssert(testOutListCopy[1].get<uint32_t>() == testIn.List[1], "testOut.Struct.List[1] (copy) failed");
return OxError(0); return OxError(0);

View File

@ -68,6 +68,10 @@ constexpr void *ox_memset(void *ptr, int val, std::size_t size) noexcept {
namespace ox { namespace ox {
constexpr void *memcpy(void *dest, const void *src, std::size_t size) noexcept {
return ox_memcpy(dest, src, size);
}
template<typename T> template<typename T>
void *memsetElements(T *ptr, T val, std::size_t elements) noexcept { void *memsetElements(T *ptr, T val, std::size_t elements) noexcept {
return memset(ptr, val, elements * sizeof(T)); return memset(ptr, val, elements * sizeof(T));

View File

@ -247,6 +247,9 @@ class UniquePtr {
}; };
template<typename T>
using UPtr = UniquePtr<T>;
template<typename T> template<typename T>
constexpr bool operator==(const UniquePtr<T> &p1, const UniquePtr<T> &p2) noexcept { constexpr bool operator==(const UniquePtr<T> &p1, const UniquePtr<T> &p2) noexcept {
return p1.get() == p2.get(); return p1.get() == p2.get();

View File

@ -8,8 +8,10 @@
#pragma once #pragma once
#include "iterator.hpp"
#include "strops.hpp" #include "strops.hpp"
#include "types.hpp" #include "types.hpp"
#include "bit.hpp"
namespace ox { namespace ox {
@ -20,6 +22,111 @@ template<std::size_t buffLen>
class BasicString; class BasicString;
class StringView { class StringView {
public:
template<typename RefType = char&, typename PtrType = char*, bool reverse = false>
struct iterator: public Iterator<std::bidirectional_iterator_tag, char> {
private:
PtrType m_t = nullptr;
std::size_t m_offset = 0;
std::size_t m_max = 0;
public:
constexpr iterator() noexcept = default;
constexpr iterator(PtrType t, std::size_t offset, std::size_t max) noexcept {
m_t = t;
m_offset = offset;
m_max = max;
}
constexpr auto offset() const noexcept {
return m_offset;
}
constexpr iterator operator+(std::size_t s) const noexcept {
if constexpr(reverse) {
return iterator(m_t, max<std::size_t>(m_offset - s, 0), m_max);
} else {
return iterator(m_t, min<std::size_t>(m_offset + s, m_max), m_max);
}
}
constexpr auto operator-(const iterator &other) const noexcept {
if constexpr(reverse) {
return m_offset + other.m_offset;
} else {
return m_offset - other.m_offset;
}
}
constexpr iterator operator-(std::size_t s) const noexcept {
if constexpr(reverse) {
return iterator(m_t, min<std::size_t>(m_offset + s, m_max), m_max);
} else {
return iterator(m_t, max<std::size_t>(m_offset - s, 0), m_max);
}
}
constexpr iterator &operator+=(std::size_t s) noexcept {
if constexpr(reverse) {
m_offset = max<std::size_t>(m_offset - s, 0);
} else {
m_offset = min(m_offset + s, m_max);
}
return *this;
}
constexpr iterator &operator-=(std::size_t s) noexcept {
if constexpr(reverse) {
m_offset = min(m_offset + s, m_max);
} else {
m_offset = max<std::size_t>(m_offset - s, 0);
}
return *this;
}
constexpr iterator &operator++() noexcept {
return operator+=(1);
}
constexpr iterator &operator--() noexcept {
return operator-=(1);
}
constexpr RefType operator*() const noexcept {
return m_t[m_offset];
}
constexpr RefType operator[](std::size_t s) const noexcept {
return m_t[s];
}
constexpr bool operator<(const iterator &other) const noexcept {
return m_offset < other.m_offset;
}
constexpr bool operator>(const iterator &other) const noexcept {
return m_offset > other.m_offset;
}
constexpr bool operator<=(const iterator &other) const noexcept {
return m_offset <= other.m_offset;
}
constexpr bool operator>=(const iterator &other) const noexcept {
return m_offset >= other.m_offset;
}
constexpr bool operator==(const iterator &other) const noexcept {
return m_t == other.m_t && m_offset == other.m_offset && m_max == other.m_max;
}
constexpr bool operator!=(const iterator &other) const noexcept {
return m_t != other.m_t || m_offset != other.m_offset || m_max != other.m_max;
}
};
private: private:
const char *m_str = nullptr; const char *m_str = nullptr;
std::size_t m_len = 0; std::size_t m_len = 0;
@ -41,6 +148,46 @@ class StringView {
constexpr StringView(const char *str, std::size_t len) noexcept: m_str(str), m_len(len) {} constexpr StringView(const char *str, std::size_t len) noexcept: m_str(str), m_len(len) {}
[[nodiscard]]
constexpr iterator<const char&, const char*> begin() const noexcept {
return {m_str, 0, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*> end() const noexcept {
return {m_str, m_len, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*> cbegin() const noexcept {
return {m_str, 0, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*> cend() const noexcept {
return {m_str, m_len, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*, true> crbegin() const noexcept {
return {m_str, m_len - 1, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*, true> crend() const noexcept {
return {m_str, MaxValue<std::size_t>, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*, true> rbegin() const noexcept {
return {m_str, m_len - 1, m_len};
}
[[nodiscard]]
constexpr iterator<const char&, const char*, true> rend() const noexcept {
return {m_str, MaxValue<std::size_t>, m_len};
}
[[nodiscard]] [[nodiscard]]
constexpr auto bytes() const noexcept { constexpr auto bytes() const noexcept {
return m_len; return m_len;
@ -66,6 +213,10 @@ class StringView {
return m_str[m_len - 1]; return m_str[m_len - 1];
} }
constexpr auto substr(std::size_t pos) const noexcept {
return StringView(m_str + pos, m_len - pos);
}
constexpr auto operator[](std::size_t i) const noexcept { constexpr auto operator[](std::size_t i) const noexcept {
return m_str[i]; return m_str[i];
} }

View File

@ -3,6 +3,7 @@ set(CMAKE_INCLUDE_CURRENT_DIR ON)
add_executable( add_executable(
nostalgia-studio MACOSX_BUNDLE nostalgia-studio MACOSX_BUNDLE
aboutpopup.cpp aboutpopup.cpp
clawviewer.cpp
filedialogmanager.cpp filedialogmanager.cpp
main.cpp main.cpp
newmenu.cpp newmenu.cpp

View File

@ -0,0 +1,186 @@
/*
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <imgui.h>
#include "clawviewer.hpp"
namespace nostalgia {
ClawEditor::ClawEditor(ox::CRStringView path, ox::ModelObject obj) noexcept:
m_itemName(path),
m_itemDisplayName(pathToItemName(path)),
m_obj(std::move(obj)) {
}
ox::CRString ClawEditor::itemName() const noexcept {
return m_itemName;
}
ox::CRString ClawEditor::itemDisplayName() const noexcept {
return m_itemDisplayName;
}
void ClawEditor::draw(core::Context*) noexcept {
//const auto paneSize = ImGui::GetContentRegionAvail();
ImGui::BeginChild("PaletteEditor");
static constexpr auto flags = ImGuiTableFlags_RowBg | ImGuiTableFlags_NoBordersInBody;
if (ImGui::BeginTable("ObjTree", 3, flags)) {
ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, 100);
ImGui::TableSetupColumn("Type", ImGuiTableColumnFlags_WidthFixed, 250);
ImGui::TableSetupColumn("Value", ImGuiTableColumnFlags_NoHide);
ImGui::TableHeadersRow();
ObjPath objPath;
drawTree(&objPath, m_obj);
ImGui::EndTable();
}
ImGui::EndChild();
}
void ClawEditor::drawRow(const ox::ModelValue &value) noexcept {
using Str = ox::BasicString<100>;
Str val, type;
switch (value.type()) {
case ox::ModelValue::Type::Undefined:
val = "undefined";
type = "undefined";
break;
case ox::ModelValue::Type::Bool:
val = value.get<bool>() ? "true" : "false";
type = "bool";
break;
case ox::ModelValue::Type::UnsignedInteger8:
val = ox::sfmt<Str>("{}", value.get<uint8_t>());
type = "uint8";
break;
case ox::ModelValue::Type::UnsignedInteger16:
val = ox::sfmt<Str>("{}", value.get<uint16_t>());
type = "uint16";
break;
case ox::ModelValue::Type::UnsignedInteger32:
val = ox::sfmt<Str>("{}", value.get<uint32_t>());
type = "uint32";
break;
case ox::ModelValue::Type::UnsignedInteger64:
val = ox::sfmt<Str>("{}", value.get<uint64_t>());
type = "uint64";
break;
case ox::ModelValue::Type::SignedInteger8:
val = ox::sfmt<Str>("{}", value.get<int8_t>());
type = "int8";
break;
case ox::ModelValue::Type::SignedInteger16:
val = ox::sfmt<Str>("{}", value.get<int16_t>());
type = "int16";
break;
case ox::ModelValue::Type::SignedInteger32:
val = ox::sfmt<Str>("{}", value.get<int32_t>());
type = "int32";
break;
case ox::ModelValue::Type::SignedInteger64:
val = ox::sfmt<Str>("{}", value.get<int64_t>());
type = "int64";
break;
case ox::ModelValue::Type::String:
val = ox::sfmt<Str>("\"{}\"", value.get<ox::String>());
type = "string";
break;
case ox::ModelValue::Type::Object:
type = value.get<ox::ModelObject>().type()->typeName.c_str();
break;
case ox::ModelValue::Type::Union:
type = "union";
break;
case ox::ModelValue::Type::Vector:
type = "list";
break;
}
ImGui::TableNextColumn();
ImGui::Text("%s", type.c_str());
ImGui::TableNextColumn();
ImGui::Text("%s", val.c_str());
}
void ClawEditor::drawVar(ObjPath *path, ox::CRStringView name, const ox::ModelValue &value) noexcept {
using Str = ox::BasicString<100>;
path->push_back(name);
if (value.type() == ox::ModelValue::Type::Object) {
drawTree(path, value.get<ox::ModelObject>());
} else if (value.type() == ox::ModelValue::Type::Vector) {
const auto &vec = value.get<ox::ModelValueVector>();
const auto pathStr = ox::join<Str>("##", *path).unwrap();
const auto lbl = ox::sfmt<Str>("{}##{}", name, pathStr);
const auto flags = ImGuiTreeNodeFlags_SpanFullWidth
| ImGuiTreeNodeFlags_OpenOnArrow
| (vec.size() ? 0 : ImGuiTreeNodeFlags_Leaf)
| (false ? ImGuiTreeNodeFlags_Selected : 0);
const auto open = ImGui::TreeNodeEx(lbl.c_str(), flags);
ImGui::SameLine();
drawRow(value);
if (open) {
for (auto i = 0lu; const auto &e: vec) {
const auto iStr = ox::sfmt<Str>("{}", i);
path->push_back(iStr);
ImGui::TableNextRow(0, 5);
ImGui::TableNextColumn();
drawVar(path, ox::sfmt<Str>("[{}]", i), e);
path->pop_back();
++i;
}
ImGui::TreePop();
}
} else {
const auto pathStr = ox::join<Str>("##", *path).unwrap();
const auto lbl = ox::sfmt<Str>("{}##{}", name, pathStr);
const auto flags = ImGuiTreeNodeFlags_SpanFullWidth
| ImGuiTreeNodeFlags_OpenOnArrow
| ImGuiTreeNodeFlags_Leaf
| (false ? ImGuiTreeNodeFlags_Selected : 0);
const auto open = ImGui::TreeNodeEx(lbl.c_str(), flags);
ImGui::SameLine();
drawRow(value);
if (open) {
ImGui::TreePop();
}
}
path->pop_back();
}
void ClawEditor::drawTree(ObjPath *path, const ox::ModelObject &obj) noexcept {
using Str = ox::BasicString<100>;
for (const auto &c : obj) {
ImGui::TableNextRow(0, 5);
auto pathStr = ox::join<Str>("##", *path).unwrap();
auto lbl = ox::sfmt<Str>("{}##{}", c->name, pathStr);
const auto rowSelected = false;
const auto hasChildren = c->value.type() == ox::ModelValue::Type::Object
|| c->value.type() == ox::ModelValue::Type::Vector;
const auto flags = ImGuiTreeNodeFlags_SpanFullWidth
| ImGuiTreeNodeFlags_OpenOnArrow
| (hasChildren ? 0 : ImGuiTreeNodeFlags_Leaf)
| (rowSelected ? ImGuiTreeNodeFlags_Selected : 0);
ImGui::TableNextColumn();
if (ImGui::IsItemClicked()) {
//model()->setActiveSubsheet(*path);
}
if (ImGui::IsMouseDoubleClicked(0) && ImGui::IsItemHovered()) {
//showSubsheetEditor();
}
path->push_back(c->name);
if (c->value.type() == ox::ModelValue::Type::Object) {
const auto open = ImGui::TreeNodeEx(lbl.c_str(), flags);
ImGui::SameLine();
drawRow(c->value);
if (open) {
drawTree(path, c->value.get<ox::ModelObject>());
ImGui::TreePop();
}
} else {
drawVar(path, c->name, c->value);
}
path->pop_back();
}
}
}

View File

@ -0,0 +1,40 @@
/*
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/model/modelvalue.hpp>
#include <nostalgia/core/context.hpp>
#include "lib/editor.hpp"
namespace nostalgia {
class ClawEditor: public studio::Editor {
private:
using ObjPath = ox::Vector<ox::StringView, 8>;
ox::String m_itemName;
ox::String m_itemDisplayName;
ox::ModelObject m_obj;
public:
ClawEditor(ox::CRStringView path, ox::ModelObject obj) noexcept;
/**
* Returns the name of item being edited.
*/
ox::CRString itemName() const noexcept final;
ox::CRString itemDisplayName() const noexcept final;
void draw(core::Context*) noexcept final;
private:
static void drawRow(const ox::ModelValue &value) noexcept;
void drawVar(ObjPath *path, ox::CRStringView name, const ox::ModelValue &value) noexcept;
void drawTree(ObjPath *path, const ox::ModelObject &obj) noexcept;
};
}

View File

@ -100,6 +100,11 @@ class NOSTALGIASTUDIO_EXPORT BaseEditor: public Widget {
return nullptr; return nullptr;
} }
static constexpr auto pathToItemName(ox::CRStringView path) noexcept {
const auto lastSlash = std::find(path.rbegin(), path.rend(), '/').offset();
return path.substr(lastSlash + 1);
}
// signals // signals
public: public:
ox::Signal<ox::Error(bool)> unsavedChangesChanged; ox::Signal<ox::Error(bool)> unsavedChangesChanged;

View File

@ -61,7 +61,7 @@ class NOSTALGIASTUDIO_EXPORT Project {
ox::Error writeObj(const ox::String &path, const T *obj, ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept; ox::Error writeObj(const ox::String &path, const T *obj, ox::ClawFormat fmt = ox::ClawFormat::Metal) noexcept;
template<typename T> template<typename T>
ox::Result<ox::UniquePtr<T>> loadObj(const ox::String &path) const noexcept; ox::Result<T> loadObj(const ox::String &path) const noexcept;
ox::Result<ox::FileStat> stat(const ox::String &path) const noexcept; ox::Result<ox::FileStat> stat(const ox::String &path) const noexcept;
@ -126,10 +126,13 @@ ox::Error Project::writeObj(const ox::String &path, const T *obj, ox::ClawFormat
} }
template<typename T> template<typename T>
ox::Result<ox::UniquePtr<T>> Project::loadObj(const ox::String &path) const noexcept { ox::Result<T> Project::loadObj(const ox::String &path) const noexcept {
auto obj = ox::make_unique<T>();
oxRequire(buff, loadBuff(path)); oxRequire(buff, loadBuff(path));
if constexpr (ox::is_same_v<T, ox::ModelObject>) {
return ox::readClaw(&m_typeStore, buff);
} else {
return ox::readClaw<T>(buff); return ox::readClaw<T>(buff);
}
} }
template<typename Functor> template<typename Functor>

View File

@ -8,6 +8,7 @@
#include "lib/configio.hpp" #include "lib/configio.hpp"
#include "builtinmodules.hpp" #include "builtinmodules.hpp"
#include "clawviewer.hpp"
#include "filedialogmanager.hpp" #include "filedialogmanager.hpp"
#include "studioapp.hpp" #include "studioapp.hpp"
@ -300,11 +301,11 @@ ox::Error StudioUI::openProject(const ox::String &path) noexcept {
return m_projectExplorer->refreshProjectTreeModel(); return m_projectExplorer->refreshProjectTreeModel();
} }
ox::Error StudioUI::openFile(const ox::String &path) noexcept { ox::Error StudioUI::openFile(ox::CRStringView path) noexcept {
return openFileActiveTab(path, true); return openFileActiveTab(path, true);
} }
ox::Error StudioUI::openFileActiveTab(const ox::String &path, bool makeActiveTab) noexcept { ox::Error StudioUI::openFileActiveTab(ox::CRStringView path, bool makeActiveTab) noexcept {
if (m_openFiles.contains(path)) { if (m_openFiles.contains(path)) {
for (auto &e : m_editors) { for (auto &e : m_editors) {
if (makeActiveTab && e->itemName() == path) { if (makeActiveTab && e->itemName() == path) {
@ -317,10 +318,15 @@ ox::Error StudioUI::openFileActiveTab(const ox::String &path, bool makeActiveTab
} }
oxRequire(ext, studio::fileExt(path)); oxRequire(ext, studio::fileExt(path));
// create Editor // create Editor
studio::BaseEditor *editor = nullptr;
if (!m_editorMakers.contains(ext)) { if (!m_editorMakers.contains(ext)) {
auto [obj, err] = m_project->loadObj<ox::ModelObject>(path);
if (err) {
return OxError(1, "There is no editor for this file extension"); return OxError(1, "There is no editor for this file extension");
} }
auto [editor, err] = m_editorMakers[ext](path); editor = new ClawEditor(path, std::move(obj));
} else {
const auto err = m_editorMakers[ext](path).moveTo(&editor);
if (err) { if (err) {
if constexpr(!ox::defines::Debug) { if constexpr(!ox::defines::Debug) {
oxErrf("Could not open Editor: {}\n", toStr(err)); oxErrf("Could not open Editor: {}\n", toStr(err));
@ -329,6 +335,7 @@ ox::Error StudioUI::openFileActiveTab(const ox::String &path, bool makeActiveTab
} }
return err; return err;
} }
}
editor->closed.connect(this, &StudioUI::closeFile); editor->closed.connect(this, &StudioUI::closeFile);
m_editors.emplace_back(editor); m_editors.emplace_back(editor);
m_openFiles.emplace_back(path); m_openFiles.emplace_back(path);

View File

@ -79,9 +79,9 @@ class StudioUI: public ox::SignalHandler {
ox::Error openProject(const ox::String &path) noexcept; ox::Error openProject(const ox::String &path) noexcept;
ox::Error openFile(const ox::String &path) noexcept; ox::Error openFile(ox::CRStringView path) noexcept;
ox::Error openFileActiveTab(const ox::String &path, bool makeActiveTab) noexcept; ox::Error openFileActiveTab(ox::CRStringView path, bool makeActiveTab) noexcept;
ox::Error closeFile(const ox::String &path) noexcept; ox::Error closeFile(const ox::String &path) noexcept;
}; };