Initial Commit
This commit is contained in:
4
.gitignore
vendored
Normal file
4
.gitignore
vendored
Normal file
@@ -0,0 +1,4 @@
|
|||||||
|
*.o
|
||||||
|
*.so
|
||||||
|
*.so.*
|
||||||
|
|
||||||
45
Makefile
Normal file
45
Makefile
Normal file
@@ -0,0 +1,45 @@
|
|||||||
|
CXX ?= g++
|
||||||
|
|
||||||
|
VERSION := 0.0.1
|
||||||
|
|
||||||
|
TARGET_NOVERSION := liboptions.so
|
||||||
|
TARGET := $(TARGET_NOVERSION).$(VERSION)
|
||||||
|
|
||||||
|
SRCS := $(wildcard *.cpp)
|
||||||
|
|
||||||
|
OBJS := $(SRCS:.cpp=.o)
|
||||||
|
|
||||||
|
CXXFLAGS := -std=c++17 -fPIC -shared
|
||||||
|
OPTFLAGS := -O3
|
||||||
|
DBGFLAGS := -g
|
||||||
|
LDFLAGS :=
|
||||||
|
|
||||||
|
# Default build
|
||||||
|
all: release
|
||||||
|
|
||||||
|
release: CXXFLAGS += $(OPTFLAGS)
|
||||||
|
release: $(TARGET)
|
||||||
|
|
||||||
|
debug: CXXFLAGS += $(DBGFLAGS)
|
||||||
|
debug: $(TARGET)
|
||||||
|
|
||||||
|
# Linker
|
||||||
|
$(TARGET): $(OBJS)
|
||||||
|
$(CXX) $(CXXFLAGS) -o $@ $^ $(LDFLAGS)
|
||||||
|
|
||||||
|
# Compiler
|
||||||
|
%.o: %.cpp
|
||||||
|
$(CXX) $(CXXFLAGS) -c $< -o $@
|
||||||
|
|
||||||
|
clean:
|
||||||
|
rm -f $(OBJS) $(TARGET_NOVERSION) $(TARGET_NOVERSION).*
|
||||||
|
|
||||||
|
install:
|
||||||
|
cp $(TARGET) /usr/lib/$(TARGET)
|
||||||
|
cp options.h /usr/include/options.h
|
||||||
|
ln -s /usr/lib/$(TARGET) /usr/lib/$(TARGET_NOVERSION)
|
||||||
|
|
||||||
|
uninstall:
|
||||||
|
unlink /usr/lib/$(TARGET_NOVERSION)
|
||||||
|
rm /usr/lib/$(TARGET)
|
||||||
|
rm /usr/include/options.h
|
||||||
63
options.cpp
Normal file
63
options.cpp
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
|
||||||
|
#include "options.h"
|
||||||
|
|
||||||
|
using namespace OptionLib;
|
||||||
|
|
||||||
|
bool isValidKeyChar(char c) {
|
||||||
|
return (c >= 'a' && c <= 'z') ||
|
||||||
|
(c >= '0' && c <= '9') ||
|
||||||
|
(c == '_' || c == '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string validateKey(const std::string &key) {
|
||||||
|
for (char c : key) {
|
||||||
|
if (!isValidKeyChar(c)) {
|
||||||
|
throw std::invalid_argument("Options key contains invalid characters, must match [a-z0-9\\_\\-]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
__OptionBase::__OptionBase(const std::string &key) : key(validateKey(key)) {}
|
||||||
|
|
||||||
|
void OptionsBase::registerOption(__OptionBase* opt) {
|
||||||
|
options.push_back(opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<__OptionBase*>& OptionsBase::getOptions() const {
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsBase::store(const std::string& filename, std::string) {
|
||||||
|
std::ofstream file(filename);
|
||||||
|
if(!comment.empty()) {
|
||||||
|
file << "# " << comment << std::endl;
|
||||||
|
}
|
||||||
|
for (auto* opt : getOptions()) {
|
||||||
|
file << opt->key << "=";
|
||||||
|
opt->store(file);
|
||||||
|
file << std::endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void OptionsBase::read(const std::string& filename) {
|
||||||
|
std::ifstream file(filename);
|
||||||
|
std::unordered_map<std::string, std::string> kv;
|
||||||
|
|
||||||
|
std::string key, value, line;
|
||||||
|
|
||||||
|
while (std::getline(file, line)) {
|
||||||
|
if (line.size() < 1 || line[0] == '#') continue; // skip comment lines TODO make better
|
||||||
|
auto pos = line.find('=');
|
||||||
|
if (pos == std::string::npos) continue; // skip invalid lines
|
||||||
|
std::string key = line.substr(0, pos);
|
||||||
|
std::string value = line.substr(pos + 1);
|
||||||
|
kv[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto* opt : getOptions()) {
|
||||||
|
if (kv.count(opt->key)) {
|
||||||
|
opt->setFromString(kv[opt->key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
63
options.h
Normal file
63
options.h
Normal file
@@ -0,0 +1,63 @@
|
|||||||
|
#ifndef OPTIONS_H
|
||||||
|
#define OPTIONS_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <sstream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <ostream>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace OptionLib {
|
||||||
|
class __OptionBase {
|
||||||
|
public:
|
||||||
|
const std::string key;
|
||||||
|
|
||||||
|
__OptionBase(const std::string &key);
|
||||||
|
virtual ~__OptionBase() = default;
|
||||||
|
|
||||||
|
virtual void setFromString(const std::string& value) = 0;
|
||||||
|
|
||||||
|
virtual void store(std::ostream& stream) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class OptionsBase {
|
||||||
|
private:
|
||||||
|
std::vector<__OptionBase*> options;
|
||||||
|
std::string comment = "";
|
||||||
|
|
||||||
|
public:
|
||||||
|
void registerOption(__OptionBase* opt);
|
||||||
|
const std::vector<__OptionBase*>& getOptions() const;
|
||||||
|
void store(const std::string& filename, std::string comment="");
|
||||||
|
void read(const std::string& filename);
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Option : public __OptionBase{
|
||||||
|
private:
|
||||||
|
T value;
|
||||||
|
public:
|
||||||
|
Option(OptionsBase * parent, std::string name) : __OptionBase(name) {
|
||||||
|
parent->registerOption(this);
|
||||||
|
}
|
||||||
|
Option(OptionsBase * parent, std::string name, T defaultValue) : __OptionBase(name) {
|
||||||
|
parent->registerOption(this);
|
||||||
|
set(defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& get() const {return value;}
|
||||||
|
void set(const T& v) {value = v;}
|
||||||
|
|
||||||
|
void setFromString(const std::string& str) override {
|
||||||
|
std::istringstream iss(str);
|
||||||
|
iss >> value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void store(std::ostream& stream) {
|
||||||
|
stream << value;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
118
options_headeronly.h
Normal file
118
options_headeronly.h
Normal file
@@ -0,0 +1,118 @@
|
|||||||
|
#ifndef OPTIONS_H
|
||||||
|
#define OPTIONS_H
|
||||||
|
|
||||||
|
#include <vector>
|
||||||
|
#include <sstream>
|
||||||
|
#include <fstream>
|
||||||
|
#include <ostream>
|
||||||
|
#include <unordered_map>
|
||||||
|
|
||||||
|
namespace OptionLib {
|
||||||
|
|
||||||
|
// TODO There has to be a better way of doing this
|
||||||
|
bool isValidKeyChar(char c) {
|
||||||
|
return (c >= 'a' && c <= 'z') ||
|
||||||
|
(c >= '0' && c <= '9') ||
|
||||||
|
(c == '_' || c == '-');
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::string validateKey(const std::string &key) {
|
||||||
|
for (char c : key) {
|
||||||
|
if (!isValidKeyChar(c)) {
|
||||||
|
throw std::invalid_argument("Options key contains invalid characters, must match [a-z0-9\\_\\-]");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return key;
|
||||||
|
}
|
||||||
|
|
||||||
|
class __OptionBase {
|
||||||
|
public:
|
||||||
|
const std::string key;
|
||||||
|
|
||||||
|
__OptionBase(const std::string &key) : key(validateKey(key)) {}
|
||||||
|
virtual ~__OptionBase() = default;
|
||||||
|
|
||||||
|
virtual void setFromString(const std::string& value) = 0;
|
||||||
|
|
||||||
|
virtual void store(ostream& stream) = 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
|
class OptionsBase {
|
||||||
|
private:
|
||||||
|
std::vector<__OptionBase*> options;
|
||||||
|
std::string comment = "";
|
||||||
|
|
||||||
|
public:
|
||||||
|
void registerOption(__OptionBase* opt) {
|
||||||
|
options.push_back(opt);
|
||||||
|
}
|
||||||
|
|
||||||
|
const std::vector<__OptionBase*>& getOptions() const {
|
||||||
|
return options;
|
||||||
|
}
|
||||||
|
|
||||||
|
void store(const std::string& filename, std::string comment="") {
|
||||||
|
std::ofstream file(filename);
|
||||||
|
if(!comment.empty()) {
|
||||||
|
file << "# " << comment << endl;
|
||||||
|
}
|
||||||
|
for (auto* opt : getOptions()) {
|
||||||
|
file << opt->key << "=";
|
||||||
|
opt->store(file);
|
||||||
|
file << endl;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void read(const std::string& filename) {
|
||||||
|
std::ifstream file(filename);
|
||||||
|
std::unordered_map<std::string, std::string> kv;
|
||||||
|
|
||||||
|
std::string key, value, line;
|
||||||
|
|
||||||
|
while (std::getline(file, line)) {
|
||||||
|
if (line.size() < 1 || line[0] == '#') continue; // skip comment lines TODO make better
|
||||||
|
auto pos = line.find('=');
|
||||||
|
if (pos == std::string::npos) continue; // skip invalid lines
|
||||||
|
std::string key = line.substr(0, pos);
|
||||||
|
std::string value = line.substr(pos + 1);
|
||||||
|
kv[key] = value;
|
||||||
|
}
|
||||||
|
|
||||||
|
for (auto* opt : getOptions()) {
|
||||||
|
if (kv.count(opt->key)) {
|
||||||
|
opt->setFromString(kv[opt->key]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
};
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
class Option : public __OptionBase{
|
||||||
|
private:
|
||||||
|
T value;
|
||||||
|
public:
|
||||||
|
Option(OptionsBase * parent, std::string name) : __OptionBase(name) {
|
||||||
|
parent->registerOption(this);
|
||||||
|
}
|
||||||
|
Option(OptionsBase * parent, std::string name, T defaultValue) : __OptionBase(name) {
|
||||||
|
parent->registerOption(this);
|
||||||
|
set(defaultValue);
|
||||||
|
}
|
||||||
|
|
||||||
|
const T& get() const {return value;}
|
||||||
|
void set(const T& v) {value = v;}
|
||||||
|
|
||||||
|
void setFromString(const std::string& str) override {
|
||||||
|
std::istringstream iss(str);
|
||||||
|
iss >> value;
|
||||||
|
}
|
||||||
|
|
||||||
|
void store(ostream& stream) {
|
||||||
|
stream << value;
|
||||||
|
};
|
||||||
|
};
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
Reference in New Issue
Block a user