Skip to content

Commit

Permalink
core: add custom data types
Browse files Browse the repository at this point in the history
  • Loading branch information
vaxerski committed Dec 29, 2023
1 parent 8d53858 commit a081d90
Show file tree
Hide file tree
Showing 6 changed files with 206 additions and 72 deletions.
42 changes: 37 additions & 5 deletions include/hyprlang.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@
#include <fstream>

class CConfigImpl;
struct SConfigDefaultValue;
struct SSpecialCategory;

namespace Hyprlang {

Expand Down Expand Up @@ -66,8 +68,30 @@ namespace Hyprlang {

/* typedefs */
typedef CParseResult (*PCONFIGHANDLERFUNC)(const char* COMMAND, const char* VALUE);
typedef CParseResult (*PCONFIGCUSTOMVALUEHANDLERFUNC)(const char* VALUE, void** data);
typedef void (*PCONFIGCUSTOMVALUEDESTRUCTOR)(void** data);

/* Container for a custom config value type
When creating, pass your handler.
Handler will receive a void** that points to a void* that you can set to your own
thing. Pass a dtor to free whatever you allocated when the custom value type is being released.
data may always be pointing to a nullptr.
*/
class CConfigCustomValueType {
public:
CConfigCustomValueType(PCONFIGCUSTOMVALUEHANDLERFUNC handler_, PCONFIGCUSTOMVALUEDESTRUCTOR dtor_, const char* defaultValue);
~CConfigCustomValueType();

private:
PCONFIGCUSTOMVALUEHANDLERFUNC handler = nullptr;
PCONFIGCUSTOMVALUEDESTRUCTOR dtor = nullptr;
void* data = nullptr;
std::string defaultVal = "";

friend class CConfigValue;
friend class CConfig;
};

struct SConfigValueImpl;
/* Container for a config value */
class CConfigValue {
public:
Expand All @@ -76,9 +100,11 @@ namespace Hyprlang {
CConfigValue(const float value);
CConfigValue(const char* value);
CConfigValue(const SVector2D value);
CConfigValue(const CConfigValue&);
CConfigValue(CConfigValue&&);
void operator=(const CConfigValue&);
CConfigValue(CConfigCustomValueType&& value);
CConfigValue(const CConfigValue&) = delete;
CConfigValue(CConfigValue&&) = delete;
CConfigValue(const CConfigValue&&) = delete;
CConfigValue(CConfigValue&) = delete;
~CConfigValue();

void* dataPtr() const;
Expand All @@ -89,21 +115,26 @@ namespace Hyprlang {
case CONFIGDATATYPE_FLOAT: return std::any(*reinterpret_cast<float*>(m_pData));
case CONFIGDATATYPE_STR: return std::any(reinterpret_cast<const char*>(m_pData));
case CONFIGDATATYPE_VEC2: return std::any(*reinterpret_cast<SVector2D*>(m_pData));
case CONFIGDATATYPE_CUSTOM: return std::any(reinterpret_cast<CConfigCustomValueType*>(m_pData)->data);
default: throw;
}
return {}; // unreachable
}

private:
// remember to also edit config.hpp if editing
enum eDataType {
CONFIGDATATYPE_EMPTY,
CONFIGDATATYPE_INT,
CONFIGDATATYPE_FLOAT,
CONFIGDATATYPE_STR,
CONFIGDATATYPE_VEC2,
CONFIGDATATYPE_CUSTOM,
};
eDataType m_eType = eDataType::CONFIGDATATYPE_EMPTY;
void* m_pData = nullptr;
void defaultFrom(SConfigDefaultValue& ref);
void setFrom(std::any value);

friend class CConfig;
};
Expand All @@ -117,7 +148,7 @@ namespace Hyprlang {
/* Add a config value, for example myCategory:myValue.
This has to be done before commence()
Value provided becomes default */
void addConfigValue(const char* name, const CConfigValue value);
void addConfigValue(const char* name, const CConfigValue& value);

/* Register a handler. Can be called anytime, though not recommended
to do this dynamically */
Expand Down Expand Up @@ -181,6 +212,7 @@ namespace Hyprlang {
CParseResult configSetValueSafe(const std::string& command, const std::string& value);
CParseResult parseVariable(const std::string& lhs, const std::string& rhs, bool dynamic = false);
void clearState();
void applyDefaultsToCat(SSpecialCategory& cat);
};
};
#endif
133 changes: 85 additions & 48 deletions src/common.cpp
Original file line number Diff line number Diff line change
@@ -1,4 +1,5 @@
#include "public.hpp"
#include "config.hpp"
#include <string.h>

using namespace Hyprlang;
Expand All @@ -16,6 +17,9 @@ void CParseResult::setError(const char* err) {
}

CConfigValue::~CConfigValue() {
if (m_eType == CONFIGDATATYPE_CUSTOM)
reinterpret_cast<CConfigCustomValueType*>(m_pData)->dtor(&reinterpret_cast<CConfigCustomValueType*>(m_pData)->data);

if (m_pData)
free(m_pData);
}
Expand Down Expand Up @@ -44,71 +48,104 @@ CConfigValue::CConfigValue(const char* value) {
m_eType = CONFIGDATATYPE_STR;
}

CConfigValue::CConfigValue(const CConfigValue& ref) {
m_eType = ref.m_eType;
switch (ref.m_eType) {
case eDataType::CONFIGDATATYPE_INT: {
m_pData = calloc(1, sizeof(int64_t));
*reinterpret_cast<int64_t*>(m_pData) = std::any_cast<int64_t>(ref.getValue());
CConfigValue::CConfigValue(CConfigCustomValueType&& value) {
m_pData = calloc(1, sizeof(CConfigCustomValueType));
new (m_pData) CConfigCustomValueType(value);
m_eType = CONFIGDATATYPE_CUSTOM;
}

CConfigValue::CConfigValue() {
;
}

void* CConfigValue::dataPtr() const {
return m_pData;
}

CConfigCustomValueType::CConfigCustomValueType(PCONFIGCUSTOMVALUEHANDLERFUNC handler_, PCONFIGCUSTOMVALUEDESTRUCTOR dtor_, const char* def) {
handler = handler_;
dtor = dtor_;
defaultVal = def;
}

CConfigCustomValueType::~CConfigCustomValueType() {
dtor(&data);
}

void CConfigValue::defaultFrom(SConfigDefaultValue& ref) {
m_eType = (CConfigValue::eDataType)ref.type;
switch (m_eType) {
case CONFIGDATATYPE_FLOAT: {
if (!m_pData)
m_pData = calloc(1, sizeof(float));
*reinterpret_cast<float*>(m_pData) = std::any_cast<float>(ref.data);
break;
}
case eDataType::CONFIGDATATYPE_FLOAT: {
m_pData = calloc(1, sizeof(float));
*reinterpret_cast<float*>(m_pData) = std::any_cast<float>(ref.getValue());
case CONFIGDATATYPE_INT: {
if (!m_pData)
m_pData = calloc(1, sizeof(int64_t));
*reinterpret_cast<int64_t*>(m_pData) = std::any_cast<int64_t>(ref.data);
break;
}
case eDataType::CONFIGDATATYPE_VEC2: {
m_pData = calloc(1, sizeof(SVector2D));
*reinterpret_cast<SVector2D*>(m_pData) = std::any_cast<SVector2D>(ref.getValue());
case CONFIGDATATYPE_STR: {
if (!m_pData)
free(m_pData);
std::string str = std::any_cast<std::string>(ref.data);
m_pData = calloc(1, str.length() + 1);
strncpy((char*)m_pData, str.c_str(), str.length());
break;
}
case eDataType::CONFIGDATATYPE_STR: {
auto str = std::any_cast<const char*>(ref.getValue());
m_pData = calloc(1, strlen(str) + 1);
strncpy((char*)m_pData, str, strlen(str));
case CONFIGDATATYPE_VEC2: {
if (!m_pData)
m_pData = calloc(1, sizeof(SVector2D));
*reinterpret_cast<SVector2D*>(m_pData) = std::any_cast<SVector2D>(ref.data);
break;
}
case CONFIGDATATYPE_CUSTOM: {
if (!m_pData)
m_pData = calloc(1, sizeof(CConfigCustomValueType));
CConfigCustomValueType* type = reinterpret_cast<CConfigCustomValueType*>(m_pData);
type->handler = ref.handler;
type->dtor = ref.dtor;
type->handler(std::any_cast<std::string>(ref.data).c_str(), &type->data);
break;
}
default: {
throw "bad defaultFrom type";
}
}
}

void CConfigValue::operator=(const CConfigValue& ref) {
m_eType = ref.m_eType;
switch (ref.m_eType) {
case eDataType::CONFIGDATATYPE_INT: {
m_pData = calloc(1, sizeof(int64_t));
*reinterpret_cast<int64_t*>(m_pData) = std::any_cast<int64_t>(ref.getValue());
void CConfigValue::setFrom(std::any value) {
switch (m_eType) {
case CONFIGDATATYPE_FLOAT: {
*reinterpret_cast<float*>(m_pData) = std::any_cast<float>(value);
break;
}
case eDataType::CONFIGDATATYPE_FLOAT: {
m_pData = calloc(1, sizeof(float));
*reinterpret_cast<float*>(m_pData) = std::any_cast<float>(ref.getValue());
case CONFIGDATATYPE_INT: {
*reinterpret_cast<int64_t*>(m_pData) = std::any_cast<int64_t>(value);
break;
}
case eDataType::CONFIGDATATYPE_VEC2: {
m_pData = calloc(1, sizeof(SVector2D));
*reinterpret_cast<SVector2D*>(m_pData) = std::any_cast<SVector2D>(ref.getValue());
case CONFIGDATATYPE_STR: {
free(m_pData);
std::string str = std::any_cast<std::string>(value);
m_pData = calloc(1, str.length() + 1);
strncpy((char*)m_pData, str.c_str(), str.length());
break;
}
case eDataType::CONFIGDATATYPE_STR: {
auto str = std::any_cast<const char*>(ref.getValue());
m_pData = calloc(1, strlen(str) + 1);
strncpy((char*)m_pData, str, strlen(str));
case CONFIGDATATYPE_VEC2: {
*reinterpret_cast<SVector2D*>(m_pData) = std::any_cast<SVector2D>(value);
break;
}
// case CONFIGDATATYPE_CUSTOM: {
// CConfigCustomValueType* type = reinterpret_cast<CConfigCustomValueType*>(m_pData);
// type->handler = ref.handler;
// type->dtor = ref.dtor;
// type->handler(std::any_cast<std::string>(ref.data).c_str(), &type->data);
// break;
// }
default: {
throw "bad defaultFrom type";
}
}
}

CConfigValue::CConfigValue(CConfigValue&& ref) {
m_pData = ref.dataPtr();
m_eType = ref.m_eType;
ref.m_eType = eDataType::CONFIGDATATYPE_EMPTY;
ref.m_pData = nullptr;
}

CConfigValue::CConfigValue() {
;
}

void* CConfigValue::dataPtr() const {
return m_pData;
}
}
48 changes: 34 additions & 14 deletions src/config.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,11 +52,19 @@ CConfig::~CConfig() {
delete impl;
}

void CConfig::addConfigValue(const char* name, const CConfigValue value) {
void CConfig::addConfigValue(const char* name, const CConfigValue& value) {
if (m_bCommenced)
throw "Cannot addConfigValue after commence()";

impl->defaultValues[std::string{name}] = value;
if ((eDataType)value.m_eType != CONFIGDATATYPE_CUSTOM && (eDataType)value.m_eType != CONFIGDATATYPE_STR)
impl->defaultValues.emplace(name, SConfigDefaultValue{value.getValue(), (eDataType)value.m_eType});
else if ((eDataType)value.m_eType == CONFIGDATATYPE_STR)
impl->defaultValues.emplace(name, SConfigDefaultValue{std::string{std::any_cast<const char*>(value.getValue())}, (eDataType)value.m_eType});
else
impl->defaultValues.emplace(name,
SConfigDefaultValue{reinterpret_cast<CConfigCustomValueType*>(value.m_pData)->defaultVal, (eDataType)value.m_eType,
reinterpret_cast<CConfigCustomValueType*>(value.m_pData)->handler,
reinterpret_cast<CConfigCustomValueType*>(value.m_pData)->dtor});
}

void CConfig::addSpecialConfigValue(const char* cat, const char* name, const CConfigValue value) {
Expand All @@ -65,7 +73,15 @@ void CConfig::addSpecialConfigValue(const char* cat, const char* name, const CCo
if (IT == impl->specialCategoryDescriptors.end())
throw "No such category";

IT->get()->defaultValues[std::string{name}] = value;
if ((eDataType)value.m_eType != CONFIGDATATYPE_CUSTOM && (eDataType)value.m_eType != CONFIGDATATYPE_STR)
IT->get()->defaultValues.emplace(name, SConfigDefaultValue{value.getValue(), (eDataType)value.m_eType});
else if ((eDataType)value.m_eType == CONFIGDATATYPE_STR)
IT->get()->defaultValues.emplace(name, SConfigDefaultValue{std::string{std::any_cast<const char*>(value.getValue())}, (eDataType)value.m_eType});
else
IT->get()->defaultValues.emplace(name,
SConfigDefaultValue{reinterpret_cast<CConfigCustomValueType*>(value.m_pData)->defaultVal, (eDataType)value.m_eType,
reinterpret_cast<CConfigCustomValueType*>(value.m_pData)->handler,
reinterpret_cast<CConfigCustomValueType*>(value.m_pData)->dtor});
}

void CConfig::addSpecialCategory(const char* name, SSpecialCategoryOptions options) {
Expand All @@ -85,16 +101,16 @@ void CConfig::addSpecialCategory(const char* name, SSpecialCategoryOptions optio
}
}

void SSpecialCategory::applyDefaults() {
for (auto& [k, v] : descriptor->defaultValues) {
values[k] = v;
void CConfig::applyDefaultsToCat(SSpecialCategory& cat) {
for (auto& [k, v] : cat.descriptor->defaultValues) {
cat.values[k].defaultFrom(v);
}
}

void CConfig::commence() {
m_bCommenced = true;
for (auto& [k, v] : impl->defaultValues) {
impl->values[k] = v;
impl->values[k].defaultFrom(v);
}
}

Expand Down Expand Up @@ -240,7 +256,7 @@ CParseResult CConfig::configSetValueSafe(const std::string& command, const std::
PCAT->key = sc->key;
addSpecialConfigValue(sc->name.c_str(), sc->key.c_str(), CConfigValue("0"));

PCAT->applyDefaults();
applyDefaultsToCat(*PCAT);

VALUEIT = PCAT->values.find(valueName.substr(sc->name.length() + 1));

Expand All @@ -267,7 +283,7 @@ CParseResult CConfig::configSetValueSafe(const std::string& command, const std::
switch (VALUEIT->second.m_eType) {
case CConfigValue::eDataType::CONFIGDATATYPE_INT: {
try {
VALUEIT->second = {configStringToInt(value)};
VALUEIT->second.setFrom(configStringToInt(value));
} catch (std::exception& e) {
result.setError(std::format("failed parsing an int: {}", e.what()));
return result;
Expand All @@ -276,7 +292,7 @@ CParseResult CConfig::configSetValueSafe(const std::string& command, const std::
}
case CConfigValue::eDataType::CONFIGDATATYPE_FLOAT: {
try {
VALUEIT->second = {std::stof(value)};
VALUEIT->second.setFrom(std::stof(value));
} catch (std::exception& e) {
result.setError(std::format("failed parsing a float: {}", e.what()));
return result;
Expand All @@ -294,15 +310,19 @@ CParseResult CConfig::configSetValueSafe(const std::string& command, const std::
if (LHS.contains(" ") || RHS.contains(" "))
throw std::runtime_error("too many args");

VALUEIT->second = {SVector2D{std::stof(LHS), std::stof(RHS)}};
VALUEIT->second.setFrom(SVector2D{std::stof(LHS), std::stof(RHS)});
} catch (std::exception& e) {
result.setError(std::format("failed parsing a vec2: {}", e.what()));
return result;
}
break;
}
case CConfigValue::eDataType::CONFIGDATATYPE_STR: {
VALUEIT->second = {value.c_str()};
VALUEIT->second.setFrom(value);
break;
}
case CConfigValue::eDataType::CONFIGDATATYPE_CUSTOM: {
reinterpret_cast<CConfigCustomValueType*>(VALUEIT->second.m_pData)->handler(value.c_str(), &reinterpret_cast<CConfigCustomValueType*>(VALUEIT->second.m_pData)->data);
break;
}
default: {
Expand Down Expand Up @@ -468,10 +488,10 @@ CParseResult CConfig::parse() {
clearState();

for (auto& [k, v] : impl->defaultValues) {
impl->values.at(k) = v;
impl->values.at(k).defaultFrom(v);
}
for (auto& sc : impl->specialCategories) {
sc->applyDefaults();
applyDefaultsToCat(*sc);
}

CParseResult fileParseResult = parseFile(impl->path);
Expand Down
Loading

0 comments on commit a081d90

Please sign in to comment.