[ox] Add StringView, Writer system, Preloader system

This commit is contained in:
Gary Talent 2022-11-30 01:45:11 -06:00
parent 98f35140fe
commit cbb496c59f
64 changed files with 2343 additions and 417 deletions

View File

@ -7,4 +7,5 @@ add_subdirectory(event)
add_subdirectory(fs)
add_subdirectory(mc)
add_subdirectory(model)
add_subdirectory(preloader)
add_subdirectory(std)

View File

@ -15,10 +15,11 @@ namespace ox {
Result<ClawHeader> readClawHeader(const char *buff, std::size_t buffLen) noexcept {
const auto s1End = ox_strchr(buff, ';', buffLen);
if (!s1End) {
oxAssert(false, "fail");
return OxError(1, "Could not read Claw header");
}
const auto s1Size = s1End - buff;
String fmt(buff, s1Size);
const String fmt(buff, s1Size);
buff += s1Size + 1;
buffLen -= s1Size + 1;
@ -27,7 +28,7 @@ Result<ClawHeader> readClawHeader(const char *buff, std::size_t buffLen) noexcep
return OxError(2, "Could not read Claw header");
}
const auto s2Size = s2End - buff;
String typeName(buff, s2Size);
const String typeName(buff, s2Size);
buff += s2Size + 1;
buffLen -= s2Size + 1;
@ -36,7 +37,7 @@ Result<ClawHeader> readClawHeader(const char *buff, std::size_t buffLen) noexcep
return OxError(3, "Could not read Claw header");
}
const auto s3Size = s3End - buff;
String versionStr(buff, s3Size);
const String versionStr(buff, s3Size);
buff += s3Size + 1;
buffLen -= s3Size + 1;
@ -74,7 +75,7 @@ Result<Buffer> stripClawHeader(const ox::Buffer &buff) noexcept {
Result<ModelObject> readClaw(TypeStore *ts, const Buffer &buff) noexcept {
oxRequire(header, readClawHeader(buff));
oxRequire(t, ts->template getLoad(header.typeName, header.typeVersion));
oxRequire(t, ts->template getLoad(header.typeName, header.typeVersion, header.typeParams));
ModelObject obj;
oxReturnError(obj.setType(t));
switch (header.fmt) {

View File

@ -25,6 +25,7 @@ constexpr auto Error_ClawTypeVersionMismatch = 201;
struct ClawHeader {
String typeName;
int typeVersion = -1;
TypeParamPack typeParams;
ClawFormat fmt = ClawFormat::None;
const char *data = nullptr;
std::size_t dataSize = 0;

View File

@ -96,7 +96,7 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) {
oxReturnError(io->field("Int7", &obj->Int7));
oxReturnError(io->field("Int8", &obj->Int8));
int unionIdx = 0;
if constexpr(ox_strcmp(T::opType(), ox::OpType::Reflect) != 0) {
if constexpr(T::opType() != ox::OpType::Reflect) {
unionIdx = obj->unionIdx;
}
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, unionIdx}));

View File

@ -24,10 +24,12 @@ namespace detail {
struct TypeInfoCatcher {
const char *name = nullptr;
int version = 0;
template<typename T = void>
constexpr void setTypeInfo(const char *name = T::TypeName, int = T::TypeVersion) noexcept {
constexpr void setTypeInfo(const char *name = T::TypeName, int v = T::TypeVersion, const Vector<String>& = {}, int = 0) noexcept {
this->name = name;
this->version = v;
}
constexpr Error field(...) noexcept {
@ -57,6 +59,13 @@ constexpr const char *getTypeName(T *t) noexcept {
return tnc.name;
}
template<typename T>
constexpr int getTypeVersion(T *t) noexcept {
TypeInfoCatcher tnc;
oxIgnoreError(model(&tnc, t));
return tnc.version;
}
template<typename T>
Result<String> writeClawHeader(T *t, ClawFormat fmt) noexcept {
String out;
@ -72,7 +81,7 @@ Result<String> writeClawHeader(T *t, ClawFormat fmt) noexcept {
}
out += detail::getTypeName(t);
out += ";";
const auto tn = detail::type_version<T>::value;
const auto tn = detail::getTypeVersion(t);
if (tn > -1) {
out += tn;
}

View File

@ -28,10 +28,10 @@ FileAddress::FileAddress(uint64_t inode) noexcept {
m_type = FileAddressType::Inode;
}
FileAddress::FileAddress(const ox::String &path) noexcept {
FileAddress::FileAddress(ox::CRStringView path) noexcept {
auto pathSize = path.bytes();
m_data.path = new char[pathSize];
memcpy(m_data.path, path.c_str(), pathSize);
memcpy(m_data.path, path.data(), pathSize);
m_type = FileAddressType::Path;
}
@ -98,7 +98,7 @@ FileAddress &FileAddress::operator=(FileAddress &&other) noexcept {
return *this;
}
bool FileAddress::operator==(const ox::String &path) const noexcept {
bool FileAddress::operator==(CRStringView path) const noexcept {
auto [p, err] = getPath();
if (err) {
return false;

View File

@ -57,7 +57,11 @@ class FileAddress {
FileAddress(uint64_t inode) noexcept;
FileAddress(const ox::String &path) noexcept;
FileAddress(CRStringView path) noexcept;
template<std::size_t SmallStrSz>
FileAddress(const ox::BasicString<SmallStrSz> &path) noexcept: FileAddress(StringView(path)) {
}
FileAddress(char *path) noexcept;
@ -69,7 +73,7 @@ class FileAddress {
FileAddress &operator=(FileAddress &&other) noexcept;
bool operator==(const ox::String &path) const noexcept;
bool operator==(CRStringView path) const noexcept;
[[nodiscard]]
constexpr FileAddressType type() const noexcept {
@ -82,6 +86,7 @@ class FileAddress {
}
}
[[nodiscard]]
constexpr Result<uint64_t> getInode() const noexcept {
switch (m_type) {
case FileAddressType::Inode:
@ -141,16 +146,16 @@ constexpr Error model(T *io, CommonPtrWith<FileAddress::Data> auto *obj) noexcep
template<typename T>
constexpr Error model(T *io, CommonPtrWith<FileAddress> auto *fa) noexcept {
io->template setTypeInfo<FileAddress>();
if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) {
if constexpr(T::opType() == OpType::Reflect) {
int8_t type = 0;
oxReturnError(io->field("type", &type));
oxReturnError(io->field("data", UnionView(&fa->m_data, 0)));
} else if constexpr(ox_strcmp(T::opType(), OpType::Read) == 0) {
} else if constexpr(T::opType() == OpType::Read) {
auto type = static_cast<int8_t>(fa->m_type);
oxReturnError(io->field("type", &type));
fa->m_type = static_cast<FileAddressType>(type);
oxReturnError(io->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));
} else if constexpr(ox_strcmp(T::opType(), OpType::Write) == 0) {
} else if constexpr(T::opType() == OpType::Write) {
auto type = static_cast<int8_t>(fa->m_type);
oxReturnError(io->field("type", &type));
oxReturnError(io->field("data", UnionView(&fa->m_data, static_cast<int>(fa->m_type))));

View File

@ -62,8 +62,8 @@ static ox::Error runRead(ox::FileSystem *fs, int argc, const char **argv) noexce
}
static ox::Error run(int argc, const char **argv) noexcept {
if (argc < 2) {
oxErr("Subcommand and OxFS file arguments are required\n");
if (argc < 3) {
oxErr("OxFS file and subcommand arguments are required\n");
return OxError(1);
}
const auto fsPath = argv[1];

View File

@ -100,7 +100,7 @@ class MetalClawReaderTemplate {
template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion,
int fields = ModelFieldCount_v<T>) noexcept;
const Vector<String>& = {}, int fields = ModelFieldCount_v<T>) noexcept;
/**
* Returns a MetalClawReader to parse a child object.
@ -225,7 +225,7 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char *name, a
if (valLen >= len) {
auto reader = child("");
auto handler = HandlerMaker(&reader);
handler.setTypeInfo("List", 0, static_cast<int>(len));
handler.setTypeInfo("List", 0, {}, static_cast<int>(len));
for (std::size_t i = 0; i < len; ++i) {
oxReturnError(handler.field("", &val[i]));
}
@ -254,7 +254,7 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, HashMa
// read the list
auto reader = child("");
auto handler = HandlerMaker(&reader);
handler.setTypeInfo("List", 0, static_cast<int>(len));
handler.setTypeInfo("List", 0, {}, static_cast<int>(len));
for (std::size_t i = 0; i < len; ++i) {
const auto keyLen = handler.stringLength(nullptr);
auto wkey = ox_malloca(keyLen + 1, char, 0);
@ -500,7 +500,7 @@ constexpr Error MetalClawReaderTemplate<HandlerMaker>::field(const char*, CB cb)
// read the list
auto reader = child("");
auto handler = HandlerMaker(&reader);
handler.setTypeInfo("List", 0, static_cast<int>(len));
handler.setTypeInfo("List", 0, {}, static_cast<int>(len));
for (std::size_t i = 0; i < len; ++i) {
T val;
oxReturnError(handler.field("", &val));
@ -527,7 +527,7 @@ constexpr StringLength MetalClawReaderTemplate<HandlerMaker>::stringLength(const
template<auto HandlerMaker>
template<typename T>
constexpr void MetalClawReaderTemplate<HandlerMaker>::setTypeInfo(const char*, int, int fields) noexcept {
constexpr void MetalClawReaderTemplate<HandlerMaker>::setTypeInfo(const char*, int, const Vector<String>&, int fields) noexcept {
m_fields = fields;
m_buffIt = static_cast<std::size_t>((fields / 8 + 1) - (fields % 8 == 0));
m_fieldPresence.setFields(fields);

View File

@ -89,7 +89,7 @@ constexpr ox::Error model(T *io, ox::CommonPtrWith<TestStruct> auto *obj) noexce
oxReturnError(io->field("Int7", &obj->Int7));
oxReturnError(io->field("Int8", &obj->Int8));
oxReturnError(io->field("unionIdx", &obj->unionIdx));
if (ox_strcmp(io->opType(), ox::OpType::Reflect) == 0) {
if constexpr(T::opType() == ox::OpType::Reflect) {
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 0}));
} else {
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, obj->unionIdx}));
@ -309,10 +309,10 @@ std::map<ox::String, ox::Error(*)()> tests = {
testIn.Union.Int = 93;
oxAssert(ox::writeMC(dataBuff.data(), dataBuff.size(), &testIn), "Data generation failed");
ox::TypeStore typeStore;
auto type = ox::buildTypeDef(&typeStore, &testIn);
oxAssert(type.error, "Descriptor write failed");
const auto [type, typeErr] = ox::buildTypeDef(&typeStore, &testIn);
oxAssert(typeErr, "Descriptor write failed");
ox::ModelObject testOut;
oxReturnError(testOut.setType(type.value));
oxReturnError(testOut.setType(type));
oxAssert(ox::readMC(dataBuff.data(), dataBuff.size(), &testOut), "Data read failed");
oxAssert(testOut["Int"].get<int>() == testIn.Int, "testOut.Int failed");
oxAssert(testOut["Bool"].get<bool>() == testIn.Bool, "testOut.Bool failed");
@ -361,9 +361,9 @@ std::map<ox::String, ox::Error(*)()> tests = {
testIn.Struct.BString = "Test String 2";
oxAssert(ox::writeMC(dataBuff, dataBuffLen, &testIn), "Data generation failed");
ox::TypeStore typeStore;
auto type = ox::buildTypeDef(&typeStore, &testIn);
oxAssert(type.error, "Descriptor write failed");
oxReturnError(ox::walkModel<ox::MetalClawReader>(type.value, dataBuff, dataBuffLen,
const auto [type, typeErr] = ox::buildTypeDef(&typeStore, &testIn);
oxAssert(typeErr, "Descriptor write failed");
oxReturnError(ox::walkModel<ox::MetalClawReader>(type, dataBuff, dataBuffLen,
[](const ox::Vector<ox::FieldName>&, const ox::Vector<ox::String>&, const ox::DescriptorField &f, ox::MetalClawReader *rdr) -> ox::Error {
//std::cout << f.fieldName.c_str() << '\n';
auto fieldName = f.fieldName.c_str();

View File

@ -104,7 +104,7 @@ class MetalClawWriter {
template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion,
int fields = ModelFieldCount_v<T>) noexcept;
const Vector<String>& = {}, int fields = ModelFieldCount_v<T>) noexcept;
[[nodiscard]]
constexpr std::size_t size() const noexcept;
@ -135,10 +135,10 @@ class MetalClawWriter {
};
constexpr MetalClawWriter::MetalClawWriter(uint8_t *buff, std::size_t buffLen, int unionIdx) noexcept:
m_fieldPresence(buff, buffLen),
m_unionIdx(unionIdx),
m_buffLen(buffLen),
m_buff(buff) {
m_fieldPresence(buff, buffLen),
m_unionIdx(unionIdx),
m_buffLen(buffLen),
m_buff(buff) {
}
constexpr MetalClawWriter::~MetalClawWriter() noexcept {
@ -330,7 +330,7 @@ constexpr Error MetalClawWriter::field(const char*, T *val, std::size_t len) noe
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
ModelHandlerInterface handler{&writer};
handler.setTypeInfo<T>("List", 0, len);
handler.setTypeInfo<T>("List", 0, {}, len);
// write the array
for (std::size_t i = 0; i < len; i++) {
@ -363,7 +363,7 @@ constexpr Error MetalClawWriter::field(const char*, const HashMap<String, T> *va
MetalClawWriter writer(m_buff + m_buffIt, m_buffLen - m_buffIt);
ModelHandlerInterface handler{&writer};
// double len for both key and value
handler.setTypeInfo("Map", 0, len * 2);
handler.setTypeInfo("Map", 0, {}, len * 2);
// write the array
for (std::size_t i = 0; i < len; i++) {
const auto &key = keys[i];
@ -388,7 +388,7 @@ constexpr Error MetalClawWriter::field(const char *name, HashMap<String, T> *val
}
template<typename T>
constexpr void MetalClawWriter::setTypeInfo(const char*, int, int fields) noexcept {
constexpr void MetalClawWriter::setTypeInfo(const char*, int, const Vector<String>&, int fields) noexcept {
m_fields = fields;
m_fieldPresence.setFields(fields);
m_buffIt = static_cast<std::size_t>(m_fieldPresence.getMaxLen());

View File

@ -2,6 +2,7 @@ add_library(
OxModel
desctypes.cpp
descwrite.cpp
modelvalue.cpp
)
target_link_libraries(
@ -42,3 +43,7 @@ install(TARGETS OxModel
LIBRARY DESTINATION lib/ox
ARCHIVE DESTINATION lib/ox
)
if(OX_RUN_TESTS)
add_subdirectory(test)
endif()

View File

@ -10,6 +10,7 @@
#include <ox/std/bit.hpp>
#include <ox/std/error.hpp>
#include <ox/std/fmt.hpp>
#include <ox/std/hashmap.hpp>
#include <ox/std/memory.hpp>
#include <ox/std/string.hpp>
@ -23,6 +24,22 @@ namespace ox {
using FieldName = String;
using TypeParamPack = Vector<String>;
static constexpr auto buildTypeId(CRStringView name, int version,
const TypeParamPack &typeParams) noexcept {
String tp;
if (typeParams.size()) {
tp = "<";
for (const auto &p : typeParams) {
tp += p + ",";
}
tp = tp.substr(0, tp.len() - 1);
tp += ">";
}
return ox::sfmt("{}{};{}", name, tp, version);
}
enum class PrimitiveType: uint8_t {
UnsignedInteger = 0,
SignedInteger = 1,
@ -33,45 +50,82 @@ enum class PrimitiveType: uint8_t {
Union = 6,
};
struct Subscript {
static constexpr auto TypeName = "net.drinkingtea.ox.Subscript";
static constexpr auto TypeVersion = 1;
enum class SubscriptType: uint32_t {
None = 0,
Ptr = 1,
PtrArray = 2,
InlineArray = 3,
Vector = 4,
};
SubscriptType subscriptType = SubscriptType::None;
uint64_t length = 0;
uint64_t smallSzLen = 0;
};
template<typename T>
constexpr Error model(T *io, CommonPtrWith<Subscript> auto *type) noexcept {
io->template setTypeInfo<Subscript>();
if constexpr(T::opType() == OpType::Reflect) {
uint32_t st = 0;
oxReturnError(io->field("subscriptType", &st));
} else {
auto pt = type ? static_cast<uint32_t>(type->subscriptType) : 0;
oxReturnError(io->field("subscriptType", &pt));
type->subscriptType = static_cast<Subscript::SubscriptType>(pt);
}
oxReturnError(io->field("length", &type->length));
oxReturnError(io->field("smallSzLen", &type->smallSzLen));
return OxError(0);
}
using SubscriptStack = Vector<Subscript, 3>;
struct DescriptorField {
// order of fields matters
static constexpr auto TypeName = "net.drinkingtea.ox.DescriptorField";
static constexpr auto TypeVersion = 2;
static constexpr auto TypeVersion = 3;
// do not serialize type
const struct DescriptorType *type = nullptr;
String fieldName;
int subscriptLevels = 0;
String typeName; // gives reference to type for lookup if type is null
int typeVersion = 0;
bool list = false;
SubscriptStack subscriptStack;
String typeId; // gives reference to type for lookup if type is null
constexpr DescriptorField() noexcept = default;
constexpr DescriptorField(const DescriptorType *pType, String pFieldName,
int pSubscriptLevels, String pTypeName, int pTypeVersion) noexcept:
int pSubscriptLevels,
SubscriptStack pSubscriptType,
String pTypeId) noexcept:
type(pType),
fieldName(std::move(pFieldName)),
subscriptLevels(pSubscriptLevels),
typeName(std::move(pTypeName)),
typeVersion(pTypeVersion) {
subscriptStack(std::move(pSubscriptType)),
typeId(std::move(pTypeId)) {
}
constexpr DescriptorField(const DescriptorField &other) noexcept:
type(other.type),
fieldName(other.fieldName),
subscriptLevels(other.subscriptLevels),
typeName(other.typeName) {
subscriptStack(other.subscriptStack),
typeId(other.typeId) {
}
constexpr DescriptorField(DescriptorField &&other) noexcept:
type(other.type),
fieldName(other.fieldName),
fieldName(std::move(other.fieldName)),
subscriptLevels(other.subscriptLevels),
typeName(std::move(other.typeName)) {
subscriptStack(std::move(other.subscriptStack)),
typeId(std::move(other.typeId)) {
other.type = {};
other.subscriptLevels = {};
other.subscriptStack = {};
}
constexpr ~DescriptorField() noexcept = default;
@ -86,13 +140,14 @@ using FieldList = Vector<DescriptorField>;
struct DescriptorType {
static constexpr auto TypeName = "net.drinkingtea.ox.DescriptorType";
static constexpr auto TypeVersion = 2;
static constexpr auto TypeName = "net.drinkingtea.ox.TypeDescriptor";
static constexpr auto TypeVersion = 1;
String typeName;
int typeVersion = 0;
PrimitiveType primitiveType = PrimitiveType::UnsignedInteger;
// fieldList only applies to structs
TypeParamPack typeParams;
// fieldList only applies to structs and unions
FieldList fieldList;
// - number of bytes for integer and float types
// - number of fields for structs and lists
@ -101,31 +156,26 @@ struct DescriptorType {
constexpr DescriptorType() noexcept = default;
constexpr explicit DescriptorType(String tn, int typeVersion) noexcept:
typeName(std::move(tn)), typeVersion(typeVersion) {
}
constexpr DescriptorType(String tn, PrimitiveType t, int b) noexcept:
constexpr explicit DescriptorType(String tn, int typeVersion, PrimitiveType t, TypeParamPack pTypeParams) noexcept:
typeName(std::move(tn)),
typeVersion(typeVersion),
primitiveType(t),
length(b) {
}
constexpr DescriptorType(String tn, PrimitiveType t, FieldList fl) noexcept:
typeName(std::move(tn)),
primitiveType(t),
fieldList(std::move(fl)) {
typeParams(std::move(pTypeParams)) {
}
};
[[nodiscard]]
constexpr auto buildTypeId(const DescriptorType &t) noexcept {
return buildTypeId(t.typeName, t.typeVersion, t.typeParams);
}
template<typename T>
constexpr Error model(T *io, CommonPtrWith<DescriptorType> auto *type) noexcept {
io->template setTypeInfo<DescriptorType>();
oxReturnError(io->field("typeName", &type->typeName));
oxReturnError(io->field("typeVersion", &type->typeVersion));
if constexpr(ox_strcmp(T::opType(), OpType::Reflect) == 0) {
if constexpr(T::opType() == OpType::Reflect) {
uint8_t pt = 0;
oxReturnError(io->field("primitiveType", &pt));
} else {
@ -133,6 +183,7 @@ constexpr Error model(T *io, CommonPtrWith<DescriptorType> auto *type) noexcept
oxReturnError(io->field("primitiveType", &pt));
type->primitiveType = static_cast<PrimitiveType>(pt);
}
oxReturnError(io->field("typeParams", &type->typeParams));
oxReturnError(io->field("fieldList", &type->fieldList));
oxReturnError(io->field("length", &type->length));
oxReturnError(io->field("preloadable", &type->preloadable));
@ -142,9 +193,10 @@ constexpr Error model(T *io, CommonPtrWith<DescriptorType> auto *type) noexcept
template<typename T>
constexpr Error model(T *io, CommonPtrWith<DescriptorField> auto *field) noexcept {
io->template setTypeInfo<DescriptorField>();
oxReturnError(io->field("typeName", &field->typeName));
oxReturnError(io->field("typeId", &field->typeId));
oxReturnError(io->field("fieldName", &field->fieldName));
oxReturnError(io->field("subscriptLevels", &field->subscriptLevels));
oxReturnError(io->field("subscriptStack", &field->subscriptStack));
// defaultValue is unused now, but leave placeholder for backwards compatibility
int defaultValue = 0;
oxReturnError(io->field("defaultValue", &defaultValue));
@ -154,20 +206,30 @@ constexpr Error model(T *io, CommonPtrWith<DescriptorField> auto *field) noexcep
template<typename ReaderBase>
class TypeDescReader;
#if 0 // unused right now
template<typename T>
constexpr Error model(TypeDescReader<T> *io, CommonPtrWith<DescriptorField> auto *field) noexcept {
io->template setTypeInfo<DescriptorField>(DescriptorField::TypeName, DescriptorField::TypeVersion, 4);
io->template setTypeInfo<DescriptorField>();
oxReturnError(io->field("typeName", &field->typeName));
oxReturnError(io->field("typeVersion", &field->typeVersion));
auto &typeStore = io->typeStore();
auto &[type, err] = typeStore->at(field->typeName).value;
oxReturnError(err);
field->type = type.get();
oxReturnError(io->field("fieldName", &field->fieldName));
oxReturnError(io->field("subscriptLevels", &field->subscriptLevels));
if constexpr(T::opType() != ox::OpType::Reflect) {
auto subscriptStack = static_cast<uint32_t>(field->subscriptStack);
oxReturnError(io->field("subscriptStack", &subscriptStack));
field->subscriptStack = static_cast<DescriptorField::SubscriptType>(subscriptStack);
} else {
oxReturnError(io->field("subscriptStack", &field->subscriptStack));
}
// defaultValue is unused now, but placeholder for backwards compatibility
int defaultValue = 0;
oxReturnError(io->field("defaultValue", &defaultValue));
return OxError(0);
}
#endif
}

View File

@ -38,6 +38,45 @@ constexpr int indirectionLevels_v<T*> = 1 + indirectionLevels_v<T>;
template<typename T, std::size_t sz>
constexpr int indirectionLevels_v<T[sz]> = 1 + indirectionLevels_v<T>;
template<typename T, std::size_t SmallVecSz>
constexpr int indirectionLevels_v<::ox::Vector<T, SmallVecSz>> = 1 + indirectionLevels_v<typename T::value_type>;
template<typename T>
constexpr auto buildSubscriptStack(const T*, SubscriptStack*) noexcept {
}
template<typename T>
constexpr auto buildSubscriptStack(const T**, SubscriptStack *s) noexcept {
s->push_back({.subscriptType = Subscript::SubscriptType::Ptr});
}
template<typename T>
constexpr auto buildSubscriptStack(const UniquePtr<T>*, SubscriptStack *s) noexcept {
s->push_back({.subscriptType = Subscript::SubscriptType::Ptr});
}
template<typename T, std::size_t sz>
constexpr auto buildSubscriptStack(const Array<T, sz>*, SubscriptStack *s) noexcept {
s->push_back({.subscriptType = Subscript::SubscriptType::InlineArray, .length = sz});
buildSubscriptStack(static_cast<T*>(nullptr), s);
}
template<typename T, std::size_t SmallVecSz>
constexpr auto buildSubscriptStack(const Vector<T, SmallVecSz>*, SubscriptStack *s) noexcept {
s->push_back({
.subscriptType = Subscript::SubscriptType::Vector,
.smallSzLen = SmallVecSz,
});
buildSubscriptStack(static_cast<T*>(nullptr), s);
}
template<typename T>
constexpr auto buildSubscriptStack(const T*) {
SubscriptStack s;
buildSubscriptStack(static_cast<const T*>(nullptr), &s);
return s;
}
}
class TypeDescWriter {
@ -52,21 +91,23 @@ class TypeDescWriter {
constexpr ~TypeDescWriter() noexcept = default;
template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *name = T::TypeName,
constexpr void setTypeInfo(CRStringView name = T::TypeName,
int version = T::TypeVersion,
int fields = ModelFieldCount_v<T>) noexcept;
const TypeParamPack &typeParams = {},
int fields = ModelFieldCount_v<T>) noexcept;
template<typename T>
constexpr Error field(const char *name, const T *val, std::size_t valLen) noexcept;
constexpr Error field(CRStringView name, const T *val, std::size_t valLen,
const SubscriptStack &subscriptStack = {}) noexcept;
template<typename T, bool force>
constexpr Error field(CRStringView name, UnionView<T, force> val) noexcept;
template<typename T>
constexpr Error field(const char *name, T val) noexcept;
template<typename T>
constexpr Error field(const char *name, const T *val) noexcept;
constexpr Error field(CRStringView name, const T *val) noexcept;
template<typename ...Args>
constexpr Error fieldCString(const char *name, Args&&...) noexcept;
constexpr Error fieldCString(CRStringView name, Args&&...) noexcept;
[[nodiscard]]
constexpr DescriptorType *definition() noexcept {
@ -105,8 +146,12 @@ class TypeDescWriter {
[[nodiscard]]
constexpr const DescriptorType *type(SerStr val) const noexcept;
template<std::size_t SmallStrSz>
[[nodiscard]]
constexpr const DescriptorType *type(const String *val) const noexcept;
constexpr const DescriptorType *type(const BasicString<SmallStrSz>*) const noexcept {
constexpr auto PT = PrimitiveType::String;
return getType(types::BasicString, 1, PT, 0, {sfmt("{}", SmallStrSz)});
}
template<std::size_t sz>
[[nodiscard]]
@ -125,71 +170,77 @@ class TypeDescWriter {
constexpr const DescriptorType *type(UnionView<U> val) const noexcept;
[[nodiscard]]
constexpr const DescriptorType *getType(const String &tn, int typeVersion, PrimitiveType t, int b) const noexcept;
constexpr const DescriptorType *getType(CRStringView tn, int typeVersion, PrimitiveType t, int b,
const TypeParamPack &typeParams = {}) const noexcept;
};
constexpr TypeDescWriter::TypeDescWriter(TypeStore *typeStore) noexcept: m_typeStore(typeStore) {
}
constexpr TypeDescWriter::TypeDescWriter(TypeStore *typeStore) noexcept: m_typeStore(typeStore) {}
template<typename T>
constexpr void TypeDescWriter::setTypeInfo(const char *typeName, int typeVersion, int) noexcept {
m_type = m_typeStore->getInit(typeName, typeVersion);
constexpr void TypeDescWriter::setTypeInfo(CRStringView typeName, int typeVersion,
const TypeParamPack &typeParams, int) noexcept {
PrimitiveType pt;
if constexpr(is_union_v<T>) {
m_type->primitiveType = PrimitiveType::Union;
pt = PrimitiveType::Union;
} else if constexpr(isBasicString_v<T> || isBString_v<T>) {
pt = PrimitiveType::String;
} else {
m_type->primitiveType = PrimitiveType::Struct;
pt = PrimitiveType::Struct;
}
m_type->preloadable = detail::preloadable<T>::value;
m_type = m_typeStore->getInit(typeName, typeVersion, pt, typeParams);
m_type->preloadable = preloadable<T>::value;
}
// array handler
template<typename T>
constexpr Error TypeDescWriter::field(const char *name, const T *val, std::size_t) noexcept {
constexpr Error TypeDescWriter::field(CRStringView name, const T*, std::size_t, const SubscriptStack &subscriptStack) noexcept {
if (m_type) {
constexpr typename remove_pointer<decltype(val)>::type *p = nullptr;
constexpr typename remove_pointer<T>::type *p = nullptr;
const auto t = type(p);
oxAssert(t != nullptr, "field(const char *name, T *val, std::size_t): Type not found or generated");
m_type->fieldList.emplace_back(t, name, detail::indirectionLevels_v<T> + 1, t->typeName, t->typeVersion);
m_type->fieldList.emplace_back(t, name, detail::indirectionLevels_v<T> + 1, subscriptStack, buildTypeId(*t));
return OxError(0);
}
return OxError(1);
}
template<typename T, bool force>
constexpr Error TypeDescWriter::field(CRStringView name, UnionView<T, force> val) noexcept {
if (m_type) {
const auto t = type(val);
oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated");
m_type->fieldList.emplace_back(t, name, 0, SubscriptStack{}, t->typeName);
return OxError(0);
}
return OxError(1);
}
template<typename T>
constexpr Error TypeDescWriter::field(const char *name, T val) noexcept {
if (m_type) {
if constexpr(isVector_v<typename ox::remove_pointer<T>::type> || isArray_v<typename ox::remove_pointer<T>::type>) {
return field(name, val->data(), val->size());
} else {
const auto t = type(val);
oxAssert(t != nullptr, "field(const char *name, T val): Type not found or generated");
m_type->fieldList.emplace_back(t, name, 0, t->typeName, t->typeVersion);
return OxError(0);
}
}
return OxError(1);
}
template<typename T>
constexpr Error TypeDescWriter::field(const char *name, const T *val) noexcept {
constexpr Error TypeDescWriter::field(CRStringView name, const T *val) noexcept {
if (m_type) {
if constexpr(isVector_v<T> || isArray_v<T>) {
return field(name, val->data(), val->size());
return field(name, val->data(), 0, detail::buildSubscriptStack(val));
} else if constexpr(isSmartPtr_v<T>) {
return field(name, val->get(), 0, detail::buildSubscriptStack(val));
} else if constexpr(is_pointer_v<T>) {
return field(name, val, 0, detail::buildSubscriptStack(val));
} else {
const auto t = type(val);
oxAssert(t != nullptr, "field(const char *name, T *val): Type not found or generated");
m_type->fieldList.emplace_back(t, name, 0, t->typeName, t->typeVersion);
return OxError(0);
m_type->fieldList.emplace_back(t, name, 0, SubscriptStack{}, buildTypeId(*t));
return {};
}
}
return OxError(1);
}
template<typename ...Args>
constexpr Error TypeDescWriter::fieldCString(const char *name, Args&&...) noexcept {
String s;
return field(name, &s);
constexpr Error TypeDescWriter::fieldCString(CRStringView name, Args&&...) noexcept {
constexpr auto s = "";
const auto t = type(s);
m_type->fieldList.emplace_back(t, name, 0, SubscriptStack{}, t->typeName);
return {};
}
template<typename T>
@ -286,29 +337,25 @@ constexpr const DescriptorType *TypeDescWriter::type(SerStr) const noexcept {
return getType(types::String, 0, PT, 0);
}
constexpr const DescriptorType *TypeDescWriter::type(const String*) const noexcept {
constexpr auto PT = PrimitiveType::String;
return getType(types::String, 0, PT, 0);
}
template<std::size_t sz>
constexpr const DescriptorType *TypeDescWriter::type(const BString<sz>*) const noexcept {
constexpr auto PT = PrimitiveType::String;
return getType(types::String, 0, PT, 0);
return getType(types::BString, 0, PT, 0);
}
constexpr const DescriptorType *TypeDescWriter::getType(const String &tn, int typeVersion, PrimitiveType pt, int b) const noexcept {
auto t = m_typeStore->get(tn, typeVersion);
constexpr const DescriptorType *TypeDescWriter::getType(CRStringView tn, int typeVersion, PrimitiveType pt, int b,
const TypeParamPack &typeParams) const noexcept {
auto t = m_typeStore->get(tn, typeVersion, typeParams);
if (!t.error) {
auto type = t.value;
oxAssert(type != nullptr, "TypeDescWriter::getType returning null DescriptorType");
return type;
} else {
auto dt = ox::make_unique<DescriptorType>(tn, typeVersion);
dt->primitiveType = pt;
auto dt = ox::make_unique<DescriptorType>(tn, typeVersion, pt, typeParams);
dt->length = b;
const auto out = dt.get();
m_typeStore->set(tn, typeVersion, std::move(dt));
const auto typeId = buildTypeId(tn, typeVersion, typeParams);
m_typeStore->set(typeId, std::move(dt));
return out;
}
}

View File

@ -8,6 +8,7 @@
#pragma once
#include <ox/std/assert.hpp>
#include <ox/std/bit.hpp>
#include <ox/std/error.hpp>
@ -23,23 +24,23 @@ class FieldCounter {
int fields = 0;
template<typename U = std::nullptr_t>
constexpr void setTypeInfo(const char * = "", int = 0, int = 0) {
constexpr void setTypeInfo(CRStringView = "", int = 0, const Vector<String>& = {}, int = 0) {
}
template<typename U>
constexpr ox::Error field(const char *, U) noexcept {
constexpr ox::Error field(CRStringView, U) noexcept {
++fields;
return OxError(0);
}
template<typename U>
constexpr ox::Error field(const char *, U, std::size_t) noexcept {
constexpr ox::Error field(CRStringView, U, std::size_t) noexcept {
++fields;
return OxError(0);
}
template<typename U, typename Handler>
constexpr Error field(const char *, Handler) {
constexpr Error field(CRStringView, Handler) {
++fields;
return OxError(0);
}
@ -49,7 +50,7 @@ class FieldCounter {
return OxError(0);
}
static constexpr auto opType() {
static constexpr auto opType() noexcept {
return OpType::Reflect;
}
};

View File

@ -21,25 +21,29 @@
#include "optype.hpp"
#include "types.hpp"
namespace ox::detail {
namespace ox {
namespace detail {
template<bool>
struct BoolWrapper {
};
template<typename T, typename = BoolWrapper<true>>
template<int>
struct IntWrapper {
};
}
template<typename T, typename = detail::BoolWrapper<true>>
struct preloadable: false_type {
};
template<typename T>
struct preloadable<T, BoolWrapper<T::Preloadable>> {
struct preloadable<T, detail::BoolWrapper<T::Preloadable>> {
static constexpr bool value = T::Preloadable;
};
template<int>
struct IntWrapper {
};
// cannot be done until C++20
//struct PseudoString {
// constexpr PseudoString(const char* = "") noexcept {}

View File

@ -25,8 +25,8 @@ class ModelHandlerInterface {
template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *name = T::TypeName, int version = T::TypeVersion,
int fields = ModelFieldCount_v<T>) noexcept {
m_handler->setTypeInfo(name, version, fields);
const Vector<String> &typeParams = {}, int fields = ModelFieldCount_v<T>) noexcept {
m_handler->setTypeInfo(name, version, typeParams, fields);
}
template<std::size_t len>
@ -63,7 +63,7 @@ class ModelHandlerInterface {
return m_handler->fieldCString(name, val, buffLen);
}
constexpr Error field(const char *name, CommonPtrWith<ModelValue> auto *v) noexcept {
constexpr Error fieldModelValue(const char *name, CommonPtrWith<ModelValue> auto *v) noexcept {
switch (v->type()) {
case ModelValue::Type::Undefined:
break;
@ -92,14 +92,17 @@ class ModelHandlerInterface {
case ModelValue::Type::Union:
{
auto &u = v->template get<ModelUnion>();
if constexpr(ox_strcmp(Handler::opType(), OpType::Read) == 0) {
if constexpr(Handler::opType() == OpType::Read) {
u.setActiveField(m_handler->whichFieldPresent(name, u));
return m_handler->field(name, UnionView<ModelUnion, true>(&u, u.unionIdx()));
} else {
return m_handler->field(name, UnionView<const ModelUnion, true>(&u, u.unionIdx()));
}
return m_handler->field(name, UnionView<ModelUnion, true>(&u, u.unionIdx()));
}
case ModelValue::Type::Vector:
return m_handler->field(name, &v->template get<ModelValueVector>());
}
oxErrf("invalid type: {}: {}\n", name, static_cast<int>(v->type()));
oxPanic(OxError(1), "invalid type");
return OxError(1, "invalid type");
}
@ -110,12 +113,22 @@ class ModelHandlerInterface {
return m_handler->template field<T, Callback>(name, cb);
}
constexpr Error field(const char *name, const auto *v) noexcept {
return m_handler->field(name, v);
template<typename T>
constexpr Error field(const char *name, const T *v) noexcept {
if constexpr(ox::is_same_v<T, ModelValue>) {
return fieldModelValue(name, v);
} else {
return m_handler->field(name, v);
}
}
constexpr Error field(const char *name, auto *v) noexcept {
return m_handler->field(name, v);
template<typename T>
constexpr Error field(const char *name, T *v) noexcept {
if constexpr(ox::is_same_v<T, ModelValue>) {
return fieldModelValue(name, v);
} else {
return m_handler->field(name, v);
}
}
template<typename U, bool force = false>
@ -156,4 +169,18 @@ class ModelHandlerInterface {
};
template<typename Handler>
class ModelHandlerBase {
private:
ModelHandlerInterface<Handler> m_interface;
public:
constexpr ModelHandlerBase() noexcept: m_interface(static_cast<Handler*>(this)) {}
constexpr ModelHandlerBase(const ModelHandlerBase&) noexcept: m_interface(static_cast<Handler*>(this)) {}
constexpr ModelHandlerBase(ModelHandlerBase&&) noexcept: m_interface(static_cast<Handler*>(this)) {}
[[nodiscard]]
constexpr auto interface() noexcept {
return &m_interface;
}
};
}

View File

@ -76,7 +76,8 @@ class MemberList {
}
template<typename T = void>
constexpr void setTypeInfo(const char* = T::TypeName, int = ModelFieldCount_v<T>) noexcept {
constexpr void setTypeInfo(const char* = T::TypeName, int = ModelTypeVersion_v<T>,
const Vector<String>& = {}, int = ModelFieldCount_v<T>) noexcept {
}
[[nodiscard]]
@ -135,7 +136,7 @@ class Copier {
}
template<typename T = void>
constexpr void setTypeInfo(const char* = T::TypeName, int = T::TypeVersion, int = ModelFieldCount_v<T>) noexcept {
constexpr void setTypeInfo(const char* = T::TypeName, int = T::TypeVersion, const Vector<String>& = {}, int = ModelFieldCount_v<T>) noexcept {
}
[[nodiscard]]
@ -196,7 +197,7 @@ class Mover {
}
template<typename T = void>
constexpr void setTypeInfo(const char* = T::TypeName, int = T::TypeVersion, int = ModelFieldCount_v<T>) noexcept {
constexpr void setTypeInfo(const char* = T::TypeName, int = T::TypeVersion, const Vector<String>& = {}, int = ModelFieldCount_v<T>) noexcept {
}
[[nodiscard]]
@ -272,7 +273,7 @@ class Equals {
}
template<typename T = void>
constexpr void setTypeInfo(const char* = T::TypeName, int = T::Fields) noexcept {
constexpr void setTypeInfo(const char* = T::TypeName, const Vector<String>& = {}, int = T::Fields) noexcept {
}
[[nodiscard]]

View File

@ -7,3 +7,17 @@
*/
#include "modelvalue.hpp"
namespace ox {
static_assert([]() -> ox::Error {
ox::ModelValue v;
oxReturnError(v.setType<int32_t>());
if (v.type() != ModelValue::Type::SignedInteger32) {
return OxError(1, "type is wrong");
}
//oxReturnError(v.set<int32_t>(5));
return {};
}() == OxError(0));
}

View File

@ -9,6 +9,7 @@
#pragma once
#include <ox/std/memory.hpp>
#include <ox/std/serialize.hpp>
#include <ox/std/string.hpp>
#include <ox/std/trace.hpp>
#include <ox/std/types.hpp>
@ -60,20 +61,20 @@ class ModelValue {
int32_t i32;
uint32_t ui32;
int64_t i64;
uint64_t ui64;
String *str = nullptr;
uint64_t ui64 = 0;
String *str;
ModelObject *obj;
ModelUnion *uni;
ModelValueVector *vec;
} m_data;
template<typename T>
consteval static Type getType() noexcept {
static consteval Type getType() noexcept {
using U = typename ox::remove_reference<T>::type;
if constexpr(is_bool_v<U>) {
return Type::Bool;
} else if constexpr(is_integer_v<U>) {
if (!is_signed_v<U> && sizeof(U) == 1) {
if constexpr(!is_signed_v<U> && sizeof(U) == 1) {
return Type::UnsignedInteger8;
} else if constexpr(!is_signed_v<U> && sizeof(U) == 2) {
return Type::UnsignedInteger16;
@ -94,7 +95,7 @@ class ModelValue {
return Type::Union;
} else if constexpr(is_same_v<U, ModelObject>) {
return Type::Object;
} else if constexpr(is_same_v<U, String>) {
} else if constexpr(isBasicString_v<U> || isBString_v<U>) {
return Type::String;
} else if constexpr(is_same_v<U, ModelValueVector>) {
return Type::Vector;
@ -198,6 +199,129 @@ class ModelValue {
};
template<typename PlatSpec>
[[nodiscard]]
constexpr std::size_t sizeOf(const ModelValueVector*) noexcept {
VectorMemMap<PlatSpec> v;
return sizeOf<PlatSpec>(&v);
}
template<typename PlatSpec>
[[nodiscard]]
constexpr std::size_t sizeOf(const ModelUnion*) noexcept {
VectorMemMap<PlatSpec> v;
return sizeOf<PlatSpec>(&v);
}
template<typename PlatSpec>
[[nodiscard]]
constexpr std::size_t sizeOf(const ModelValue *t) noexcept {
std::size_t size = 0;
switch (t->type()) {
case ModelValue::Type::Bool:
size = sizeof(t->get<bool>());
break;
case ModelValue::Type::Undefined:
size = 1;
break;
case ModelValue::Type::UnsignedInteger8:
size = sizeof(t->get<uint8_t>());
break;
case ModelValue::Type::UnsignedInteger16:
size = sizeof(t->get<uint16_t>());
break;
case ModelValue::Type::UnsignedInteger32:
size = sizeof(t->get<uint32_t>());
break;
case ModelValue::Type::UnsignedInteger64:
size = sizeof(t->get<uint64_t>());
break;
case ModelValue::Type::SignedInteger8:
size = sizeof(t->get<int8_t>());
break;
case ModelValue::Type::SignedInteger16:
size = sizeof(t->get<int16_t>());
break;
case ModelValue::Type::SignedInteger32:
size = sizeof(t->get<int32_t>());
break;
case ModelValue::Type::SignedInteger64:
size = sizeof(t->get<int64_t>());
break;
case ModelValue::Type::String:
size = sizeOf<PlatSpec>(&t->get<ox::String>());
break;
case ModelValue::Type::Object:
size = sizeOf<PlatSpec>(&t->get<ox::ModelObject>());
break;
case ModelValue::Type::Union:
size = sizeOf<PlatSpec>(&t->get<ox::ModelUnion>());
break;
case ModelValue::Type::Vector:
size = sizeOf<PlatSpec>(&t->get<ox::ModelValueVector>());
break;
}
return size;
}
template<typename PlatSpec>
[[nodiscard]]
constexpr std::size_t alignOf(const ModelValueVector&) noexcept {
VectorMemMap<PlatSpec> v;
return alignOf<PlatSpec>(v);
}
template<typename PlatSpec>
[[nodiscard]]
constexpr std::size_t alignOf(const ModelValue &t) noexcept {
std::size_t size = 0;
switch (t.type()) {
case ModelValue::Type::Bool:
size = PlatSpec::alignOf(t.get<bool>());
break;
case ModelValue::Type::Undefined:
size = 1;
break;
case ModelValue::Type::UnsignedInteger8:
size = PlatSpec::alignOf(t.get<uint8_t>());
break;
case ModelValue::Type::UnsignedInteger16:
size = PlatSpec::alignOf(t.get<uint16_t>());
break;
case ModelValue::Type::UnsignedInteger32:
size = PlatSpec::alignOf(t.get<uint32_t>());
break;
case ModelValue::Type::UnsignedInteger64:
size = PlatSpec::alignOf(t.get<uint64_t>());
break;
case ModelValue::Type::SignedInteger8:
size = PlatSpec::alignOf(t.get<int8_t>());
break;
case ModelValue::Type::SignedInteger16:
size = PlatSpec::alignOf(t.get<int16_t>());
break;
case ModelValue::Type::SignedInteger32:
size = PlatSpec::alignOf(t.get<int32_t>());
break;
case ModelValue::Type::SignedInteger64:
size = PlatSpec::alignOf(t.get<int64_t>());
break;
case ModelValue::Type::String:
size = PlatSpec::alignOf(t.get<ox::String>());
break;
case ModelValue::Type::Object:
size = alignOf<PlatSpec>(t.get<ox::ModelObject>());
break;
case ModelValue::Type::Union:
size = alignOf<PlatSpec>(t.get<ox::ModelUnion>());
break;
case ModelValue::Type::Vector:
size = alignOf<PlatSpec>(t.get<ox::ModelValueVector>());
break;
}
return size;
}
class ModelValueVector {
private:
Vector<ModelValue> m_vec;
@ -329,6 +453,7 @@ class ModelObject {
friend ModelValue;
Vector<UniquePtr<Field>> m_fieldsOrder;
HashMap<String, ModelValue*> m_fields;
const DescriptorType *m_type = nullptr;
String m_typeName;
int m_typeVersion = 0;
@ -340,12 +465,14 @@ class ModelObject {
auto &field = m_fieldsOrder.emplace_back(new Field{f->name, f->value});
m_fields[field->name] = &field->value;
}
m_type = other.m_type;
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
}
constexpr ModelObject(ModelObject &&other) noexcept {
m_fields = std::move(other.m_fields);
m_type = other.m_type;
m_fieldsOrder = std::move(other.m_fieldsOrder);
m_typeName = std::move(other.m_typeName);
m_typeVersion = other.m_typeVersion;
@ -419,6 +546,7 @@ class ModelObject {
auto &field = m_fieldsOrder.emplace_back(new Field{f->name, f->value});
m_fields[field->name] = &field->value;
}
m_type = other.m_type;
m_typeName = other.m_typeName;
m_typeVersion = other.m_typeVersion;
return *this;
@ -428,6 +556,7 @@ class ModelObject {
if (&other == this) [[unlikely]] {
return *this;
}
m_type = other.m_type;
m_fields = std::move(other.m_fields);
m_fieldsOrder = std::move(other.m_fieldsOrder);
m_typeName = std::move(other.m_typeName);
@ -448,7 +577,7 @@ class ModelObject {
}
[[nodiscard]]
constexpr const String &typeName() const noexcept {
constexpr StringView typeName() const noexcept {
return m_typeName;
}
@ -457,10 +586,16 @@ class ModelObject {
return m_typeVersion;
}
[[nodiscard]]
constexpr auto type() const noexcept {
return m_type;
}
constexpr Error setType(const DescriptorType *type) noexcept {
if (type->primitiveType != PrimitiveType::Struct && type->primitiveType != PrimitiveType::Union) {
return OxError(1, "Cannot load a non-struct type to ModelObject");
}
m_type = type;
m_typeName = type->typeName;
m_typeVersion = type->typeVersion;
for (const auto &f : type->fieldList) {
@ -609,7 +744,7 @@ class ModelUnion {
};
constexpr Error model(auto *h, CommonPtrWith<ModelObject> auto *obj) noexcept {
h->setTypeInfo(obj->m_typeName.c_str(), obj->m_typeVersion, static_cast<int>(obj->m_fieldsOrder.size()));
h->setTypeInfo(obj->m_typeName.c_str(), obj->m_typeVersion, {}, static_cast<int>(obj->m_fieldsOrder.size()));
for (auto &f : obj->m_fieldsOrder) {
oxReturnError(h->field(f->name.c_str(), &f->value));
}
@ -617,7 +752,7 @@ constexpr Error model(auto *h, CommonPtrWith<ModelObject> auto *obj) noexcept {
}
constexpr Error model(auto *h, CommonPtrWith<ModelUnion> auto *obj) noexcept {
h->setTypeInfo(obj->m_typeName.c_str(), obj->m_typeVersion, static_cast<int>(obj->m_fieldsOrder.size()));
h->setTypeInfo(obj->m_typeName.c_str(), obj->m_typeVersion, {}, static_cast<int>(obj->m_fieldsOrder.size()));
for (auto &f : obj->m_fieldsOrder) {
oxReturnError(h->field(f->name.c_str(), &f->value));
}
@ -718,7 +853,9 @@ constexpr Error ModelValue::setType(const DescriptorType *type, int subscriptLev
return m_data.vec->setType(type, subscriptLevels - 1);
} else if (type->typeName == types::Bool) {
m_type = Type::Bool;
} else if (type->typeName == types::String) {
} else if (type->typeName == types::BasicString ||
type->typeName == types::BString ||
type->typeName == types::String) {
m_type = Type::String;
m_data.str = new String;
} else if (type->typeName == types::Uint8) {
@ -747,13 +884,47 @@ constexpr Error ModelValue::setType(const DescriptorType *type, int subscriptLev
m_data.uni = u.release();
oxReturnError(m_data.uni->setType(type));
}
oxAssert(m_type != Type::Undefined, "No type set");
return OxError(0);
}
template<typename T>
constexpr Error ModelValue::setType() noexcept {
constexpr auto type = getType<T>();
return setType(type);
freeResources();
m_type = type;
// 2022.09.04: Clang retardedly requires initializing the union values directly, rather than using getValue<type>()
if constexpr(type == Type::Object) {
m_data.obj = new ModelObject;
oxReturnError(m_data.obj->setType(type));
} else if constexpr(type == Type::Union) {
oxRequireM(u, ModelUnion::make(type));
m_data.uni = u.release();
oxReturnError(m_data.uni->setType(type));
} else if constexpr(type == Type::String) {
m_data.str = new String;
} else if constexpr(type == Type::Vector) {
m_data.vec = new ModelValueVector;
} else if constexpr(type == Type::Bool) {
m_data.b = false;
} else if constexpr(type == Type::SignedInteger8) {
m_data.i8 = 0;
} else if constexpr(type == Type::SignedInteger16) {
m_data.i16 = 0;
} else if constexpr(type == Type::SignedInteger32) {
m_data.i32 = 0;
} else if constexpr(type == Type::SignedInteger64) {
m_data.i64 = 0;
} else if constexpr(type == Type::UnsignedInteger8) {
m_data.ui8 = 0;
} else if constexpr(type == Type::UnsignedInteger16) {
m_data.ui16 = 0;
} else if constexpr(type == Type::UnsignedInteger32) {
m_data.ui32 = 0;
} else if constexpr(type == Type::UnsignedInteger64) {
m_data.ui64 = 0;
}
return {};
}
template<typename T>
@ -763,6 +934,10 @@ constexpr Error ModelValue::set(const T &v) noexcept {
return OxError(1, "type mismatch");
}
auto &value = getValue<type>(*this);
if constexpr(type == Type::Vector || type == Type::Object ||
type == Type::Union || type == Type::String) {
safeDelete(&value);
}
value = v;
return OxError(0);
}

View File

@ -8,13 +8,14 @@
#pragma once
#include <ox/std/assert.hpp>
#include <ox/std/concepts.hpp>
#include <ox/std/error.hpp>
#include <ox/std/strops.hpp>
#include <ox/std/stringview.hpp>
namespace ox {
enum class OpType {
Read = 1,
Write,
Reflect,
};
namespace ox::OpType {
constexpr auto Read = "Read";
constexpr auto Write = "Write";
constexpr auto Reflect = "Reflect";
}

View File

@ -0,0 +1,11 @@
add_executable(
ModelTest
tests.cpp
)
target_link_libraries(
ModelTest
OxModel
)
add_test("[ox/model] ModelTest Writer" ModelTest ModelValue)

41
deps/ox/src/ox/model/test/tests.cpp vendored Normal file
View File

@ -0,0 +1,41 @@
/*
* Copyright 2015 - 2022 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#undef NDEBUG
#include <map>
#include <ox/model/model.hpp>
#include <ox/std/std.hpp>
std::map<ox::String, ox::Error(*)()> tests = {
{
{
"ModelValue",
[] {
ox::ModelValue v;
oxReturnError(v.setType<int32_t>());
//v.m_type = ox::ModelValue::getType<int32_t>();
if (v.type() != ox::ModelValue::Type::SignedInteger32) {
return OxError(1, "type is wrong");
}
oxReturnError(v.set<int32_t>(5));
return ox::Error{};
}
},
}
};
int main(int argc, const char **args) {
if (argc > 0) {
auto testName = args[1];
if (tests.find(testName) != tests.end()) {
oxAssert(tests[testName](), "Test failed...");
}
}
return 0;
}

View File

@ -8,9 +8,9 @@
#pragma once
#include <ox/std/memory.hpp>
#include <ox/std/string.hpp>
#include <ox/std/types.hpp>
#include <ox/std/memory.hpp>
#include "fieldcounter.hpp"
#include "optype.hpp"
@ -25,7 +25,7 @@ struct TypeNameCatcher {
constexpr TypeNameCatcher() noexcept = default;
template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *n = T::TypeName, int v = 0) noexcept {
constexpr void setTypeInfo(const char *n = T::TypeName, const Vector<String>& = {}, int v = 0) noexcept {
this->name = n;
this->version = v;
}
@ -59,7 +59,7 @@ struct TypeInfoCatcher {
constexpr TypeInfoCatcher() noexcept = default;
template<typename T = std::nullptr_t>
constexpr void setTypeInfo(const char *n = T::TypeName, int v = T::TypeVersion, int = 0) noexcept {
constexpr void setTypeInfo(const char *n = T::TypeName, int v = T::TypeVersion, const Vector<String>& = {}, int = 0) noexcept {
this->name = n;
this->version = v;
}
@ -87,7 +87,7 @@ struct TypeInfoCatcher {
template<typename T>
constexpr int getModelTypeVersion() noexcept {
auto a = std::allocator<T>();
std::allocator<T> a;
auto t = a.allocate(1);
TypeInfoCatcher nc;
oxIgnoreError(model(&nc, t));
@ -111,7 +111,7 @@ consteval int requireModelTypeVersion() noexcept {
template<typename T, typename Str = const char*>
constexpr Str getModelTypeName() noexcept {
auto a = std::allocator<T>();
std::allocator<T> a;
auto t = a.allocate(1);
TypeNameCatcher nc;
oxIgnoreError(model(&nc, t));

View File

@ -22,6 +22,7 @@
#include <ox/std/array.hpp>
#include <ox/std/bstring.hpp>
#include <ox/std/string.hpp>
#include <ox/std/strops.hpp>
#include <ox/std/types.hpp>
#include <ox/std/typetraits.hpp>
@ -30,25 +31,77 @@
namespace ox {
namespace types {
constexpr auto String = "B.string";
constexpr auto Bool = "B.bool";
constexpr auto Uint8 = "B.uint8";
constexpr auto Uint16 = "B.uint16";
constexpr auto Uint32 = "B.uint32";
constexpr auto Uint64 = "B.uint64";
constexpr auto Int8 = "B.int8";
constexpr auto Int16 = "B.int16";
constexpr auto Int32 = "B.int32";
constexpr auto Int64 = "B.int64";
constexpr StringView BasicString = "net.drinkingtea.ox.BasicString";
constexpr StringView BString = "net.drinkingtea.ox.BString";
constexpr StringView String = "B.string";
constexpr StringView Bool = "B.bool";
constexpr StringView Uint8 = "B.uint8";
constexpr StringView Uint16 = "B.uint16";
constexpr StringView Uint32 = "B.uint32";
constexpr StringView Uint64 = "B.uint64";
constexpr StringView Int8 = "B.int8";
constexpr StringView Int16 = "B.int16";
constexpr StringView Int32 = "B.int32";
constexpr StringView Int64 = "B.int64";
}
template<typename T>
consteval bool isBasicString(const T*) noexcept {
return false;
}
template<std::size_t SmallVecSize>
consteval bool isBasicString(const BasicString<SmallVecSize>*) noexcept {
return true;
}
template<typename T>
constexpr bool isBasicString_v = isBasicString(static_cast<const T*>(nullptr));
static_assert(isBasicString_v<ox::BasicString<0ul>>);
static_assert(isBasicString_v<ox::BasicString<8ul>>);
static_assert(isBasicString_v<ox::String>);
template<typename T>
consteval bool isBString(const T*) noexcept {
return false;
}
template<std::size_t SmallVecSize>
consteval bool isBString(const BasicString<SmallVecSize>*) noexcept {
return true;
}
template<typename T>
constexpr bool isBString_v = isBasicString(static_cast<const T*>(nullptr));
static_assert(isBasicString_v<ox::BasicString<0ul>>);
static_assert(isBasicString_v<ox::BasicString<8ul>>);
static_assert(isBasicString_v<ox::String>);
template<typename T>
constexpr bool isOxString_v = isBString_v<T> || isBasicString_v<T>;
template<typename T>
consteval bool isOxVector(const T*) noexcept {
return false;
}
template<typename T, std::size_t SmallVecSize>
consteval bool isOxVector(const Vector<T, SmallVecSize>*) noexcept {
return true;
}
template<typename T>
constexpr bool isOxVector_v = isVector(static_cast<const T*>(nullptr));
template<typename T>
consteval bool isVector(const T*) noexcept {
return false;
}
template<typename T>
consteval bool isVector(const Vector<T>*) noexcept {
template<typename T, std::size_t SmallVecSize>
consteval bool isVector(const Vector<T, SmallVecSize>*) noexcept {
return true;
}
@ -71,21 +124,36 @@ constexpr bool isVector_v = isVector(static_cast<const T*>(nullptr));
static_assert(isVector_v<ox::Vector<unsigned int, 0ul>>);
template<typename T>
constexpr bool isBareArray_v = false;
template<typename T>
constexpr bool isBareArray_v<T[]> = true;
template<typename T, std::size_t sz>
constexpr bool isBareArray_v<T[sz]> = true;
template<typename T>
constexpr bool isArray_v = false;
template<typename T>
constexpr bool isArray_v<T[]> = false;
constexpr bool isArray_v<T[]> = true;
template<typename T, std::size_t sz>
constexpr bool isArray_v<T[sz]> = false;
constexpr bool isArray_v<T[sz]> = true;
template<typename T, std::size_t sz>
constexpr bool isArray_v<Array<T, sz>> = false;
constexpr bool isArray_v<Array<T, sz>> = true;
template<typename T>
constexpr bool isSmartPtr_v = false;
template<typename T>
constexpr bool isSmartPtr_v<::ox::UniquePtr<T>> = true;
#if __has_include(<array>)
template<typename T, std::size_t sz>
constexpr bool isArray_v<std::array<T, sz>> = false;
template<typename T>
constexpr bool isSmartPtr_v<::std::unique_ptr<T>> = true;
#endif

View File

@ -8,12 +8,12 @@
#pragma once
#include <ox/std/fmt.hpp>
#include <ox/std/hashmap.hpp>
#include <ox/std/memory.hpp>
#include <ox/std/string.hpp>
#include <ox/std/typetraits.hpp>
#include "ox/std/fmt.hpp"
#include "typenamecatcher.hpp"
#include "desctypes.hpp"
@ -23,45 +23,42 @@ class TypeStore {
private:
HashMap<String, UniquePtr<DescriptorType>> m_cache;
static constexpr auto buildTypeId(const auto &name, auto version) noexcept {
return ox::sfmt("{};{}", name, version);
}
public:
constexpr TypeStore() noexcept = default;
constexpr virtual ~TypeStore() noexcept = default;
constexpr Result<const DescriptorType*> get(const auto &name, int typeVersion) const noexcept {
const auto typeId = buildTypeId(name, typeVersion);
constexpr Result<const DescriptorType*> get(const auto &name, int typeVersion,
const Vector<String> &typeParams) const noexcept {
const auto typeId = buildTypeId(name, typeVersion, typeParams);
oxRequire(out, m_cache.at(typeId));
return out->get();
}
template<typename T>
constexpr Result<const DescriptorType*> get() const noexcept {
constexpr auto typeName = requireModelTypeName<T>();
constexpr auto typeVersion = requireModelTypeVersion<T>();
const auto typeId = buildTypeId(typeName, typeVersion);
constexpr auto typeName = ModelTypeName_v<T>;
constexpr auto typeVersion = ModelTypeVersion_v<T>;
const auto typeId = buildTypeId(typeName, typeVersion, {});
oxRequire(out, m_cache.at(typeId));
return out->get();
}
constexpr DescriptorType *getInit(const auto &typeName, int typeVersion) noexcept {
const auto typeId = buildTypeId(typeName, typeVersion);
constexpr DescriptorType *getInit(const auto &typeName, int typeVersion, PrimitiveType pt,
const TypeParamPack &typeParams) noexcept {
const auto typeId = buildTypeId(typeName, typeVersion, typeParams);
auto &out = m_cache[typeId];
out = ox::make_unique<DescriptorType>(typeName, typeVersion);
out = ox::make_unique<DescriptorType>(typeName, typeVersion, pt, typeParams);
return out.get();
}
constexpr Result<const DescriptorType*> getLoad(const auto &typeName, auto typeVersion) noexcept {
const auto typeId = buildTypeId(typeName, typeVersion);
constexpr Result<const DescriptorType*> getLoad(const auto &typeId) noexcept {
auto [val, err] = m_cache.at(typeId);
if (err) {
if (!std::is_constant_evaluated()) {
oxRequireM(dt, loadDescriptor(typeName, typeVersion));
oxRequireM(dt, loadDescriptor(typeId));
for (auto &f : dt->fieldList) {
oxReturnError(this->getLoad(f.typeName, f.typeVersion).moveTo(&f.type));
oxReturnError(this->getLoad(f.typeId).moveTo(&f.type));
}
auto &out = m_cache[typeId];
out = std::move(dt);
@ -73,6 +70,11 @@ class TypeStore {
return val->get();
}
constexpr Result<const DescriptorType*> getLoad(const auto &typeName, auto typeVersion,
const Vector<String> &typeParams = {}) noexcept {
return getLoad(buildTypeId(typeName, typeVersion, typeParams));
}
template<typename T>
constexpr Result<const DescriptorType*> getLoad() noexcept {
constexpr auto typeName = requireModelTypeName<T>();
@ -80,19 +82,17 @@ class TypeStore {
return getLoad(typeName, typeVersion);
}
constexpr void set(const auto &typeName, auto typeVersion, UniquePtr<DescriptorType> dt) noexcept {
const auto typeId = buildTypeId(typeName, typeVersion);
constexpr void set(const auto &typeId, UniquePtr<DescriptorType> dt) noexcept {
m_cache[typeId] = std::move(dt);
}
constexpr void set(const auto &typeName, auto typeVersion, DescriptorType *dt) noexcept {
const auto typeId = buildTypeId(typeName, typeVersion);
m_cache[typeId] = UniquePtr<DescriptorType>(dt);
constexpr void set(const auto &typeId, DescriptorType *dt) noexcept {
m_cache[typeId] = UniquePtr<DescriptorType>(dt);
}
[[nodiscard]]
constexpr auto typeList() const noexcept {
auto keys = m_cache.keys();
const auto &keys = m_cache.keys();
ox::Vector<DescriptorType*> descs;
for (const auto &k : keys) {
descs.emplace_back(m_cache.at(k).value->get());
@ -101,10 +101,16 @@ class TypeStore {
}
protected:
virtual Result<UniquePtr<DescriptorType>> loadDescriptor(const ox::String&, int) noexcept {
virtual Result<UniquePtr<DescriptorType>> loadDescriptor(ox::CRStringView) noexcept {
return OxError(1);
}
Result<UniquePtr<DescriptorType>> loadDescriptor(ox::CRStringView name, int version,
const Vector<String> &typeParams) noexcept {
const auto typeId = buildTypeId(name, version, typeParams);
return loadDescriptor(typeId);
}
};
}

View File

@ -89,7 +89,7 @@ static constexpr Error parseField(const DescriptorField &field, Reader *rdr, Dat
// add array handling
oxRequire(arrayLen, rdr->arrayLength(field.fieldName.c_str(), true));
auto child = rdr->child(field.fieldName.c_str());
child.setTypeInfo(field.type->typeName.c_str(), field.type->typeVersion, arrayLen);
child.setTypeInfo(field.type->typeName.c_str(), field.type->typeVersion, field.type->typeParams, arrayLen);
DescriptorField f(field); // create mutable copy
--f.subscriptLevels;
String subscript;
@ -135,8 +135,9 @@ constexpr Error model(Reader *rdr, DataWalker<Reader, FH> *walker) noexcept {
oxRequire(type, walker->type());
auto typeName = type->typeName.c_str();
auto typeVersion = type->typeVersion;
auto typeParams = type->typeParams;
auto &fields = type->fieldList;
rdr->setTypeInfo(typeName, typeVersion, fields.size());
rdr->setTypeInfo(typeName, typeVersion, typeParams, fields.size());
for (const auto &field : fields) {
oxReturnError(parseField(field, rdr, walker));
}

View File

@ -100,11 +100,11 @@ class OrganicClawReader {
}
template<typename T = void>
constexpr void setTypeInfo(const char*, int) noexcept {
constexpr void setTypeInfo(const char*, int, const Vector<String>& = {}) noexcept {
}
template<typename T = void>
constexpr void setTypeInfo(const char*, int, int) noexcept {
constexpr void setTypeInfo(const char*, int, const Vector<String>& = {}, int = {}) noexcept {
}
/**

View File

@ -94,7 +94,7 @@ constexpr ox::Error model(auto *io, ox::CommonPtrWith<TestStruct> auto *obj) noe
oxReturnError(io->field("Int7", &obj->Int7));
oxReturnError(io->field("Int8", &obj->Int8));
oxReturnError(io->field("unionIdx", &obj->unionIdx));
if (ox_strcmp(io->opType(), ox::OpType::Reflect) == 0) {
if (io->opType() == ox::OpType::Reflect) {
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, 0}));
} else {
oxReturnError(io->field("Union", ox::UnionView{&obj->Union, obj->unionIdx}));

View File

@ -176,7 +176,8 @@ class OrganicClawWriter {
Error field(const char*, T *val) noexcept;
template<typename T = void>
constexpr void setTypeInfo(const char* = T::TypeName, int = T::TypeVersion, int = ModelFieldCount_v<T>) noexcept {
constexpr void setTypeInfo(const char* = T::TypeName, int = T::TypeVersion,
const Vector<String>& = {}, int = ModelFieldCount_v<T>) noexcept {
}
static constexpr auto opType() noexcept {

24
deps/ox/src/ox/preloader/CMakeLists.txt vendored Normal file
View File

@ -0,0 +1,24 @@
add_library(
OxPreloader
preload.cpp
preloader.cpp
)
target_link_libraries(
OxPreloader PUBLIC
OxClaw
OxModel
OxStd
)
install(
FILES
alignmentcatcher.hpp
platspecs.hpp
preload.hpp
preloader.hpp
unionsizecatcher.hpp
DESTINATION
include/nostalgia/preloader
)

View File

@ -0,0 +1,62 @@
/*
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/model/modelhandleradaptor.hpp>
#include <ox/model/optype.hpp>
#include <ox/model/types.hpp>
#include <ox/std/error.hpp>
#include <ox/std/string.hpp>
#include <ox/std/types.hpp>
namespace ox {
template<typename PlatSpec, typename T>
[[nodiscard]]
constexpr std::size_t alignOf(const T &t) noexcept;
template<typename PlatSpec, typename T>
[[nodiscard]]
constexpr std::size_t sizeOf(const T *t) noexcept;
template<typename PlatSpec>
struct AlignmentCatcher: public ModelHandlerBase<AlignmentCatcher<PlatSpec>> {
std::size_t biggestAlignment = 1;
template<typename ...T>
constexpr void setTypeInfo(T&&...) const noexcept {
}
template<typename T, bool force>
constexpr ox::Error field(CRStringView name, const UnionView<T, force> val) noexcept {
return field(name, val.get());
}
template<typename T>
constexpr ox::Error field(CRStringView, const T *val) noexcept {
if constexpr(ox::is_integer_v<T>) {
biggestAlignment = ox::max(biggestAlignment, PlatSpec::alignOf(*val));
} else {
biggestAlignment = ox::max(biggestAlignment, alignOf<PlatSpec>(*val));
}
return {};
}
template<typename T>
constexpr ox::Error field(CRStringView, const T *val, std::size_t cnt) noexcept {
for (std::size_t i = 0; i < cnt; ++i) {
oxReturnError(field(nullptr, &val[i]));
}
return {};
}
[[nodiscard]]
static constexpr auto opType() noexcept {
return ox::OpType::Reflect;
}
};
}

126
deps/ox/src/ox/preloader/platspecs.hpp vendored Normal file
View File

@ -0,0 +1,126 @@
/*
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/serialize.hpp>
#include <ox/std/typetraits.hpp>
#include "alignmentcatcher.hpp"
#include "sizecatcher.hpp"
namespace ox {
struct NativePlatSpec {
using PtrType = uintptr_t;
using size_t = std::size_t;
static constexpr auto PtrAlign = alignof(void*);
static constexpr PtrType RomStart = 0x08000000;
template<typename T>
[[nodiscard]]
static constexpr auto alignOf(const T &v) noexcept {
if constexpr(ox::is_integral_v<T>) {
return alignof(T);
} else if constexpr(ox::is_pointer_v<T>) {
return PtrAlign;
} else {
AlignmentCatcher<NativePlatSpec> c;
oxAssert(model(c.interface(), &v), "Could not get alignment for type");
return c.biggestAlignment;
}
}
[[nodiscard]]
static constexpr auto correctEndianness(auto v) noexcept {
return v;
}
};
struct GbaPlatSpec {
using PtrType = uint32_t;
using size_t = uint32_t;
static constexpr auto PtrAlign = 4;
static constexpr PtrType RomStart = 0x08000000;
[[nodiscard]]
static constexpr std::size_t alignOf(const bool) noexcept {
return 1;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const uint8_t) noexcept {
return 1;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const uint16_t) noexcept {
return 2;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const uint32_t) noexcept {
return 4;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const uint64_t) noexcept {
return 8;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const int8_t) noexcept {
return 1;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const int16_t) noexcept {
return 2;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const int32_t) noexcept {
return 4;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const int64_t) noexcept {
return 8;
}
[[nodiscard]]
static constexpr std::size_t alignOf(auto*) noexcept {
return 4;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const auto*) noexcept {
return 4;
}
[[nodiscard]]
static constexpr std::size_t alignOf(const auto &v) noexcept {
AlignmentCatcher<GbaPlatSpec> c;
oxAssert(model(c.interface(), &v), "Could not get alignment for type");
return c.biggestAlignment;
}
[[nodiscard]]
static constexpr auto correctEndianness(auto v) noexcept {
return ox::toLittleEndian(v);
}
};
template<typename PlatSpec, typename T>
[[nodiscard]]
constexpr std::size_t alignOf(const T &t) noexcept {
return PlatSpec::alignOf(t);
}
template<typename PlatSpec, typename T>
constexpr auto alignOf_v = alignOf<PlatSpec>(static_cast<T*>(nullptr));
}

33
deps/ox/src/ox/preloader/preload.cpp vendored Normal file
View File

@ -0,0 +1,33 @@
/*
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <ox/claw/claw.hpp>
#include "preload.hpp"
namespace ox {
static ox::Error buildPreloadBuffer(ox::Buffer *buff, std::size_t buffStart, ox::FileSystem *fs,
ox::TypeStore *ts, const char *path) noexcept {
oxRequire(files, fs->ls(path));
for (const auto &f : files) {
oxRequire(stat, fs->stat(f));
if (stat.fileType == ox::FileType::NormalFile) {
oxRequire(fileBuff, fs->read(path));
oxRequire(obj, ox::readClaw(ts, fileBuff));
} else if (stat.fileType == ox::FileType::Directory) {
const auto childPath = ox::sfmt("{}/{}", path, f);
oxReturnError(buildPreloadBuffer(buff, buffStart, fs, ts, childPath.c_str()));
}
}
return {};
}
ox::Result<ox::Buffer> buildPreloadBuffer(std::size_t buffStart, ox::FileSystem *fs, ox::TypeStore *ts) noexcept {
ox::Buffer buff;
oxReturnError(buildPreloadBuffer(&buff, buffStart, fs, ts, "/"));
return buff;
}
}

21
deps/ox/src/ox/preloader/preload.hpp vendored Normal file
View File

@ -0,0 +1,21 @@
/*
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/fs/fs.hpp>
#include <ox/std/buffer.hpp>
namespace ox {
/**
*
* @param buffStart where the preload buffer will start in ROM
* @param fs an ox::FileSystem containing the contents to be preloaded
* @return preload buffer or error
*/
[[maybe_unused]]
ox::Result<ox::Buffer> buildPreloadBuffer(std::size_t buffStart, ox::FileSystem *fs) noexcept;
}

33
deps/ox/src/ox/preloader/preloader.cpp vendored Normal file
View File

@ -0,0 +1,33 @@
/*
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#include <ox/std/error.hpp>
#include "platspecs.hpp"
#include "preloader.hpp"
namespace ox {
struct TestType {
static constexpr auto TypeName = "net.drinkingtea.nostalgia.preloader.TestType";
static constexpr auto TypeVersion = 1;
uint32_t field1 = 0;
uint32_t *field2 = nullptr;
ox::Vector<uint32_t> field3;
};
oxModelBegin(TestType)
oxModelField(field1)
oxModelField(field2)
oxModelField(field3)
oxModelEnd()
constexpr ox::Error asdf() noexcept {
const TestType t;
return preload<NativePlatSpec>(&t).error;
}
//static_assert(asdf().errCode == 0);
}

287
deps/ox/src/ox/preloader/preloader.hpp vendored Normal file
View File

@ -0,0 +1,287 @@
/*
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/std/array.hpp>
#include <ox/std/buffer.hpp>
#include <ox/std/byteswap.hpp>
#include <ox/std/error.hpp>
#include <ox/std/memops.hpp>
#include <ox/std/memory.hpp>
#include <ox/std/types.hpp>
#include <ox/std/typetraits.hpp>
#include <ox/std/units.hpp>
#include <ox/model/modelhandleradaptor.hpp>
#include "preloader.hpp"
#include "platspecs.hpp"
namespace ox {
template<typename PlatSpec>
class Preloader: public ModelHandlerBase<Preloader<PlatSpec>> {
private:
class UnionIdxTracker {
private:
int m_unionIdx = -1;
int m_it = 0;
public:
constexpr UnionIdxTracker() noexcept = default;
constexpr explicit UnionIdxTracker(int idx) noexcept: m_unionIdx(idx) {}
constexpr auto checkAndIterate() noexcept {
return m_unionIdx == -1 || m_it++ == m_unionIdx;
}
};
ox::Buffer m_buff;
ox::BufferWriter m_writer;
// list of all the places where ptrs were written to buffer
struct PtrPair {
std::size_t loc = 0;
typename PlatSpec::PtrType value = 0;
constexpr PtrPair() noexcept = default;
constexpr PtrPair(std::size_t pLoc, typename PlatSpec::PtrType pValue) noexcept:
loc(pLoc), value(pValue) {}
};
ox::Vector<PtrPair> m_ptrs;
ox::Vector<UnionIdxTracker, 8> m_unionIdx = {{}};
constexpr Preloader() noexcept: m_writer(&m_buff) {}
Preloader(const Preloader &src) = delete;
Preloader(Preloader &&src) = delete;
const Preloader &operator=(const Preloader &src) = delete;
const Preloader &operator=(Preloader &&src) = delete;
public:
constexpr static ox::Result<ox::UniquePtr<Preloader>> make(ox::ios_base::seekdir anchor = ox::ios_base::cur,
std::size_t sz = 0) noexcept;
constexpr void setTypeInfo(CRStringView, int, const ox::Vector<String>& = {}, int = 0) noexcept {}
template<typename U, bool force>
constexpr ox::Error field(CRStringView, const ox::UnionView<U, force> val) noexcept;
template<typename T>
constexpr ox::Error field(CRStringView, const T *val) noexcept;
template<std::size_t SmallStringSize>
constexpr ox::Error field(CRStringView, const ox::BasicString<SmallStringSize> *val) noexcept;
template<typename T, std::size_t sz>
constexpr ox::Error field(CRStringView, const ox::Array<T, sz> *valArray) noexcept;
template<typename T>
constexpr ox::Error field(CRStringView, const T **val, std::size_t cnt) noexcept;
constexpr ox::Error offsetPtrs(std::size_t offset) noexcept;
[[nodiscard]]
constexpr auto &buff() const noexcept {
return m_buff;
}
[[nodiscard]]
static constexpr auto opType() noexcept {
return ox::OpType::Write;
}
private:
constexpr ox::Error fieldVector(CRStringView name, const ox::ModelValueVector *val) noexcept;
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr ox::Error fieldVector(CRStringView, const ox::Vector<T, SmallVectorSize, Allocator> *val) noexcept;
constexpr ox::Error fieldVector(CRStringView, const auto *val, ox::VectorMemMap<PlatSpec> vecVal) noexcept;
constexpr ox::Error pad(const auto *val) noexcept;
constexpr bool unionCheckAndIt() noexcept;
};
template<typename PlatSpec>
constexpr ox::Result<ox::UniquePtr<Preloader<PlatSpec>>>
Preloader<PlatSpec>::make(ox::ios_base::seekdir anchor, std::size_t sz) noexcept {
auto p = ox::UniquePtr<Preloader>(new Preloader);
if (const auto err = p->m_writer.seekp(0, anchor)) {
return {std::move(p), err};
}
if (const auto err = p->m_writer.write(nullptr, sz)) {
return {std::move(p), err};
}
if (const auto err = p->m_writer.seekp(p->m_writer.tellp() - sz)) {
return {std::move(p), err};
}
return p;
}
template<typename PlatSpec>
template<typename U, bool force>
constexpr ox::Error Preloader<PlatSpec>::field(CRStringView, const ox::UnionView<U, force> val) noexcept {
if (!unionCheckAndIt()) {
return {};
}
oxReturnError(pad(val.get()));
m_unionIdx.emplace_back(val.idx());
const auto err = model(this->interface(), val.get());
m_unionIdx.pop_back();
return err;
}
template<typename PlatSpec>
template<typename T>
constexpr ox::Error Preloader<PlatSpec>::field(CRStringView name, const T *val) noexcept {
if (!unionCheckAndIt()) {
return {};
}
oxReturnError(pad(val));
if constexpr(ox::is_integral_v<T>) {
return ox::serialize(&m_writer, PlatSpec::correctEndianness(*val));
} else if constexpr(ox::is_pointer_v<T>) {
return {};
} else if constexpr(ox::isVector_v<T> || ox::is_same_v<T, ox::ModelValueVector>) {
return fieldVector(name, val);
} else {
m_unionIdx.emplace_back(-1);
const auto out = model(this->interface(), val);
m_unionIdx.pop_back();
return out;
}
}
template<typename PlatSpec>
template<std::size_t SmallStringSize>
constexpr ox::Error Preloader<PlatSpec>::field(CRStringView, const ox::BasicString<SmallStringSize> *val) noexcept {
if (!unionCheckAndIt()) {
return {};
}
using VecMap = ox::VectorMemMap<PlatSpec>;
const auto sz = val->bytes();
oxRequire(a, ox::allocate(&m_writer, sz));
const VecMap vecVal{
.smallVecSize = SmallStringSize,
.size = PlatSpec::correctEndianness(static_cast<typename PlatSpec::size_t>(sz)),
.cap = PlatSpec::correctEndianness(static_cast<typename PlatSpec::size_t>(sz)),
.items = sz ? PlatSpec::correctEndianness(static_cast<typename PlatSpec::size_t>(a) + PlatSpec::RomStart) : 0,
};
oxReturnError(pad(&vecVal));
const auto restore = m_writer.tellp();
oxReturnError(m_writer.seekp(a));
oxReturnError(m_writer.write(val->data(), sz));
oxReturnError(m_writer.seekp(restore));
oxReturnError(serialize(&m_writer, vecVal));
m_ptrs.emplace_back(restore + offsetof(VecMap, items), vecVal.items);
return {};
}
template<typename PlatSpec>
template<typename T, std::size_t sz>
constexpr ox::Error Preloader<PlatSpec>::field(CRStringView name, const ox::Array<T, sz> *val) noexcept {
if (!unionCheckAndIt()) {
return {};
}
// serialize the Array elements
if constexpr(sz) {
m_unionIdx.emplace_back(-1);
for (std::size_t i = 0; i < val->size(); ++i) {
oxReturnError(this->interface()->field(name, &(*val)[i]));
}
m_unionIdx.pop_back();
}
return {};
}
template<typename PlatSpec>
template<typename T>
constexpr ox::Error Preloader<PlatSpec>::field(CRStringView, const T **val, std::size_t cnt) noexcept {
if (!unionCheckAndIt()) {
return {};
}
// serialize the array
m_unionIdx.emplace_back(-1);
for (std::size_t i = 0; i < cnt; ++i) {
oxReturnError(this->interface()->field(nullptr, &val[i]));
}
m_unionIdx.pop_back();
return {};
}
template<typename PlatSpec>
constexpr ox::Error Preloader<PlatSpec>::offsetPtrs(std::size_t offset) noexcept {
for (const auto &p : m_ptrs) {
oxReturnError(m_writer.seekp(p.loc));
oxReturnError(ox::serialize(&m_writer, PlatSpec::correctEndianness(p.value + offset)));
}
return {};
}
template<typename PlatSpec>
constexpr ox::Error Preloader<PlatSpec>::fieldVector(CRStringView name, const ox::ModelValueVector *val) noexcept {
// serialize the Vector
ox::VectorMemMap<PlatSpec> vecVal{
.size = PlatSpec::correctEndianness(static_cast<typename PlatSpec::size_t>(val->size())),
.cap = PlatSpec::correctEndianness(static_cast<typename PlatSpec::size_t>(val->size())),
};
return fieldVector(name, val, vecVal);
}
template<typename PlatSpec>
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr ox::Error Preloader<PlatSpec>::fieldVector(CRStringView name, const ox::Vector<T, SmallVectorSize, Allocator> *val) noexcept {
// serialize the Vector
ox::VectorMemMap<PlatSpec> vecVal{
.smallVecSize = SmallVectorSize * sizeOf<PlatSpec>(static_cast<T*>(nullptr)),
.size = PlatSpec::correctEndianness(static_cast<typename PlatSpec::size_t>(val->size())),
.cap = PlatSpec::correctEndianness(static_cast<typename PlatSpec::size_t>(val->size())),
};
return fieldVector(name, val, vecVal);
}
template<typename PlatSpec>
constexpr ox::Error Preloader<PlatSpec>::fieldVector(CRStringView, const auto *val, ox::VectorMemMap<PlatSpec> vecVal) noexcept {
oxReturnError(pad(&vecVal));
const auto vecValPt = m_writer.tellp();
// serialize the Vector elements
if (val->size()) {
const auto sz = sizeOf<PlatSpec>(&(*val)[0]) * val->size();
oxRequire(p, ox::allocate(&m_writer, sz));
oxReturnError(m_writer.seekp(p));
m_unionIdx.emplace_back(-1);
for (std::size_t i = 0; i < val->size(); ++i) {
oxReturnError(this->interface()->field(nullptr, &val->operator[](i)));
}
m_unionIdx.pop_back();
vecVal.items = PlatSpec::correctEndianness(p + PlatSpec::RomStart);
oxReturnError(m_writer.seekp(vecValPt));
} else {
vecVal.items = 0;
}
// serialize the Vector
oxReturnError(serialize(&m_writer, vecVal));
m_ptrs.emplace_back(vecValPt + offsetof(ox::VectorMemMap<PlatSpec>, items), vecVal.items);
return {};
}
template<typename PlatSpec>
constexpr ox::Error Preloader<PlatSpec>::pad(const auto *val) noexcept {
constexpr auto a = alignOf_v<PlatSpec, decltype(val)>;
const auto padding = a - m_writer.tellp() % a;
return m_writer.write(nullptr, padding);
}
template<typename PlatSpec>
constexpr bool Preloader<PlatSpec>::unionCheckAndIt() noexcept {
auto &u = m_unionIdx.back().unwrap();
return u.checkAndIterate();
}
template<typename PlatSpec>
constexpr ox::Result<ox::Buffer> preload(const auto *obj) noexcept {
using Pl = Preloader<PlatSpec>;
oxRequireM(preloader, Pl::make(ox::ios_base::end));
oxReturnError(model(preloader->interface(), obj));
return preloader->buff();
}
}

109
deps/ox/src/ox/preloader/sizecatcher.hpp vendored Normal file
View File

@ -0,0 +1,109 @@
/*
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/model/modelhandleradaptor.hpp>
#include <ox/model/optype.hpp>
#include <ox/model/types.hpp>
#include <ox/std/error.hpp>
#include <ox/std/string.hpp>
#include <ox/std/types.hpp>
#include "unionsizecatcher.hpp"
namespace ox {
template<typename PlatSpec, typename T>
[[nodiscard]]
constexpr std::size_t alignOf(const T &t) noexcept;
template<typename PlatSpec, typename T>
[[nodiscard]]
constexpr std::size_t sizeOf(const T *t) noexcept;
template<typename PlatSpec>
class SizeCatcher: public ModelHandlerBase<SizeCatcher<PlatSpec>> {
private:
std::size_t m_size = 0;
public:
constexpr explicit SizeCatcher() noexcept = default;
template<typename ...T>
constexpr void setTypeInfo(T&&...) const noexcept {
}
template<typename T, bool force>
constexpr ox::Error field(const char*, UnionView<T, force>) noexcept;
template<typename T>
constexpr ox::Error field(const char*, const T *val) noexcept;
template<typename T>
constexpr ox::Error field(const char*, const T **val, std::size_t cnt) noexcept;
[[nodiscard]]
constexpr auto size() const noexcept {
return m_size;
}
[[nodiscard]]
static constexpr auto opType() noexcept {
return ox::OpType::Reflect;
}
private:
constexpr void pad(const auto *val) noexcept;
};
template<typename PlatSpec>
template<typename T, bool force>
constexpr ox::Error SizeCatcher<PlatSpec>::field(const char*, const UnionView<T, force> val) noexcept {
pad(val.get());
UnionSizeCatcher<PlatSpec> sc;
oxReturnError(model(sc.interface(), val.get()));
m_size += sc.size();
return {};
}
template<typename PlatSpec>
template<typename T>
constexpr ox::Error SizeCatcher<PlatSpec>::field(const char*, const T *val) noexcept {
pad(val);
m_size += sizeOf<PlatSpec>(val);
return {};
}
template<typename PlatSpec>
template<typename T>
constexpr ox::Error SizeCatcher<PlatSpec>::field(const char*, const T **val, std::size_t cnt) noexcept {
for (std::size_t i = 0; i < cnt; ++i) {
oxReturnError(field("", &val[i]));
}
return {};
}
template<typename PlatSpec>
constexpr void SizeCatcher<PlatSpec>::pad(const auto *val) noexcept {
const auto padding = m_size - m_size % alignOf<PlatSpec>(*val);
m_size += padding;
}
template<typename PlatSpec, typename T>
[[nodiscard]]
constexpr std::size_t sizeOf(const T *t) noexcept {
if constexpr(ox::is_integral_v<T>) {
return sizeof(T);
} else if constexpr(ox::is_pointer_v<T>) {
return sizeof(PlatSpec::PtrType);
} else {
SizeCatcher<PlatSpec> sc;
const auto err = model(sc.interface(), t);
oxAssert(err, "Could not get size of type");
return sc.size();
}
}
}

View File

@ -0,0 +1,97 @@
/*
* Copyright 2016 - 2022 Gary Talent (gary@drinkingtea.net). All rights reserved.
*/
#pragma once
#include <ox/model/modelhandleradaptor.hpp>
#include <ox/model/optype.hpp>
#include <ox/model/types.hpp>
#include <ox/std/error.hpp>
#include <ox/std/string.hpp>
#include <ox/std/types.hpp>
namespace ox {
template<typename PlatSpec>
class UnionSizeCatcher: public ModelHandlerBase<UnionSizeCatcher<PlatSpec>> {
private:
std::size_t m_size = 0;
public:
template<typename ...T>
constexpr void setTypeInfo(T&&...) const noexcept {
}
template<typename T, bool force>
constexpr ox::Error field(CRStringView, const UnionView<T, force> val) noexcept {
UnionSizeCatcher<PlatSpec> sc;
oxReturnError(model(sc.interface(), val.get()));
m_size += sc.size();
return {};
}
template<typename T>
constexpr ox::Error field(CRStringView, const T *val) noexcept;
template<typename T>
constexpr ox::Error field(CRStringView, const T **val, std::size_t cnt) noexcept;
[[nodiscard]]
constexpr auto size() const noexcept {
return m_size;
}
[[nodiscard]]
static constexpr auto opType() noexcept {
return ox::OpType::Reflect;
}
private:
template<typename T, std::size_t SmallVecSize>
constexpr ox::Error fieldStr(CRStringView, const ox::BasicString<SmallVecSize> *val) noexcept;
template<typename T, std::size_t SmallVecSize>
constexpr ox::Error fieldVector(CRStringView, const ox::Vector<T, SmallVecSize> *val) noexcept;
constexpr void setSize(std::size_t sz) noexcept;
};
template<typename PlatSpec>
template<typename T>
constexpr ox::Error UnionSizeCatcher<PlatSpec>::field(CRStringView, const T *val) noexcept {
setSize(sizeOf<PlatSpec>(val));
return {};
}
template<typename PlatSpec>
template<typename T>
constexpr ox::Error UnionSizeCatcher<PlatSpec>::field(CRStringView, const T **val, std::size_t cnt) noexcept {
for (std::size_t i = 0; i < cnt; ++i) {
oxReturnError(field("", &val[i]));
}
return {};
}
template<typename PlatSpec>
template<typename T, std::size_t SmallStrSize>
constexpr ox::Error UnionSizeCatcher<PlatSpec>::fieldStr(CRStringView, const ox::BasicString<SmallStrSize>*) noexcept {
ox::VectorMemMap<PlatSpec> v;
setSize(sizeOf<PlatSpec>(v));
return {};
}
template<typename PlatSpec>
template<typename T, std::size_t SmallVecSize>
constexpr ox::Error UnionSizeCatcher<PlatSpec>::fieldVector(CRStringView, const ox::Vector<T, SmallVecSize>*) noexcept {
ox::VectorMemMap<PlatSpec> v;
setSize(sizeOf<PlatSpec>(v));
return {};
}
template<typename PlatSpec>
constexpr void UnionSizeCatcher<PlatSpec>::setSize(std::size_t sz) noexcept {
m_size = ox::max(m_size, sz);
}
}

View File

@ -90,10 +90,12 @@ install(
new.hpp
optional.hpp
random.hpp
serialize.hpp
std.hpp
stddef.hpp
stacktrace.hpp
string.hpp
stringview.hpp
strongint.hpp
strops.hpp
trace.hpp
@ -102,6 +104,7 @@ install(
typetraits.hpp
units.hpp
vector.hpp
writer.hpp
DESTINATION
include/ox/std
)

View File

@ -30,4 +30,14 @@ constexpr It find_if(It begin, It end, auto predicate) {
return end;
}
template<typename It, typename Size, typename OutIt>
constexpr OutIt copy_n(It in, Size cnt, OutIt out) {
for (Size i = 0; i < cnt; ++i) {
*out = *in;
++out;
++in;
}
return out;
}
}

View File

@ -51,7 +51,7 @@ constexpr void assertFunc(const char *file, int line, bool pass, [[maybe_unused]
constexpr void assertFunc(const char *file, int line, const Error &err, const char*, const char *assertMsg) noexcept {
if (err) {
if (!std::is_constant_evaluated()) {
if (!std::is_constant_evaluated()) {
#if defined(OX_USE_STDLIB)
oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, assertMsg);
if (err.msg) {
@ -73,4 +73,22 @@ constexpr void assertFunc(const char *file, int line, const Error &err, const ch
}
}
constexpr void expect(const char *file, int line, const auto &actual, const auto &expected) noexcept {
if (actual != expected) {
if (!std::is_constant_evaluated()) {
#if defined(OX_USE_STDLIB)
oxErrf("\n\033[31;1;1mASSERT FAILURE:\033[0m [{}:{}]: {}\n", file, line, "Value incorrect");
oxErrf("expected: {}, actual: {}\n", detail::toStringView<true>(expected), detail::toStringView<true>(actual));
printStackTrace(2);
oxTracef("assert::expect", "Failed assert: {} == {} [{}:{}]", detail::toStringView<true>(actual), detail::toStringView<true>(expected), file, line);
std::abort();
#else
constexprPanic(file, line, "Comparison failed");
#endif
} else {
while (true);
}
}
}
}

View File

@ -21,7 +21,8 @@
namespace std {
template<typename To, typename From>
constexpr typename ox::enable_if<sizeof(To) == sizeof(From), To>::type bit_cast(const From &src) noexcept {
[[nodiscard]]
constexpr To bit_cast(const From &src) noexcept requires(sizeof(To) == sizeof(From)) {
return __builtin_bit_cast(To, src);
}

View File

@ -9,6 +9,7 @@
#pragma once
#include "memops.hpp"
#include "stringview.hpp"
#include "strops.hpp"
#include "typetraits.hpp"
@ -23,6 +24,8 @@ class BString {
public:
constexpr BString() noexcept;
constexpr BString(StringView str) noexcept;
constexpr BString(const char *str) noexcept;
constexpr BString &operator=(const char *str) noexcept;
@ -37,6 +40,8 @@ class BString {
constexpr BString &operator+=(Integer_c auto i) noexcept;
constexpr BString &operator+=(StringView s) noexcept;
constexpr BString operator+(const char *str) const noexcept;
constexpr BString operator+(char *str) const noexcept;
@ -81,6 +86,11 @@ template<std::size_t size>
constexpr BString<size>::BString() noexcept: m_buff{{0}} {
}
template<std::size_t size>
constexpr BString<size>::BString(StringView str) noexcept: m_buff{{0}} {
*this = str;
}
template<std::size_t size>
constexpr BString<size>::BString(const char *str) noexcept: m_buff{{0}} {
*this = str;
@ -129,6 +139,12 @@ constexpr BString<size> &BString<size>::operator+=(Integer_c auto i) noexcept {
return this->operator+=(str);
}
template<std::size_t size>
constexpr BString<size> &BString<size>::operator+=(StringView s) noexcept {
std::size_t strLen = s.bytes();
oxIgnoreError(append(s.data(), strLen));
}
template<std::size_t size>
constexpr BString<size> BString<size>::operator+(const char *str) const noexcept {
auto out = *this;

View File

@ -13,4 +13,7 @@ namespace ox {
template class Vector<char>;
template class WriterT<BufferWriter>;
template class WriterT<CharBuffWriter>;
}

View File

@ -10,6 +10,7 @@
#include "error.hpp"
#include "vector.hpp"
#include "writer.hpp"
namespace ox {
@ -17,4 +18,155 @@ extern template class Vector<char>;
using Buffer = Vector<char>;
class BufferWriter {
private:
std::size_t m_it = 0;
ox::Buffer &m_buff;
public:
explicit constexpr BufferWriter(Buffer *buff) noexcept: m_it(buff->size()), m_buff(*buff) {
}
explicit constexpr BufferWriter(Buffer *buff, std::size_t it) noexcept: m_it(it), m_buff(*buff) {
}
constexpr ox::Error seekp(std::size_t p) noexcept {
m_it = p;
return {};
}
constexpr ox::Error seekp(ox::Signed<std::size_t> off, ox::ios_base::seekdir dir) noexcept {
ox::Signed<std::size_t> base = 0;
switch (dir) {
case ox::ios_base::beg:
base = 0;
break;
case ox::ios_base::end:
base = static_cast<ox::Signed<std::size_t>>(m_buff.size());
break;
case ox::ios_base::cur:
base = static_cast<ox::Signed<std::size_t>>(m_it);
break;
default:
return OxError(1, "Invalid seekdir");
}
m_it = static_cast<std::size_t>(base + off);
return {};
}
[[nodiscard]]
constexpr auto tellp() const noexcept {
return m_it;
}
constexpr ox::Error put(char val) noexcept {
if (m_it >= m_buff.size()) [[unlikely]] {
m_buff.resize(m_buff.size() + 1);
}
m_buff[m_it] = val;
++m_it;
return {};
}
constexpr ox::Error write(const char *inBuff, std::size_t cnt) noexcept {
const auto end = m_it + cnt;
if (end >= m_buff.size()) {
m_buff.resize(end);
}
if (inBuff) {
const auto buff = m_buff.data() + m_it;
for (auto i = 0u; i < cnt; ++i) {
buff[i] = inBuff[i];
}
}
m_it += cnt;
return {};
}
[[nodiscard]]
constexpr auto data() const noexcept {
return &m_buff;
}
};
class CharBuffWriter {
private:
std::size_t m_it = 0;
std::size_t m_cap = 0;
std::size_t m_size = 0;
char *m_buff = nullptr;
public:
template<std::size_t sz>
explicit constexpr CharBuffWriter(ox::Array<char, sz> *buff) noexcept:
m_cap(buff->size()),
m_buff(buff->data()) {
}
explicit constexpr CharBuffWriter(char *buff, std::size_t size) noexcept: m_cap(size), m_buff(buff) {
}
constexpr ox::Error seekp(std::size_t p) noexcept {
m_it = p;
return {};
}
constexpr ox::Error seekp(ox::Signed<std::size_t> off, ox::ios_base::seekdir dir) noexcept {
ox::Signed<std::size_t> base = 0;
switch (dir) {
case ox::ios_base::beg:
base = 0;
break;
case ox::ios_base::end:
base = static_cast<ox::Signed<std::size_t>>(m_size);
break;
case ox::ios_base::cur:
base = static_cast<ox::Signed<std::size_t>>(m_it);
break;
default:
return OxError(1, "Invalid seekdir");
}
m_it = static_cast<std::size_t>(base + off);
return {};
}
[[nodiscard]]
constexpr auto tellp() const noexcept {
return m_it;
}
constexpr ox::Error put(char val) noexcept {
if (m_it >= m_cap) [[unlikely]] {
return OxError(1, "Buffer overrun");
}
m_buff[m_it] = val;
++m_it;
m_size = ox::max(m_it, m_size);
return {};
}
constexpr ox::Error write(const char *buff, std::size_t cnt) noexcept {
const auto end = m_it + cnt;
if (end > m_cap) [[unlikely]] {
return OxError(1, "Buffer overrun");
}
if (buff) {
for (auto i = 0u; i < cnt; ++i) {
m_buff[m_it + i] = buff[i];
}
}
m_it += cnt;
m_size = ox::max(m_it, m_size);
return {};
}
[[nodiscard]]
constexpr auto data() const noexcept {
return m_buff;
}
};
extern template class WriterT<BufferWriter>;
extern template class WriterT<CharBuffWriter>;
}

View File

@ -11,7 +11,43 @@
#include "typetraits.hpp"
namespace ox {
template<typename T, typename U>
concept CommonPtrWith = ox::is_same_v<typename ox::remove_pointer<const T*>::type,
typename ox::remove_pointer<const U*>::type>;
template<typename T, typename U>
concept same_as = ox::is_same_v<T, T>;
template<std::size_t SmallStringSize>
class BasicString;
template<std::size_t sz>
class BString;
class StringView;
namespace detail {
constexpr auto isOxString(const auto*) noexcept {
return false;
}
template<std::size_t sz>
constexpr auto isOxString(const BasicString<sz>*) noexcept {
return true;
}
template<std::size_t sz>
constexpr auto isOxString(const BString<sz>*) noexcept {
return true;
}
constexpr auto isOxString(const StringView*) noexcept {
return true;
}
}
template<typename T>
concept OxString_c = detail::isOxString(static_cast<T*>(nullptr));
}

View File

@ -75,6 +75,7 @@ constexpr void oxAssert(bool, const char*) noexcept {}
constexpr void oxAssert(const ox::Error&, const char*) noexcept {}
#endif
#define oxExpect(actual, expected) ox::expect(__FILE__, __LINE__, actual, expected)
// Alloca

View File

@ -122,6 +122,8 @@ struct Exception: public std::exception {
}
};
void panic(const char *file, int line, const char *panicMsg, const Error &err) noexcept;
template<typename T>
struct [[nodiscard]] Result {
@ -182,6 +184,19 @@ struct [[nodiscard]] Result {
return error;
}
constexpr auto &unwrap() noexcept {
if (error) {
oxPanic(error, "Failed unwrap");
}
return value;
}
constexpr const auto &unwrap() const noexcept {
if (error) [[unlikely]] {
oxPanic(error, "Failed unwrap");
}
return value;
}
};
namespace detail {

View File

@ -27,60 +27,77 @@
namespace ox {
namespace detail {
constexpr const char *toCString(const char *s) noexcept {
template<bool force = false>
constexpr StringView toStringView(const StringView &s) noexcept {
return s;
}
template<std::size_t size>
constexpr const char *toCString(const BString<size> &s) noexcept {
template<bool force = false>
constexpr StringView toStringView(const char *s) noexcept {
return s;
}
template<bool force = false, std::size_t size>
constexpr StringView toStringView(const BString<size> &s) noexcept {
return s.c_str();
}
template<std::size_t size>
constexpr const char *toCString(const BasicString<size> &s) noexcept {
template<bool force = false, std::size_t size>
constexpr StringView toStringView(const BasicString<size> &s) noexcept {
return s.c_str();
}
#if __has_include(<string>)
template<bool force = false>
#ifdef OX_OS_Darwin
constexpr
#else
inline
#endif
const char *toCString(const std::string &s) noexcept {
StringView toStringView(const std::string &s) noexcept {
return s.c_str();
}
#endif
#if __has_include(<QString>)
inline const char *toCString(const QString &s) noexcept {
template<bool force = false>
inline StringView toStringView(const QString &s) noexcept {
return s.toUtf8();
}
#endif
template<bool force = false>
constexpr StringView toStringView(const auto&) noexcept requires(force) {
return "<unstringable>";
}
class FmtArg {
private:
char dataStr[10] = {};
template<typename T>
static StringView sv(const T &v, char *dataStr) noexcept {
if constexpr(is_bool_v<T>) {
return v ? "true" : "false";
} else if constexpr(is_integer_v<T>) {
return ox_itoa(v, dataStr);
} else {
return toStringView(v);
}
}
public:
const char *out = nullptr;
const StringView out = nullptr;
template<typename T>
constexpr FmtArg(const T &v) noexcept {
if constexpr(is_bool_v<T>) {
out = v ? "true" : "false";
} else if constexpr(is_integer_v<T>) {
out = ox_itoa(v, dataStr);
} else {
out = toCString(v);
}
constexpr FmtArg(const T &v) noexcept: out(sv(v, dataStr)) {
}
};
[[nodiscard]]
constexpr uint64_t argCount(const char *str) noexcept {
constexpr uint64_t argCount(StringView str) noexcept {
uint64_t cnt = 0;
const auto prev = [str](std::size_t i) -> char {
if (i > 0) {
@ -90,13 +107,13 @@ constexpr uint64_t argCount(const char *str) noexcept {
}
};
const auto next = [str](std::size_t i) -> char {
if (i < ox_strlen(str) - 1) {
if (i < str.bytes() - 1) {
return str[i + 1];
} else {
return '\0';
}
};
for (std::size_t i = 0; i < ox_strlen(str); ++i) {
for (std::size_t i = 0; i < str.bytes(); ++i) {
if (str[i] == '{' && prev(i) != '\\' && next(i) == '}') {
++cnt;
}
@ -120,7 +137,7 @@ struct FmtSegment {
template<std::size_t sz>
struct Fmt {
static constexpr std::size_t size = sz;
FmtSegment segments[sz];
ox::Array<FmtSegment, sz> segments;
constexpr bool operator==(const Fmt<sz> &o) const noexcept {
for (std::size_t i = 0; i < sz; ++i) {
@ -134,7 +151,7 @@ struct Fmt {
template<std::size_t segementCnt>
[[nodiscard]]
constexpr Fmt<segementCnt> fmtSegments(const char *fmt) noexcept {
constexpr Fmt<segementCnt> fmtSegments(StringView fmt) noexcept {
Fmt<segementCnt> out;
const auto prev = [fmt](std::size_t i) -> char {
if (i > 0) {
@ -144,18 +161,18 @@ constexpr Fmt<segementCnt> fmtSegments(const char *fmt) noexcept {
}
};
const auto next = [fmt](std::size_t i) -> char {
if (i < ox_strlen(fmt) - 1) {
if (i < fmt.bytes() - 1) {
return fmt[i + 1];
} else {
return '\0';
}
};
auto current = &out.segments[0];
current->str = fmt;
for (std::size_t i = 0; i < ox_strlen(fmt); ++i) {
current->str = fmt.data();
for (std::size_t i = 0; i < fmt.bytes(); ++i) {
if (fmt[i] == '{' && prev(i) != '\\' && next(i) == '}') {
++current;
current->str = fmt + i + 2;
current->str = fmt.data() + i + 2;
current->length = 0;
i += 1;
} else {
@ -169,7 +186,7 @@ constexpr Fmt<segementCnt> fmtSegments(const char *fmt) noexcept {
template<typename StringType = String, typename ...Args>
[[nodiscard]]
constexpr StringType sfmt(const char *fmt, Args... args) noexcept {
constexpr StringType sfmt(StringView fmt, Args... args) noexcept {
assert(ox::detail::argCount(fmt) == sizeof...(args));
StringType out;
const auto fmtSegments = ox::detail::fmtSegments<sizeof...(args)+1>(fmt);

View File

@ -30,8 +30,8 @@ int ox_memcmp(const void *ptr1, const void *ptr2, std::size_t size) noexcept;
constexpr void *ox_memcpy(void *dest, const void *src, std::size_t size) noexcept {
if (std::is_constant_evaluated() || !ox::defines::UseStdLib) {
auto srcBuf = static_cast<const char *>(src);
auto dstBuf = static_cast<char *>(dest);
auto srcBuf = static_cast<const char*>(src);
auto dstBuf = static_cast<char*>(dest);
for (std::size_t i = 0; i < size; ++i) {
dstBuf[i] = static_cast<char>(srcBuf[i]);
}
@ -56,7 +56,7 @@ constexpr void *ox_memmove(void *dest, const void *src, std::size_t size) noexce
constexpr void *ox_memset(void *ptr, int val, std::size_t size) noexcept {
if (std::is_constant_evaluated() || !ox::defines::UseStdLib) {
auto buf = static_cast<uint8_t *>(ptr);
auto buf = static_cast<uint8_t*>(ptr);
for (std::size_t i = 0; i < size; ++i) {
buf[i] = static_cast<uint8_t>(val);
}

View File

@ -282,7 +282,7 @@ constexpr bool operator!=(std::nullptr_t, const UniquePtr<T> &p2) noexcept {
template<typename T, typename ...Args>
[[nodiscard]]
constexpr auto make_unique(Args&&... args) {
return UniquePtr(new T(forward<Args>(args)...));
return UniquePtr(new T(ox::forward<Args>(args)...));
}
}

25
deps/ox/src/ox/std/range.hpp vendored Normal file
View File

@ -0,0 +1,25 @@
/*
* Copyright 2015 - 2022 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
namespace ox {
template<typename T>
class range {
private:
T m_begin = 0;
T m_end = 0;
public:
constexpr range(T begin, T end) noexcept: m_begin(begin), m_end(end) {
}
};
}

81
deps/ox/src/ox/std/serialize.hpp vendored Normal file
View File

@ -0,0 +1,81 @@
/*
* Copyright 2015 - 2022 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "array.hpp"
#include "buffer.hpp"
#include "types.hpp"
#include "typetraits.hpp"
#include "writer.hpp"
namespace ox {
template<typename PlatSpec>
struct VectorMemMap {
const std::size_t smallVecSize = 0; // not a map value
uint8_t allocator = 0;
typename PlatSpec::size_t size = 0;
typename PlatSpec::size_t cap = 0;
typename PlatSpec::PtrType items = 0;
};
template<typename PlatSpec>
[[nodiscard]]
constexpr auto sizeOf(const VectorMemMap<PlatSpec> *t) noexcept {
constexpr auto padding = [](std::size_t size, std::size_t al) {
return size % al;
};
std::size_t size = 0;
if (t->smallVecSize) {
size += t->smallVecSize;
size += padding(size, PlatSpec::alignOf(t->size));
}
size += sizeof(t->size);
size += padding(size, PlatSpec::alignOf(t->cap));
size += sizeof(t->cap);
size += padding(size, PlatSpec::alignOf(t->items));
size += sizeof(t->items);
return size;
}
template<typename PlatSpec, std::size_t SmallVecSize = 0>
[[nodiscard]]
constexpr auto alignOf(const VectorMemMap<PlatSpec>&) noexcept {
const typename PlatSpec::size_t i = 0;
return PlatSpec::alignOf(i);
}
template<typename PlatSpec>
constexpr ox::Error serialize(Writer_c auto *buff, const VectorMemMap<PlatSpec> &vm) noexcept {
oxReturnError(buff->write(nullptr, vm.smallVecSize));
oxReturnError(serialize(buff, PlatSpec::correctEndianness(vm.allocator)));
oxReturnError(serialize(buff, PlatSpec::correctEndianness(vm.size)));
oxReturnError(serialize(buff, PlatSpec::correctEndianness(vm.cap)));
oxReturnError(serialize(buff, PlatSpec::correctEndianness(vm.items)));
return {};
}
template<typename T>
constexpr ox::Error serialize(Writer_c auto *buff, T val) noexcept requires(is_integer_v<T>) {
ox::Array<char, sizeof(T)> tmp;
for (auto i = 0u; i < sizeof(T); ++i) {
tmp[i] = static_cast<char>((val >> i * 8) & 255);
}
return buff->write(tmp.data(), tmp.size());
};
template<typename T>
constexpr ox::Result<ox::Array<char, sizeof(T)>> serialize(const T &in) noexcept {
ox::Array<char, sizeof(T)> out = {};
CharBuffWriter w(&out);
oxReturnError(serialize(&w, in));
return out;
};
}

View File

@ -30,9 +30,11 @@
#include "optional.hpp"
#include "random.hpp"
#include "realstd.hpp"
#include "serialize.hpp"
#include "stacktrace.hpp"
#include "stddef.hpp"
#include "string.hpp"
#include "stringview.hpp"
#include "strongint.hpp"
#include "strops.hpp"
#include "trace.hpp"

View File

@ -12,4 +12,9 @@ namespace ox {
template class BasicString<8>;
static_assert(StringView("Write") != String(""));
static_assert(String("Write") != StringView(""));
static_assert(String("Write") == StringView("Write"));
static_assert(String(StringView("Write")) == StringView("Write"));
}

View File

@ -12,20 +12,24 @@
#include <string>
#endif
#include "algorithm.hpp"
#include "buffer.hpp"
#include "memops.hpp"
#include "serialize.hpp"
#include "stringview.hpp"
#include "strops.hpp"
#include "typetraits.hpp"
#include "vector.hpp"
namespace ox {
template<std::size_t SmallStringSize>
template<std::size_t SmallStringSize_v>
class BasicString {
private:
Vector<char, SmallStringSize> m_buff;
Vector<char, SmallStringSize_v> m_buff;
public:
static constexpr auto SmallStringSize = SmallStringSize_v;
constexpr BasicString() noexcept;
constexpr explicit BasicString(std::size_t cap) noexcept;
@ -36,6 +40,8 @@ class BasicString {
constexpr BasicString(const char *str, std::size_t size) noexcept;
constexpr BasicString(CRStringView str) noexcept;
constexpr BasicString(const BasicString&) noexcept;
constexpr BasicString(BasicString&&) noexcept;
@ -122,6 +128,8 @@ class BasicString {
constexpr BasicString &operator+=(Integer_c auto i) noexcept;
constexpr BasicString &operator+=(StringView src) noexcept;
constexpr BasicString &operator+=(const BasicString &src) noexcept;
constexpr BasicString operator+(const char *str) const noexcept;
@ -136,11 +144,11 @@ class BasicString {
constexpr bool operator==(const char *other) const noexcept;
constexpr bool operator==(const BasicString &other) const noexcept;
constexpr bool operator==(const OxString_c auto &other) const noexcept;
constexpr bool operator!=(const char *other) const noexcept;
constexpr bool operator!=(const BasicString &other) const noexcept;
constexpr bool operator!=(const OxString_c auto &other) const noexcept;
constexpr bool operator<(const BasicString &other) const noexcept;
@ -230,13 +238,15 @@ class BasicString {
template<std::size_t OtherSize>
constexpr void set(const BasicString<OtherSize> &src) noexcept;
constexpr void set(StringView str) noexcept;
constexpr void set(const char *str) noexcept;
constexpr void set(const char8_t *str) noexcept;
};
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize>::BasicString() noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString() noexcept {
if (m_buff.size()) {
m_buff[0] = 0;
} else {
@ -244,16 +254,16 @@ constexpr BasicString<SmallStringSize>::BasicString() noexcept {
}
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize>::BasicString(std::size_t cap) noexcept: m_buff(cap + 1) {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(std::size_t cap) noexcept: m_buff(cap + 1) {
// GCC complains if you don't do this pretty unnecessary size check
if (m_buff.size()) {
m_buff[0] = 0;
}
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize>::BasicString(const char *str) noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(const char *str) noexcept {
if (m_buff.size()) {
m_buff[0] = 0;
} else {
@ -262,8 +272,8 @@ constexpr BasicString<SmallStringSize>::BasicString(const char *str) noexcept {
set(str);
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize>::BasicString(const char8_t *str) noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(const char8_t *str) noexcept {
if (m_buff.size()) {
m_buff[0] = 0;
} else {
@ -272,105 +282,122 @@ constexpr BasicString<SmallStringSize>::BasicString(const char8_t *str) noexcept
set(str);
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize>::BasicString(const char *str, std::size_t size) noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(const char *str, std::size_t size) noexcept {
m_buff.resize(size + 1);
memcpy(m_buff.data(), str, size);
m_buff[size] = 0;
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize>::BasicString(const BasicString &other) noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(CRStringView str) noexcept {
if (m_buff.size()) {
m_buff[0] = 0;
} else {
m_buff.push_back(0);
}
set(str);
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(const BasicString &other) noexcept {
m_buff = other.m_buff;
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize>::BasicString(BasicString &&other) noexcept: m_buff(std::move(other.m_buff)) {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v>::BasicString(BasicString &&other) noexcept: m_buff(std::move(other.m_buff)) {
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> &BasicString<SmallStringSize>::operator=(const char *str) noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(const char *str) noexcept {
set(str);
return *this;
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> &BasicString<SmallStringSize>::operator=(char c) noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(char c) noexcept {
char str[] = {c, 0};
set(str);
return *this;
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> &BasicString<SmallStringSize>::operator=(int i) noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(int i) noexcept {
this->operator=(static_cast<int64_t>(i));
return *this;
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> &BasicString<SmallStringSize>::operator=(int64_t i) noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(int64_t i) noexcept {
char str[65] = {};
ox_itoa(i, str);
set(str);
return *this;
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> &BasicString<SmallStringSize>::operator=(uint64_t i) noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(uint64_t i) noexcept {
char str[65] = {};
ox_itoa(i, str);
set(str);
return *this;
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> &BasicString<SmallStringSize>::operator=(const BasicString &src) noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(const BasicString &src) noexcept {
set(src);
return *this;
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> &BasicString<SmallStringSize>::operator=(BasicString &&src) noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator=(BasicString &&src) noexcept {
m_buff = std::move(src.m_buff);
return *this;
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> &BasicString<SmallStringSize>::operator+=(const char *str) noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(const char *str) noexcept {
std::size_t strLen = ox_strlen(str);
oxIgnoreError(append(str, strLen));
return *this;
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> &BasicString<SmallStringSize>::operator+=(char *str) noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(char *str) noexcept {
return *this += static_cast<const char*>(str);
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> &BasicString<SmallStringSize>::operator+=(char c) noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(char c) noexcept {
const char str[] = {c, 0};
return this->operator+=(str);
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> &BasicString<SmallStringSize>::operator+=(Integer_c auto i) noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(Integer_c auto i) noexcept {
char str[65] = {};
ox_itoa(i, str);
return this->operator+=(str);
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> &BasicString<SmallStringSize>::operator+=(const BasicString &src) noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(StringView s) noexcept {
std::size_t strLen = s.bytes();
oxIgnoreError(append(s.data(), strLen));
return *this;
}
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> &BasicString<SmallStringSize_v>::operator+=(const BasicString &src) noexcept {
oxIgnoreError(append(src.c_str(), src.len()));
return *this;
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> BasicString<SmallStringSize>::operator+(const char *str) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(const char *str) const noexcept {
const std::size_t strLen = ox_strlen(str);
const auto currentLen = len();
BasicString<SmallStringSize> cpy(currentLen + strLen);
BasicString<SmallStringSize_v> cpy(currentLen + strLen);
cpy.m_buff.resize(m_buff.size() + strLen);
memcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
memcpy(&cpy.m_buff[currentLen], str, strLen);
@ -379,37 +406,37 @@ constexpr BasicString<SmallStringSize> BasicString<SmallStringSize>::operator+(c
return cpy;
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> BasicString<SmallStringSize>::operator+(char *str) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(char *str) const noexcept {
return *this + static_cast<const char*>(str);
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> BasicString<SmallStringSize>::operator+(char c) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(char c) const noexcept {
const char str[] = {c, 0};
return *this + str;
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> BasicString<SmallStringSize>::operator+(Integer_c auto i) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(Integer_c auto i) const noexcept {
char str[65] = {};
ox_itoa(i, str);
return *this + str;
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> BasicString<SmallStringSize>::operator+(const BasicString &src) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::operator+(const BasicString &src) const noexcept {
const std::size_t strLen = src.len();
const auto currentLen = len();
BasicString<SmallStringSize> cpy(currentLen + strLen);
BasicString<SmallStringSize_v> cpy(currentLen + strLen);
cpy.m_buff.resize(m_buff.size() + strLen);
memcpy(&cpy.m_buff[0], m_buff.data(), currentLen);
memcpy(&cpy.m_buff[currentLen], src.data(), strLen + 1);
return cpy;
}
template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::operator==(const char *other) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator==(const char *other) const noexcept {
bool retval = true;
for (auto i = 0u; i < m_buff.size() && (m_buff[i] || other[i]); ++i) {
if (m_buff[i] != other[i]) {
@ -420,15 +447,15 @@ constexpr bool BasicString<SmallStringSize>::operator==(const char *other) const
return retval;
}
template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::operator==(const BasicString &other) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator==(const OxString_c auto &other) const noexcept {
if (len() != other.len()) {
return false;
}
bool retval = true;
std::size_t i = 0;
while (i < m_buff.size() && (m_buff[i] || other.m_buff[i])) {
if (m_buff[i] != other.m_buff[i]) {
while (i < m_buff.size() && (m_buff[i] || other[i])) {
if (m_buff[i] != other[i]) {
retval = false;
break;
}
@ -437,95 +464,95 @@ constexpr bool BasicString<SmallStringSize>::operator==(const BasicString &other
return retval;
}
template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::operator!=(const char *other) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator!=(const char *other) const noexcept {
return !operator==(other);
}
template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::operator!=(const BasicString &other) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator!=(const OxString_c auto &other) const noexcept {
return !operator==(other);
}
template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::operator<(const BasicString &other) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator<(const BasicString &other) const noexcept {
return ox_strcmp(c_str(), other.c_str()) < 0;
}
template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::operator>(const BasicString &other) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator>(const BasicString &other) const noexcept {
return ox_strcmp(c_str(), other.c_str()) > 0;
}
template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::operator<=(const BasicString &other) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator<=(const BasicString &other) const noexcept {
return ox_strcmp(c_str(), other.c_str()) < 1;
}
template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::operator>=(const BasicString &other) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::operator>=(const BasicString &other) const noexcept {
return ox_strcmp(c_str(), other.c_str()) > -1;
}
template<std::size_t SmallStringSize>
constexpr char BasicString<SmallStringSize>::operator[](std::size_t i) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr char BasicString<SmallStringSize_v>::operator[](std::size_t i) const noexcept {
return m_buff[i];
}
template<std::size_t SmallStringSize>
constexpr char &BasicString<SmallStringSize>::operator[](std::size_t i) noexcept {
template<std::size_t SmallStringSize_v>
constexpr char &BasicString<SmallStringSize_v>::operator[](std::size_t i) noexcept {
return m_buff[i];
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> BasicString<SmallStringSize>::substr(std::size_t pos) const noexcept {
return m_buff.data() + pos;
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::substr(std::size_t pos) const noexcept {
return BasicString(m_buff.data() + pos, m_buff.size() - pos);
}
template<std::size_t SmallStringSize>
constexpr BasicString<SmallStringSize> BasicString<SmallStringSize>::substr(std::size_t begin, std::size_t end) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr BasicString<SmallStringSize_v> BasicString<SmallStringSize_v>::substr(std::size_t begin, std::size_t end) const noexcept {
const auto src = m_buff.data() + begin;
const auto size = end - begin;
BasicString<SmallStringSize> out(size);
BasicString<SmallStringSize_v> out(size);
const auto buff = out.data();
memcpy(buff, src, size);
buff[size] = 0;
return out;
}
template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::beginsWith(const char *beginning) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::beginsWith(const char *beginning) const noexcept {
const auto beginningLen = ox::min(ox_strlen(beginning), len());
return ox_strncmp(data(), beginning, beginningLen) == 0;
}
template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::beginsWith(const BasicString &beginning) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::beginsWith(const BasicString &beginning) const noexcept {
const auto sz = ox::min(beginning.len(), len());;
return ox_strncmp(data(), beginning.c_str(), sz) == 0;
}
template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::endsWith(const char *ending) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::endsWith(const char *ending) const noexcept {
const auto endingLen = ox_strlen(ending);
return len() >= endingLen && ox_strcmp(data() + (len() - endingLen), ending) == 0;
}
template<std::size_t SmallStringSize>
constexpr bool BasicString<SmallStringSize>::endsWith(const BasicString &ending) const noexcept {
template<std::size_t SmallStringSize_v>
constexpr bool BasicString<SmallStringSize_v>::endsWith(const BasicString &ending) const noexcept {
const auto endingLen = ending.len();
return len() >= endingLen && ox_strcmp(data() + (len() - endingLen), ending.c_str()) == 0;
}
template<std::size_t SmallStringSize>
constexpr std::size_t BasicString<SmallStringSize>::bytes() const noexcept {
template<std::size_t SmallStringSize_v>
constexpr std::size_t BasicString<SmallStringSize_v>::bytes() const noexcept {
std::size_t i;
for (i = 0; i < m_buff.size() && m_buff[i]; i++);
return i + 1; // add one for null terminator
}
template<std::size_t SmallStringSize>
constexpr std::size_t BasicString<SmallStringSize>::len() const noexcept {
template<std::size_t SmallStringSize_v>
constexpr std::size_t BasicString<SmallStringSize_v>::len() const noexcept {
std::size_t length = 0;
for (const auto c : m_buff) {
auto b = static_cast<uint8_t>(c);
@ -542,29 +569,39 @@ constexpr std::size_t BasicString<SmallStringSize>::len() const noexcept {
return length;
}
template<std::size_t SmallStringSize>
template<std::size_t SmallStringSize_v>
template<std::size_t OtherSize>
constexpr void BasicString<SmallStringSize>::set(const BasicString<OtherSize> &src) noexcept {
constexpr void BasicString<SmallStringSize_v>::set(const BasicString<OtherSize> &src) noexcept {
std::size_t strBytes = src.bytes();
if (strBytes > 1) {
m_buff.resize(strBytes);
memcpy(m_buff.data(), src.data(), strBytes);
copy_n(src.begin(), strBytes, m_buff.data());
m_buff.back().value = 0;
}
}
template<std::size_t SmallStringSize>
constexpr void BasicString<SmallStringSize>::set(const char *str) noexcept {
template<std::size_t SmallStringSize_v>
constexpr void BasicString<SmallStringSize_v>::set(StringView str) noexcept {
std::size_t strBytes = str.bytes();
if (strBytes > 1) {
m_buff.resize(strBytes + 1);
copy_n(str.data(), strBytes, m_buff.data());
m_buff.back().value = 0;
}
}
template<std::size_t SmallStringSize_v>
constexpr void BasicString<SmallStringSize_v>::set(const char *str) noexcept {
std::size_t strBytes = ox_strlen(str) + 1;
if (strBytes > 1) {
m_buff.resize(strBytes);
memcpy(m_buff.data(), str, strBytes);
copy_n(str, strBytes, m_buff.data());
m_buff.back().value = 0;
}
}
template<std::size_t SmallStringSize>
constexpr void BasicString<SmallStringSize>::set(const char8_t *str) noexcept {
template<std::size_t SmallStringSize_v>
constexpr void BasicString<SmallStringSize_v>::set(const char8_t *str) noexcept {
std::size_t strBytes = ox_strlen(str) + 1;
if (strBytes > 1) {
m_buff.resize(strBytes);
@ -576,5 +613,20 @@ constexpr void BasicString<SmallStringSize>::set(const char8_t *str) noexcept {
extern template class BasicString<8>;
using String = BasicString<8>;
using CRString = String const&;
template<typename PlatSpec, std::size_t SmallStringSize_v>
[[nodiscard]]
constexpr auto sizeOf(const ox::BasicString<SmallStringSize_v>*) noexcept {
VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v};
return sizeOf<PlatSpec>(&v);
}
template<typename PlatSpec, std::size_t SmallStringSize_v>
[[nodiscard]]
constexpr auto alignOf(const ox::BasicString<SmallStringSize_v>&) noexcept {
VectorMemMap<PlatSpec> v{.smallVecSize = SmallStringSize_v};
return alignOf<PlatSpec>(&v);
}
}

123
deps/ox/src/ox/std/stringview.hpp vendored Normal file
View File

@ -0,0 +1,123 @@
/*
* Copyright 2015 - 2022 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at https://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "strops.hpp"
#include "types.hpp"
namespace ox {
template<std::size_t buffLen>
class BString;
template<std::size_t buffLen>
class BasicString;
class StringView {
private:
const char *m_str = nullptr;
std::size_t m_len = 0;
public:
constexpr StringView() noexcept = default;
constexpr StringView(const StringView &sv) noexcept: m_str(sv.m_str), m_len(sv.m_len) {
}
template<std::size_t SmallStrSz>
constexpr StringView(const BasicString<SmallStrSz> &str) noexcept: m_str(str.c_str()), m_len(str.len()) {}
template<std::size_t SmallStrSz>
constexpr StringView(const BString<SmallStrSz> &str) noexcept: m_str(str.c_str()), m_len(str.len()) {}
constexpr StringView(std::nullptr_t) noexcept {}
constexpr StringView(const char *str) noexcept: m_str(str), m_len(str ? ox_strlen(str) : 0) {}
constexpr StringView(const char *str, std::size_t len) noexcept: m_str(str), m_len(len) {}
[[nodiscard]]
constexpr auto bytes() const noexcept {
return m_len;
}
[[nodiscard]]
constexpr auto len() const noexcept {
return m_len;
}
[[nodiscard]]
constexpr auto *data() const noexcept {
return &m_str[0];
}
[[nodiscard]]
constexpr auto &front() const noexcept {
return m_str[0];
}
[[nodiscard]]
constexpr auto &back() const noexcept {
return m_str[m_len - 1];
}
constexpr auto operator[](std::size_t i) const noexcept {
return m_str[i];
}
constexpr auto operator=(const StringView &other) noexcept {
m_str = other.m_str;
m_len = other.m_len;
return *this;
}
constexpr auto operator==(const StringView &other) const noexcept {
if (other.len() != len()) {
return false;
}
return ox_strncmp(m_str, other.m_str, len()) == 0;
}
constexpr auto operator<=>(const StringView &str2) const noexcept {
const StringView &str1 = *this;
const auto maxLen = ox::min(str1.len(), str2.len());
const auto a = &str1.front();
const auto b = &str2.front();
for (std::size_t i = 0; i < maxLen && (a[i] || b[i]); ++i) {
if (a[i] < b[i]) {
return -1;
} else if (a[i] > b[i]) {
return 1;
}
}
if (str1.len() > str2.len()) {
return 1;
} else if (str1.len() < str2.len()) {
return -1;
} else {
return 0;
}
}
};
using CRStringView = const StringView&;
static_assert(StringView("Read").bytes() == 4);
static_assert(StringView("Read") == StringView("Read"));
static_assert(StringView("Read") != StringView("Write"));
static_assert(StringView("Write") != StringView("Read"));
static_assert(StringView("Write") != StringView(""));
static_assert(StringView("") != StringView("Read"));
static_assert(StringView("") == StringView(""));
static_assert(StringView("") == "");
static_assert("Read" == StringView("Read"));
static_assert(StringView("Read") == StringView("Read"));
}

View File

@ -13,16 +13,9 @@
namespace ox {
struct BaseInteger {
constexpr BaseInteger() noexcept = default;
constexpr BaseInteger(const BaseInteger&) noexcept {
}
constexpr BaseInteger operator=(const BaseInteger&) noexcept {
return *this;
}
constexpr BaseInteger(const BaseInteger&) noexcept = default;
constexpr BaseInteger &operator=(const BaseInteger&) noexcept = default;
};
/**

View File

@ -16,3 +16,5 @@ add_test("[ox/std] String" StdTest "String")
add_test("[ox/std] Vector" StdTest "Vector")
add_test("[ox/std] HashMap" StdTest "HashMap")
add_test("[ox/std] HeapMgr" StdTest malloc)
add_test("[ox/std] Serialize-Int" StdTest "Serialize-Int")
add_test("[ox/std] BufferWriter" StdTest "BufferWriter")

View File

@ -11,7 +11,7 @@
#include <map>
#include <ox/std/std.hpp>
std::map<ox::String, ox::Error(*)()> tests = {
static std::map<ox::String, ox::Error(*)()> tests = {
{
"malloc",
[] {
@ -122,6 +122,39 @@ std::map<ox::String, ox::Error(*)()> tests = {
return OxError(0);
}
},
{
"Serialize-Int",
[] {
using BA = ox::Array<char, 4>;
const auto actual = ox::serialize<uint32_t>(256).unwrap();
oxOutf("[{}, {}, {}, {}]", static_cast<int>(actual[0]), static_cast<int>(actual[1]), static_cast<int>(actual[2]), static_cast<int>(actual[3]));
oxExpect(ox::serialize<int32_t>(4).unwrap(), BA({4, 0, 0, 0}));
oxExpect(ox::serialize<int32_t>(256).unwrap(), BA({0, 1, 0, 0}));
oxExpect(ox::serialize<int32_t>(257).unwrap(), BA({1, 1, 0, 0}));
oxExpect(ox::serialize<uint32_t>(4).unwrap(), BA({4, 0, 0, 0}));
oxExpect(ox::serialize<uint32_t>(256).unwrap(), BA({0, 1, 0, 0}));
oxExpect(ox::serialize<uint32_t>(257).unwrap(), BA({1, 1, 0, 0}));
oxExpect(ox::serialize<uint32_t>(0xffff'ffff).unwrap(), BA({-1, -1, -1, -1}));
return OxError(0);
}
},
{
"BufferWriter",
[] {
ox::Buffer b;
ox::BufferWriter w(&b);
oxAssert(w.write("asdf", 4), "write failed");
oxExpect(b.size(), 4u);
oxAssert(w.write("aoeu", 4), "write failed");
oxExpect(b.size(), 8u);
oxExpect(ox::StringView(b.data(), b.size()), "asdfaoeu");
ox::StringView qwerty = "qwerty";
oxAssert(w.write(qwerty.data(), qwerty.bytes()), "write failed");
oxExpect(b.size(), 14u);
oxExpect(ox::StringView(b.data(), b.size()), "asdfaoeuqwerty");
return OxError(0);
}
},
};
int main(int argc, const char **args) {

View File

@ -73,6 +73,14 @@ template<> struct is_integral<int16_t> : true_type {};
template<> struct is_integral<uint16_t>: true_type {};
template<> struct is_integral<int32_t> : true_type {};
template<> struct is_integral<uint32_t>: true_type {};
template<> struct is_integral<const bool> : true_type {};
template<> struct is_integral<const wchar_t> : true_type {};
template<> struct is_integral<const int8_t> : true_type {};
template<> struct is_integral<const uint8_t> : true_type {};
template<> struct is_integral<const int16_t> : true_type {};
template<> struct is_integral<const uint16_t>: true_type {};
template<> struct is_integral<const int32_t> : true_type {};
template<> struct is_integral<const uint32_t>: true_type {};
// some of these need to be done with the actual language syntax because no one
// can agree on what an (u)int64_t is...
@ -80,6 +88,10 @@ template<> struct is_integral<long>: true_type {};
template<> struct is_integral<long long>: true_type {};
template<> struct is_integral<unsigned long>: true_type {};
template<> struct is_integral<unsigned long long>: true_type {};
template<> struct is_integral<const long>: true_type {};
template<> struct is_integral<const long long>: true_type {};
template<> struct is_integral<const unsigned long>: true_type {};
template<> struct is_integral<const unsigned long long>: true_type {};
template<typename T>
constexpr bool is_integral_v = is_integral<T>::value;
@ -184,6 +196,11 @@ struct is_pointer<T*> {
static constexpr bool value = true;
};
template<typename T>
struct is_pointer<const T*> {
static constexpr bool value = true;
};
template<typename T>
constexpr bool is_pointer_v = is_pointer<T>::value;

View File

@ -22,38 +22,6 @@
namespace ox {
template<typename PlatSpec>
struct VectorMemMap {
typename PlatSpec::size_t size = 0;
typename PlatSpec::size_t cap = 0;
typename PlatSpec::PtrType items = 0;
uint8_t allocator = 0;
};
template<typename PlatSpec>
[[nodiscard]]
constexpr auto sizeOf(const VectorMemMap<PlatSpec> &t) noexcept {
constexpr auto padding = [](std::size_t size, std::size_t al) {
return size - size % al;
};
std::size_t size = 0;
size += sizeof(t.size);
size += padding(size, PlatSpec::alignOf(t.cap));
size += sizeof(t.cap);
size += padding(size, PlatSpec::alignOf(t.items));
size += sizeof(t.items);
size += padding(size, PlatSpec::alignOf(t.allocator));
size += sizeof(t.allocator);
return size;
}
template<typename PlatSpec>
[[nodiscard]]
constexpr auto alignOf(const VectorMemMap<PlatSpec>&) noexcept {
const typename PlatSpec::size_t i = 0;
return PlatSpec::alignOf(i);
}
namespace detail {
template<typename T, typename Allocator, std::size_t Size = 1>
@ -75,12 +43,12 @@ struct VectorAllocator {
}
}
constexpr void moveConstructItemsFrom(T **items, VectorAllocator &src, const std::size_t count, const std::size_t cap) noexcept {
constexpr void moveConstructItemsFrom(T **items, VectorAllocator *src, const std::size_t count, const std::size_t cap) noexcept {
// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
// try removing it later
if (cap <= Size && count <= Size) {
const auto dstItems = reinterpret_cast<T*>(m_data.data());
const auto srcItems = reinterpret_cast<T*>(src.m_data.data());
const auto srcItems = reinterpret_cast<T*>(src->m_data.data());
for (auto i = 0u; i < count; ++i) {
std::construct_at<T>(&dstItems[i], std::move(srcItems[i]));
}
@ -88,12 +56,12 @@ struct VectorAllocator {
}
}
constexpr void moveItemsFrom(T **items, VectorAllocator &src, const std::size_t count, const std::size_t cap) noexcept {
constexpr void moveItemsFrom(T **items, VectorAllocator *src, const std::size_t count, const std::size_t cap) noexcept {
// this totally idiotic redundant check (&& count <= Size) is required to address a bug in devkitARM,
// try removing it later
if (cap <= Size && count <= Size) {
const auto dstItems = reinterpret_cast<T*>(m_data.data());
const auto srcItems = reinterpret_cast<T*>(src.m_data.data());
const auto srcItems = reinterpret_cast<T*>(src->m_data.data());
for (std::size_t i = 0; i < count; ++i) {
dstItems[i] = std::move(srcItems[i]);
}
@ -124,11 +92,11 @@ struct VectorAllocator<T, Allocator, 0> {
}
[[maybe_unused]]
constexpr void moveConstructItemsFrom(T**, VectorAllocator&, const std::size_t, const std::size_t) noexcept {
constexpr void moveConstructItemsFrom(T**, VectorAllocator*, const std::size_t, const std::size_t) noexcept {
}
[[maybe_unused]]
constexpr void moveItemsFrom(T**, VectorAllocator&, const std::size_t, const std::size_t) noexcept {
constexpr void moveItemsFrom(T**, VectorAllocator*, const std::size_t, const std::size_t) noexcept {
}
constexpr void deallocate(T *items, std::size_t cap) noexcept {
@ -142,7 +110,7 @@ struct VectorAllocator<T, Allocator, 0> {
}
template<typename T, std::size_t SmallVectorSize = 0, typename Allocator = std::allocator<T>>
class Vector {
class Vector: detail::VectorAllocator<T, Allocator, SmallVectorSize> {
public:
using value_type = T;
@ -257,7 +225,6 @@ class Vector {
std::size_t m_size = 0;
std::size_t m_cap = 0;
T *m_items = nullptr;
detail::VectorAllocator<T, Allocator, SmallVectorSize> m_allocator;
public:
constexpr Vector() noexcept = default;
@ -408,8 +375,7 @@ class Vector {
*/
constexpr Error unordered_erase(std::size_t pos);
private:
constexpr void expandCap(std::size_t cap);
constexpr void reserve(std::size_t cap);
};
@ -425,7 +391,7 @@ template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(std::size_t size) noexcept {
m_size = size;
m_cap = m_size;
m_allocator.allocate(&m_items, m_cap);
this->allocate(&m_items, m_cap);
for (std::size_t i = 0; i < size; ++i) {
std::construct_at(&m_items[i]);
}
@ -442,7 +408,7 @@ template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::Vector(const Vector &other) {
m_size = other.m_size;
m_cap = other.m_cap;
m_allocator.allocate(&m_items, other.m_cap);
this->allocate(&m_items, other.m_cap);
for (std::size_t i = 0; i < m_size; ++i) {
std::construct_at(&m_items[i], other.m_items[i]);
}
@ -453,7 +419,7 @@ constexpr Vector<T, SmallVectorSize, Allocator>::Vector(Vector &&other) noexcept
m_size = other.m_size;
m_cap = other.m_cap;
m_items = other.m_items;
m_allocator.moveConstructItemsFrom(&m_items, other.m_allocator, m_size, m_cap);
this->moveConstructItemsFrom(&m_items, &other, m_size, m_cap);
other.m_size = 0;
other.m_cap = 0;
other.m_items = nullptr;
@ -462,7 +428,7 @@ constexpr Vector<T, SmallVectorSize, Allocator>::Vector(Vector &&other) noexcept
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator>::~Vector() {
clear();
m_allocator.deallocate(m_items, m_cap);
this->deallocate(m_items, m_cap);
m_items = nullptr;
}
@ -483,11 +449,11 @@ template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allocator>::operator=(const Vector &other) {
if (this != &other) {
clear();
m_allocator.deallocate(m_items, m_cap);
this->deallocate(m_items, m_cap);
m_items = nullptr;
m_size = other.m_size;
m_cap = other.m_cap;
m_allocator.allocate(&m_items, other.m_cap);
this->allocate(&m_items, other.m_cap);
for (std::size_t i = 0; i < m_size; i++) {
std::construct_at(&m_items[i], other.m_items[i]);
}
@ -499,11 +465,11 @@ template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr Vector<T, SmallVectorSize, Allocator> &Vector<T, SmallVectorSize, Allocator>::operator=(Vector &&other) noexcept {
if (this != &other) {
clear();
m_allocator.deallocate(m_items, m_cap);
this->deallocate(m_items, m_cap);
m_size = other.m_size;
m_cap = other.m_cap;
m_items = other.m_items;
m_allocator.moveItemsFrom(&m_items, other.m_allocator, m_size, m_cap);
this->moveItemsFrom(&m_items, &other, m_size, m_cap);
other.m_size = 0;
other.m_cap = 0;
other.m_items = nullptr;
@ -580,7 +546,7 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::clear() {
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::resize(std::size_t size) {
if (m_cap < size) {
expandCap(size);
reserve(size * 2);
}
if (m_size < size) {
for (std::size_t i = m_size; i < size; i++) {
@ -606,9 +572,9 @@ constexpr bool Vector<T, SmallVectorSize, Allocator>::contains(const T &v) const
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::insert(std::size_t pos, std::size_t cnt, const T &val) {
// TODO: insert should ideally have its own expandCap
// TODO: insert should ideally have its own reserve
if (m_size + cnt > m_cap) {
expandCap(m_cap ? m_size + cnt : initialSize);
reserve(m_cap ? m_size + cnt : initialSize);
}
if (pos < m_size) {
for (auto i = m_size + cnt - 1; i > pos; --i) {
@ -625,9 +591,9 @@ constexpr void Vector<T, SmallVectorSize, Allocator>::insert(std::size_t pos, st
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::insert(std::size_t pos, const T &val) {
// TODO: insert should ideally have its own expandCap
// TODO: insert should ideally have its own reserve
if (m_size == m_cap) {
expandCap(m_cap ? m_cap * 2 : initialSize);
reserve(m_cap ? m_cap * 2 : initialSize);
}
if (pos < m_size) {
for (auto i = m_size; i > pos; --i) {
@ -644,7 +610,7 @@ template<typename T, std::size_t SmallVectorSize, typename Allocator>
template<typename... Args>
constexpr T &Vector<T, SmallVectorSize, Allocator>::emplace_back(Args&&... args) {
if (m_size == m_cap) {
expandCap(m_cap ? m_cap * 2 : initialSize);
reserve(m_cap ? m_cap * 2 : initialSize);
}
auto out = std::construct_at(&m_items[m_size], ox::forward<Args>(args)...);
++m_size;
@ -654,7 +620,7 @@ constexpr T &Vector<T, SmallVectorSize, Allocator>::emplace_back(Args&&... args)
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::push_back(const T &item) {
if (m_size == m_cap) {
expandCap(m_cap ? m_cap * 2 : initialSize);
reserve(m_cap ? m_cap * 2 : initialSize);
}
std::construct_at(&m_items[m_size], item);
++m_size;
@ -696,18 +662,21 @@ constexpr Error Vector<T, SmallVectorSize, Allocator>::unordered_erase(std::size
}
template<typename T, std::size_t SmallVectorSize, typename Allocator>
constexpr void Vector<T, SmallVectorSize, Allocator>::expandCap(std::size_t cap) {
constexpr void Vector<T, SmallVectorSize, Allocator>::reserve(std::size_t cap) {
if (cap <= m_cap) {
return;
}
const auto oldItems = m_items;
const auto oldCap = m_cap;
m_cap = cap;
m_allocator.allocate(&m_items, cap);
this->allocate(&m_items, cap);
if (oldItems) { // move over old items
const auto itRange = ox::min(cap, m_size);
for (std::size_t i = 0; i < itRange; ++i) {
std::construct_at(&m_items[i], std::move(oldItems[i]));
oldItems[i].~T();
}
m_allocator.deallocate(oldItems, oldCap);
this->deallocate(oldItems, oldCap);
}
}

78
deps/ox/src/ox/std/writer.hpp vendored Normal file
View File

@ -0,0 +1,78 @@
/*
* Copyright 2015 - 2022 gary@drinkingtea.net
*
* This Source Code Form is subject to the terms of the Mozilla Public
* License, v. 2.0. If a copy of the MPL was not distributed with this
* file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/
#pragma once
#include "concepts.hpp"
#include "error.hpp"
#include "types.hpp"
namespace ox {
namespace ios_base {
enum seekdir {
beg,
end,
cur,
};
}
template<typename T>
concept Writer_c = requires(T v) {
{v.put(static_cast<char>(0))} -> ox::same_as<ox::Error>;
{v.write(static_cast<const char*>(""), static_cast<std::size_t>(0))} -> ox::same_as<ox::Error>;
{v.seekp(static_cast<std::size_t>(0))} -> ox::same_as<ox::Error>;
{v.seekp(static_cast<std::size_t>(0), ios_base::beg)} -> ox::same_as<ox::Error>;
{v.tellp()} -> ox::same_as<std::size_t>;
};
class Writer_v {
public:
virtual constexpr ~Writer_v() noexcept = default;
virtual constexpr auto put(char) noexcept -> ox::Error = 0;
virtual constexpr auto write(const char*, std::size_t) noexcept -> ox::Error = 0;
virtual constexpr auto seekp(std::size_t) noexcept -> ox::Error = 0;
virtual constexpr auto seekp(int, ios_base::seekdir) -> ox::Error = 0;
virtual constexpr auto tellp() noexcept -> std::size_t = 0;
};
template<Writer_c T>
class WriterT: public Writer_v {
private:
T m_writer{};
public:
template<typename ...Args>
constexpr explicit WriterT(Args&&... args) noexcept: m_writer(args...) {
}
constexpr auto put(char v) noexcept -> ox::Error override {
return m_writer.put(v);
}
constexpr auto write(const char *v, std::size_t cnt) noexcept -> ox::Error override {
return m_writer.write(v, cnt);
}
constexpr auto seekp(std::size_t p) noexcept -> ox::Error override {
return m_writer.seekp(p);
}
constexpr auto seekp(int p, ios_base::seekdir sd) noexcept -> ox::Error override {
return m_writer.seekp(p, sd);
}
constexpr auto tellp() noexcept -> std::size_t override {
return m_writer.tellp();
}
};
constexpr ox::Result<std::size_t> allocate(Writer_c auto *writer, std::size_t sz) noexcept {
const auto p = writer->tellp();
oxReturnError(writer->seekp(0, ios_base::end));
const auto out = writer->tellp();
oxReturnError(writer->write(nullptr, sz));
oxReturnError(writer->seekp(p));
return out;
}
}