[ox/mc] Fix build issues encountered when using MetalClawDefWriter

This commit is contained in:
Gary Talent 2019-02-28 23:11:27 -06:00
parent 652b603ec6
commit 21f5a34b75
7 changed files with 120 additions and 115 deletions

View File

@ -1,5 +1,7 @@
add_library( add_library(
OxMetalClaw OxMetalClaw
defread.cpp
deftypes.cpp
defwriter.cpp defwriter.cpp
presencemask.cpp presencemask.cpp
read.cpp read.cpp
@ -20,6 +22,7 @@ set_property(
install( install(
FILES FILES
defread.hpp
deftypes.hpp deftypes.hpp
defwriter.hpp defwriter.hpp
err.hpp err.hpp
@ -27,7 +30,7 @@ install(
presencemask.hpp presencemask.hpp
read.hpp read.hpp
types.hpp types.hpp
walker.cpp walker.hpp
write.hpp write.hpp
DESTINATION DESTINATION
include/ox/mc include/ox/mc

View File

@ -15,6 +15,8 @@
namespace ox::mc { namespace ox::mc {
using String = BString<100>; using String = BString<100>;
using FieldName = String;
using TypeName = String;
enum class PrimitiveType: uint8_t { enum class PrimitiveType: uint8_t {
UnsignedInteger = 0, UnsignedInteger = 0,
@ -25,8 +27,6 @@ enum class PrimitiveType: uint8_t {
Struct = 5, Struct = 5,
}; };
using FieldName = String;
struct Field { struct Field {
// order of fields matters // order of fields matters
@ -36,28 +36,29 @@ struct Field {
int subscriptLevels = 0; int subscriptLevels = 0;
// do not serialize the following // do not serialize the following
String typeName; // gives reference to type for lookup if type is null TypeName typeName; // gives reference to type for lookup if type is null
bool serializeType = false; bool ownsType = false;
~Field();
}; };
using FieldList = Vector<Field>; using FieldList = Vector<Field>;
using TypeName = String;
struct Type { struct Type {
TypeName typeName; TypeName typeName;
PrimitiveType primitiveType; PrimitiveType primitiveType;
// fieldList only applies to structs // fieldList only applies to structs
Vector<Field> fieldList; FieldList fieldList;
// - number of bytes for integer and float types // - number of bytes for integer and float types
// - number of fields for structs and lists // - number of fields for structs and lists
int64_t length = 0; int64_t length = 0;
Type() = default; Type() = default;
Type(String tn, PrimitiveType t, int b): typeName(tn), primitiveType(t), length(b) { Type(TypeName tn, PrimitiveType t, int b): typeName(tn), primitiveType(t), length(b) {
} }
Type(String tn, PrimitiveType t, FieldList fl): typeName(tn), primitiveType(t), fieldList(fl) { Type(TypeName tn, PrimitiveType t, FieldList fl): typeName(tn), primitiveType(t), fieldList(fl) {
} }
}; };
@ -77,7 +78,7 @@ template<typename T>
int ioOpWrite(T *io, Field *field) { int ioOpWrite(T *io, Field *field) {
int32_t err = 0; int32_t err = 0;
io->setTypeInfo("ox::mc::Field", 4); io->setTypeInfo("ox::mc::Field", 4);
if (field->serializeType) { if (field->ownsType) {
err |= io->op("typeName", ""); err |= io->op("typeName", "");
err |= io->op("type", field->type); err |= io->op("type", field->type);
} else { } else {
@ -93,18 +94,21 @@ int ioOpWrite(T *io, Field *field) {
template<typename T> template<typename T>
int ioOpRead(T *io, Field *field) { int ioOpRead(T *io, Field *field) {
int32_t err = 0; int32_t err = 0;
auto &typeStore = io->typeStore();
io->setTypeInfo("ox::mc::Field", 4); io->setTypeInfo("ox::mc::Field", 4);
err |= io->op("typeName", &field->typeName); err |= io->op("typeName", &field->typeName);
if (field->typeName == "") { if (field->typeName == "") {
field->serializeType = true; field->ownsType = true;
if (field->type == nullptr) { if (field->type == nullptr) {
field->type = new Type; field->type = new Type;
} }
err |= io->op("type", field->type); err |= io->op("type", field->type);
typeStore[field->type->typeName] = field->type;
} else { } else {
// should be empty, so discard // should be empty, so discard
Type t; Type t;
err |= io->op("type", &t); err |= io->op("type", &t);
field->type = typeStore[field->typeName];
} }
err |= io->op("fieldName", &field->fieldName); err |= io->op("fieldName", &field->fieldName);
// defaultValue is unused now, but placeholder for backwards compatibility // defaultValue is unused now, but placeholder for backwards compatibility

View File

@ -12,6 +12,27 @@
namespace ox { namespace ox {
static_assert([] {
int i = 0;
return indirectionLevels(i) == 0;
}(), "indirectionLevels broken: indirectionLevels(int)");
static_assert([] {
int i = 0;
return indirectionLevels(&i) == 1;
}(), "indirectionLevels broken: indirectionLevels(int*)");
static_assert([] {
int i[2] = {};
return indirectionLevels(i) == 1;
}(), "indirectionLevels broken: indirectionLevels(int[])");
static_assert([] {
int i[2][2] = {{}};
return indirectionLevels(i) == 2;
}(), "indirectionLevels broken: indirectionLevels(int[][])");
MetalClawDefWriter::MetalClawDefWriter(mc::TypeStore *typeStore) { MetalClawDefWriter::MetalClawDefWriter(mc::TypeStore *typeStore) {
if (!typeStore) { if (!typeStore) {
m_typeStoreOwnerRef = new mc::TypeStore; m_typeStoreOwnerRef = new mc::TypeStore;
@ -21,86 +42,87 @@ MetalClawDefWriter::MetalClawDefWriter(mc::TypeStore *typeStore) {
} }
MetalClawDefWriter::~MetalClawDefWriter() { MetalClawDefWriter::~MetalClawDefWriter() {
// does not own it's elements
delete m_typeStoreOwnerRef; delete m_typeStoreOwnerRef;
} }
constexpr mc::Type *MetalClawDefWriter::type(int8_t*, bool *alreadyExisted) { mc::Type *MetalClawDefWriter::type(int8_t*, bool *alreadyExisted) {
constexpr auto TypeName = "B:int8_t"; constexpr auto TypeName = "B:int8_t";
constexpr auto PT = mc::PrimitiveType::SignedInteger; constexpr auto PT = mc::PrimitiveType::SignedInteger;
constexpr auto Bytes = 8; constexpr auto Bytes = 8;
return getPrimitive(TypeName, PT, Bytes, alreadyExisted); return getType(TypeName, PT, Bytes, alreadyExisted);
} }
constexpr mc::Type *MetalClawDefWriter::type(int16_t*, bool *alreadyExisted) { mc::Type *MetalClawDefWriter::type(int16_t*, bool *alreadyExisted) {
constexpr auto TypeName = "B:int16_t"; constexpr auto TypeName = "B:int16_t";
constexpr auto PT = mc::PrimitiveType::SignedInteger; constexpr auto PT = mc::PrimitiveType::SignedInteger;
constexpr auto Bytes = 16; constexpr auto Bytes = 16;
return getPrimitive(TypeName, PT, Bytes, alreadyExisted); return getType(TypeName, PT, Bytes, alreadyExisted);
} }
constexpr mc::Type *MetalClawDefWriter::type(int32_t*, bool *alreadyExisted) { mc::Type *MetalClawDefWriter::type(int32_t*, bool *alreadyExisted) {
constexpr auto TypeName = "B:int32_t"; constexpr auto TypeName = "B:int32_t";
constexpr auto PT = mc::PrimitiveType::SignedInteger; constexpr auto PT = mc::PrimitiveType::SignedInteger;
constexpr auto Bytes = 32; constexpr auto Bytes = 32;
return getPrimitive(TypeName, PT, Bytes, alreadyExisted); return getType(TypeName, PT, Bytes, alreadyExisted);
} }
constexpr mc::Type *MetalClawDefWriter::type(int64_t*, bool *alreadyExisted) { mc::Type *MetalClawDefWriter::type(int64_t*, bool *alreadyExisted) {
constexpr auto TypeName = "B:int64_t"; constexpr auto TypeName = "B:int64_t";
constexpr auto PT = mc::PrimitiveType::SignedInteger; constexpr auto PT = mc::PrimitiveType::SignedInteger;
constexpr auto Bytes = 64; constexpr auto Bytes = 64;
return getPrimitive(TypeName, PT, Bytes, alreadyExisted); return getType(TypeName, PT, Bytes, alreadyExisted);
} }
constexpr mc::Type *MetalClawDefWriter::type(uint8_t*, bool *alreadyExisted) { mc::Type *MetalClawDefWriter::type(uint8_t*, bool *alreadyExisted) {
constexpr auto TypeName = "B:uint8_t"; constexpr auto TypeName = "B:uint8_t";
constexpr auto PT = mc::PrimitiveType::UnsignedInteger; constexpr auto PT = mc::PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 8; constexpr auto Bytes = 8;
return getPrimitive(TypeName, PT, Bytes, alreadyExisted); return getType(TypeName, PT, Bytes, alreadyExisted);
} }
constexpr mc::Type *MetalClawDefWriter::type(uint16_t*, bool *alreadyExisted) { mc::Type *MetalClawDefWriter::type(uint16_t*, bool *alreadyExisted) {
constexpr auto TypeName = "B:uint16_t"; constexpr auto TypeName = "B:uint16_t";
constexpr auto PT = mc::PrimitiveType::UnsignedInteger; constexpr auto PT = mc::PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 16; constexpr auto Bytes = 16;
return getPrimitive(TypeName, PT, Bytes, alreadyExisted); return getType(TypeName, PT, Bytes, alreadyExisted);
} }
constexpr mc::Type *MetalClawDefWriter::type(uint32_t*, bool *alreadyExisted) { mc::Type *MetalClawDefWriter::type(uint32_t*, bool *alreadyExisted) {
constexpr auto TypeName = "B:uint32_t"; constexpr auto TypeName = "B:uint32_t";
constexpr auto PT = mc::PrimitiveType::UnsignedInteger; constexpr auto PT = mc::PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 32; constexpr auto Bytes = 32;
return getPrimitive(TypeName, PT, Bytes, alreadyExisted); return getType(TypeName, PT, Bytes, alreadyExisted);
} }
constexpr mc::Type *MetalClawDefWriter::type(uint64_t*, bool *alreadyExisted) { mc::Type *MetalClawDefWriter::type(uint64_t*, bool *alreadyExisted) {
constexpr auto TypeName = "B:uint64_t"; constexpr auto TypeName = "B:uint64_t";
constexpr auto PT = mc::PrimitiveType::UnsignedInteger; constexpr auto PT = mc::PrimitiveType::UnsignedInteger;
constexpr auto Bytes = 64; constexpr auto Bytes = 64;
return getPrimitive(TypeName, PT, Bytes, alreadyExisted); return getType(TypeName, PT, Bytes, alreadyExisted);
} }
mc::Type *MetalClawDefWriter::type(McStr, bool *alreadyExisted) { mc::Type *MetalClawDefWriter::type(McStr, bool *alreadyExisted) {
constexpr auto TypeName = "B:string"; constexpr auto TypeName = "B:string";
constexpr auto PT = mc::PrimitiveType::String; constexpr auto PT = mc::PrimitiveType::String;
return getPrimitive(TypeName, PT, 0, alreadyExisted); return getType(TypeName, PT, 0, alreadyExisted);
} }
constexpr mc::Type *MetalClawDefWriter::type(bool*, bool *alreadyExisted) { mc::Type *MetalClawDefWriter::type(bool*, bool *alreadyExisted) {
constexpr auto TypeName = "B:bool"; constexpr auto TypeName = "B:bool";
constexpr auto PT = mc::PrimitiveType::Bool; constexpr auto PT = mc::PrimitiveType::Bool;
constexpr auto Bytes = 0; constexpr auto Bytes = 0;
return getPrimitive(TypeName, PT, Bytes, alreadyExisted); return getType(TypeName, PT, Bytes, alreadyExisted);
} }
constexpr void MetalClawDefWriter::setTypeInfo(const char *name, int) { void MetalClawDefWriter::setTypeInfo(const char *name, int) {
m_typeAlreayExisted = m_typeStore->contains(name); m_typeAlreayExisted = m_typeStore->contains(name);
m_type = &m_typeStore->at(name); m_type = &m_typeStore->at(name);
m_type->typeName = name; m_type->typeName = name;
m_type->primitiveType = mc::PrimitiveType::Struct; m_type->primitiveType = mc::PrimitiveType::Struct;
} }
constexpr mc::Type *MetalClawDefWriter::getPrimitive(mc::String tn, mc::PrimitiveType pt, int b, bool *alreadyExisted) { mc::Type *MetalClawDefWriter::getType(mc::TypeName tn, mc::PrimitiveType pt, int b, bool *alreadyExisted) {
if (m_typeStore->contains(tn)) { if (m_typeStore->contains(tn)) {
*alreadyExisted = true; *alreadyExisted = true;
return &m_typeStore->at(tn); return &m_typeStore->at(tn);

View File

@ -32,26 +32,6 @@ static constexpr int indirectionLevels(T *t) {
return 1 + indirectionLevels(*t); return 1 + indirectionLevels(*t);
} }
static_assert([] {
int i = 0;
return indirectionLevels(i) == 0;
}(), "indirectionLevels broken: indirectionLevels(int)");
static_assert([] {
int i = 0;
return indirectionLevels(&i) == 1;
}(), "indirectionLevels broken: indirectionLevels(int*)");
static_assert([] {
int i[2] = {};
return indirectionLevels(i) == 1;
}(), "indirectionLevels broken: indirectionLevels(int[])");
static_assert([] {
int i[2][2] = {{}};
return indirectionLevels(i) == 2;
}(), "indirectionLevels broken: indirectionLevels(int[][])");
class MetalClawDefWriter { class MetalClawDefWriter {
private: private:
@ -72,42 +52,38 @@ class MetalClawDefWriter {
template<typename T> template<typename T>
ox::Error op(const char *name, ox::Vector<T> *val); ox::Error op(const char *name, ox::Vector<T> *val);
template<std::size_t L>
ox::Error op(const char *name, ox::BString<L> *val);
template<typename T> template<typename T>
constexpr ox::Error op(const char *name, T *val); ox::Error op(const char *name, T *val);
constexpr void setTypeInfo(const char *name, int fields); void setTypeInfo(const char *name, int fields);
[[nodiscard]] mc::Type *definition() noexcept {
return m_type;
}
static constexpr OpType opType() { static constexpr OpType opType() {
return OpType::WriteDefinition; return OpType::WriteDefinition;
} }
private: private:
constexpr mc::Type *type(int8_t *val, bool *alreadyExisted); mc::Type *type(int8_t *val, bool *alreadyExisted);
constexpr mc::Type *type(int16_t *val, bool *alreadyExisted); mc::Type *type(int16_t *val, bool *alreadyExisted);
constexpr mc::Type *type(int32_t *val, bool *alreadyExisted); mc::Type *type(int32_t *val, bool *alreadyExisted);
constexpr mc::Type *type(int64_t *val, bool *alreadyExisted); mc::Type *type(int64_t *val, bool *alreadyExisted);
constexpr mc::Type *type(uint8_t *val, bool *alreadyExisted); mc::Type *type(uint8_t *val, bool *alreadyExisted);
constexpr mc::Type *type(uint16_t *val, bool *alreadyExisted); mc::Type *type(uint16_t *val, bool *alreadyExisted);
constexpr mc::Type *type(uint32_t *val, bool *alreadyExisted); mc::Type *type(uint32_t *val, bool *alreadyExisted);
constexpr mc::Type *type(uint64_t *val, bool *alreadyExisted); mc::Type *type(uint64_t *val, bool *alreadyExisted);
constexpr mc::Type *type(bool *val, bool *alreadyExisted); mc::Type *type(bool *val, bool *alreadyExisted);
constexpr mc::Type *type(const char *val, bool *alreadyExisted);
mc::Type *type(McStr val, bool *alreadyExisted); mc::Type *type(McStr val, bool *alreadyExisted);
template<std::size_t L>
constexpr mc::Type *type(ox::BString<L> *val, bool *alreadyExisted);
template<typename T> template<typename T>
mc::Type *type(T *val, bool *alreadyExisted); mc::Type *type(T *val, bool *alreadyExisted);
constexpr mc::Type *getPrimitive(mc::String tn, mc::PrimitiveType t, int b, bool *alreadyExisted); mc::Type *getType(mc::TypeName tn, mc::PrimitiveType t, int b, bool *alreadyExisted);
}; };
// array handler // array handler
@ -117,7 +93,7 @@ ox::Error MetalClawDefWriter::op(const char *name, T *val, std::size_t) {
constexpr typename RemoveIndirection<decltype(val)>::type *p = nullptr; constexpr typename RemoveIndirection<decltype(val)>::type *p = nullptr;
bool alreadyExisted = false; bool alreadyExisted = false;
const auto t = type(p, &alreadyExisted); const auto t = type(p, &alreadyExisted);
m_type->fieldList.push_back(mc::Field{t, name, subscriptLevels(val), !alreadyExisted}); m_type->fieldList.push_back(mc::Field{t, name, indirectionLevels(val), alreadyExisted ? t->typeName : "", !alreadyExisted});
return OxError(0); return OxError(0);
} }
return OxError(1); return OxError(1);
@ -128,17 +104,12 @@ ox::Error MetalClawDefWriter::op(const char *name, ox::Vector<T> *val) {
return op(name, val->data(), val->size()); return op(name, val->data(), val->size());
} }
template<std::size_t L>
ox::Error MetalClawDefWriter::op(const char *name, ox::BString<L> *val) {
return op(name, val->c_str());
}
template<typename T> template<typename T>
constexpr ox::Error MetalClawDefWriter::op(const char *name, T *val) { ox::Error MetalClawDefWriter::op(const char *name, T *val) {
if (m_type) { if (m_type) {
bool alreadyExisted = false; bool alreadyExisted = false;
const auto t = type(val, &alreadyExisted); const auto t = type(val, &alreadyExisted);
m_type->fieldList.push_back(mc::Field{t, name, 0, !alreadyExisted}); m_type->fieldList.push_back(mc::Field{t, name, 0, alreadyExisted ? t->typeName : "", !alreadyExisted});
return OxError(0); return OxError(0);
} }
return OxError(1); return OxError(1);
@ -152,11 +123,11 @@ mc::Type *MetalClawDefWriter::type(T *val, bool *alreadyExisted) {
return dw.m_type; return dw.m_type;
} }
template<std::size_t L> template<typename T>
constexpr mc::Type *MetalClawDefWriter::type(ox::BString<L>*, bool *alreadyExisted) { [[nodiscard]] ValErr<mc::Type*> writeMCDef(T *val) {
constexpr auto TypeName = "B:string"; MetalClawDefWriter writer;
constexpr auto PT = mc::PrimitiveType::String; ox::Error err = ioOp(&writer, val);
return getPrimitive(TypeName, PT, 0, alreadyExisted); return {writer.definition(), err};
} }
} }

View File

@ -8,6 +8,7 @@
#pragma once #pragma once
#include "defread.hpp"
#include "deftypes.hpp" #include "deftypes.hpp"
#include "defwriter.hpp" #include "defwriter.hpp"
#include "read.hpp" #include "read.hpp"

View File

@ -6,21 +6,16 @@
* file, You can obtain one at http://mozilla.org/MPL/2.0/. * file, You can obtain one at http://mozilla.org/MPL/2.0/.
*/ */
#include <iostream>
#include <assert.h> #include <assert.h>
#include <map> #include <map>
#include <vector>
#include <string> #include <string>
#include <ox/mc/mc.hpp> #include <ox/mc/mc.hpp>
#include <ox/std/std.hpp> #include <ox/std/std.hpp>
using namespace std;
using namespace ox;
struct TestStructNest { struct TestStructNest {
bool Bool = false; bool Bool = false;
uint32_t Int = 0; uint32_t Int = 0;
BString<32> String = ""; ox::BString<32> String = "";
}; };
struct TestStruct { struct TestStruct {
@ -34,7 +29,7 @@ struct TestStruct {
int32_t Int6 = 0; int32_t Int6 = 0;
int32_t Int7 = 0; int32_t Int7 = 0;
int32_t Int8 = 0; int32_t Int8 = 0;
BString<32> String = ""; ox::BString<32> String = "";
uint32_t List[4] = {0, 0, 0 , 0}; uint32_t List[4] = {0, 0, 0 , 0};
TestStructNest EmptyStruct; TestStructNest EmptyStruct;
TestStructNest Struct; TestStructNest Struct;
@ -43,7 +38,7 @@ struct TestStruct {
template<typename T> template<typename T>
int ioOp(T *io, TestStructNest *obj) { int ioOp(T *io, TestStructNest *obj) {
int32_t err = 0; int32_t err = 0;
io->setTypeInfo("common::TestStructNest", 3); io->setTypeInfo("TestStructNest", 3);
err |= io->op("Bool", &obj->Bool); err |= io->op("Bool", &obj->Bool);
err |= io->op("Int", &obj->Int); err |= io->op("Int", &obj->Int);
err |= io->op("String", &obj->String); err |= io->op("String", &obj->String);
@ -53,7 +48,7 @@ int ioOp(T *io, TestStructNest *obj) {
template<typename T> template<typename T>
int ioOp(T *io, TestStruct *obj) { int ioOp(T *io, TestStruct *obj) {
int err = 0; int err = 0;
io->setTypeInfo("common::TestStruct", 14); io->setTypeInfo("TestStruct", 14);
err |= io->op("Bool", &obj->Bool); err |= io->op("Bool", &obj->Bool);
err |= io->op("Int", &obj->Int); err |= io->op("Int", &obj->Int);
err |= io->op("Int1", &obj->Int1); err |= io->op("Int1", &obj->Int1);
@ -71,31 +66,29 @@ int ioOp(T *io, TestStruct *obj) {
return err; return err;
} }
map<string, int(*)(string)> tests = { std::map<std::string, ox::Error(*)()> tests = {
{ {
{ {
"MetalClawWriter", "MetalClawWriter",
[](string) { [] {
// This test doesn't confirm much, but it does show that the writer // This test doesn't confirm much, but it does show that the writer
// doesn't segfault // doesn't segfault
size_t buffLen = 1024; constexpr size_t buffLen = 1024;
auto buff = new uint8_t[buffLen]; uint8_t buff[buffLen];
int err = 0; ox::Error err = 0;
TestStruct ts; TestStruct ts;
err |= writeMC(buff, buffLen, &ts); err |= ox::writeMC(buff, buffLen, &ts);
delete []buff;
return err; return err;
} }
}, },
{ {
"MetalClawReader", "MetalClawReader",
[](string) { [] {
int err = 0; ox::Error err = 0;
size_t buffLen = 1024; constexpr size_t buffLen = 1024;
auto buff = new uint8_t[buffLen]; uint8_t buff[buffLen];
TestStruct testIn, testOut; TestStruct testIn, testOut;
testIn.Bool = true; testIn.Bool = true;
@ -109,8 +102,8 @@ map<string, int(*)(string)> tests = {
testIn.Struct.Int = 300; testIn.Struct.Int = 300;
testIn.Struct.String = "Test String 2"; testIn.Struct.String = "Test String 2";
err |= writeMC(buff, buffLen, &testIn); err |= ox::writeMC(buff, buffLen, &testIn);
err |= readMC(buff, buffLen, &testOut); err |= ox::readMC(buff, buffLen, &testOut);
err |= !(testIn.Bool == testOut.Bool); err |= !(testIn.Bool == testOut.Bool);
err |= !(testIn.Int == testOut.Int); err |= !(testIn.Int == testOut.Int);
@ -134,24 +127,28 @@ map<string, int(*)(string)> tests = {
err |= !(testIn.Struct.String == testOut.Struct.String); err |= !(testIn.Struct.String == testOut.Struct.String);
err |= !(testIn.Struct.Bool == testOut.Struct.Bool); err |= !(testIn.Struct.Bool == testOut.Struct.Bool);
delete []buff; auto def = ox::writeMCDef(&testIn);
err |= def.error;
return err; return err;
} }
}, },
{
"MetalClawDef",
[] {
ox::Error err = 0;
return err;
}
},
} }
}; };
int main(int argc, const char **args) { int main(int argc, const char **args) {
int retval = -1; int retval = -1;
if (argc > 1) { if (argc > 0) {
auto testName = args[1]; auto testName = args[1];
string testArg = "";
if (args[2]) {
testArg = args[2];
}
if (tests.find(testName) != tests.end()) { if (tests.find(testName) != tests.end()) {
retval = tests[testName](testArg); retval = tests[testName]();
} }
} }
return retval; return retval;

View File

@ -8,6 +8,7 @@
#pragma once #pragma once
#include <ox/std/string.hpp>
#include <ox/std/strops.hpp> #include <ox/std/strops.hpp>
#include <ox/std/types.hpp> #include <ox/std/types.hpp>
@ -28,6 +29,12 @@ class McStr {
m_cap = -1; m_cap = -1;
} }
template<std::size_t sz>
constexpr McStr(BString<sz> *str) noexcept {
m_str = const_cast<char*>(str->data());
m_cap = -1;
}
constexpr McStr(char *str, int cap) noexcept { constexpr McStr(char *str, int cap) noexcept {
m_str = str; m_str = str;
m_cap = cap; m_cap = cap;