Skip to content
Merged

up #46

Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
125 changes: 87 additions & 38 deletions include/GenericToolbox.Json.h
Original file line number Diff line number Diff line change
Expand Up @@ -32,23 +32,29 @@

// Declaration
namespace GenericToolbox {
namespace Json {

namespace Json{
// we want to preserve the ordering of the key for the
// override feature to fully work
// -> nlohmann::json are faster but move the keys
typedef nlohmann::ordered_json JsonType;

// Objects configured by a JSON file can inherit from this
typedef ConfigClass<JsonType> ConfigBaseClass;
}

// generic calls, overload
inline std::string toString(const Json::JsonType& config_);

namespace Json {

// IO
inline JsonType readConfigJsonStr(const std::string& configJsonStr_);
inline JsonType readConfigFile(const std::string& configFilePath_);
inline JsonType getForwardedConfig(const JsonType& config_);
inline void forwardConfig(JsonType& config_, const std::string& className_ = "");
inline void unfoldConfig(JsonType& config_);
inline std::string toReadableString(const JsonType& config_);
inline std::string toReadableString(const JsonType& config_, bool shallow_=false);

// reading
inline JsonType cd(const JsonType& json_, const std::string& keyPath_);
Expand Down Expand Up @@ -96,6 +102,9 @@ namespace GenericToolbox {

// Implementation
namespace GenericToolbox {

inline std::string toString(const Json::JsonType& config_){ return Json::toReadableString(config_); }

namespace Json {

// io
Expand Down Expand Up @@ -156,46 +165,63 @@ namespace GenericToolbox {
}
}
}
inline std::string toReadableString(const JsonType& config_){
inline std::string toReadableString(const JsonType& config_, bool shallow_){
std::stringstream ss;
ss << config_ << std::endl;

std::string originalJson = ss.str();
ss.str(""); ss.clear();
int indentLevel{0};
bool inQuote{false};
for( char c : originalJson ){

if( c == '"'){ inQuote = not inQuote; }

if( not inQuote ){
if( c == '{' or c == '[' ){
ss << std::endl << repeatString(" ", indentLevel) << c;
indentLevel++;
ss << std::endl << repeatString(" ", indentLevel);
}
else if( c == '}' or c == ']' ){
indentLevel--;
ss << std::endl << repeatString(" ", indentLevel) << c;
if(shallow_){
for (auto it = config_.begin(); it != config_.end(); ++it) {
ss << it.key() << ": ";
if (it->is_primitive()) {
ss << *it;
} else if (it->is_array()) {
ss << "[...]" << " (size=" << it->size() << ")";;
} else if (it->is_object()) {
ss << "{...}" << " (keys=" << it->size() << ")";
}
else if( c == ':' ){
ss << c << " ";
}
else if( c == ',' ){
ss << c << std::endl << repeatString(" ", indentLevel);
}
else if( c == '\n' ){
if( ss.str().back() != '\n' ) ss << c;
ss << "\n";
}
}
else {
ss << config_ << std::endl;

std::string originalJson = ss.str();
ss.str(""); ss.clear();
int indentLevel{0};
bool inQuote{false};
for( char c : originalJson ){

if( c == '"'){ inQuote = not inQuote; }

if( not inQuote ){
if( c == '{' or c == '[' ){
ss << std::endl << repeatString(" ", indentLevel) << c;
indentLevel++;
ss << std::endl << repeatString(" ", indentLevel);
}
else if( c == '}' or c == ']' ){
indentLevel--;
ss << std::endl << repeatString(" ", indentLevel) << c;
}
else if( c == ':' ){
ss << c << " ";
}
else if( c == ',' ){
ss << c << std::endl << repeatString(" ", indentLevel);
}
else if( c == '\n' ){
if( ss.str().back() != '\n' ) ss << c;
}
else{
ss << c;
}
}
else{
ss << c;
}
}
else{
ss << c;
}

}
}

return ss.str();
}

Expand Down Expand Up @@ -588,12 +614,35 @@ namespace GenericToolbox {
return json_.get<double>();
}
inline Range getImpl(const JsonType& json_, Range*){
if( not json_.is_array() ){ throw std::runtime_error("provided json is not an array."); }
if( json_.size() != 2 ){ throw std::runtime_error("Range has " + std::to_string(json_.size()) + " values (2 expected)."); }
Range out{};
out.min = get<double>(json_[0]);
out.max = get<double>(json_[1]);
if( out.min > out.max ){ std::swap(out.min, out.max); }

if( json_.is_array() ) {
if( json_.size() != 2 ){ throw std::runtime_error("Range has " + std::to_string(json_.size()) + " values (2 expected)."); }

out.min = get<double>(json_[0]);
out.max = get<double>(json_[1]);
if( out.min > out.max ){ std::swap(out.min, out.max); }
return out;
}

if( json_.is_structured() ) {
// legacy
bool oneValidKeyFound{false};

if( doKeyExist(json_, "min") ) { oneValidKeyFound=true; fillValue(json_, out.min, "min"); }
if( doKeyExist(json_, "minValue") ){ oneValidKeyFound=true; fillValue(json_, out.min, "minValue"); }

if( doKeyExist(json_, "max") ) { oneValidKeyFound=true; fillValue(json_, out.max, "max"); }
if( doKeyExist(json_, "maxValue") ){ oneValidKeyFound=true; fillValue(json_, out.max, "maxValue"); }

if( not oneValidKeyFound ) {
throw std::runtime_error("Range has no min or max value: " + toReadableString(json_));
}

return out;
}

throw std::runtime_error("Could not parse json entry as Range:" + toReadableString(json_));
return out;
}
template<typename T> std::vector<T> getImpl(const JsonType& json_, std::vector<T>*){
Expand Down
1 change: 1 addition & 0 deletions include/GenericToolbox.Os.h
Original file line number Diff line number Diff line change
Expand Up @@ -566,6 +566,7 @@ namespace GenericToolbox{
std::vector<std::string> output;
while( fgets( buffer.data(), buffer.size(), pipe.get() ) != nullptr ){
output.emplace_back( buffer.data() );
GenericToolbox::replaceSubstringInsideInputString(output.back(), "\n", "");
}
return output;
}
Expand Down
6 changes: 4 additions & 2 deletions include/GenericToolbox.Utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -422,10 +422,12 @@ namespace GenericToolbox{
[[nodiscard]] bool hasBound() const{ return hasLowerBound() or hasUpperBound(); }
[[nodiscard]] bool hasBothBounds() const{ return hasLowerBound() and hasUpperBound(); }
[[nodiscard]] bool isUnbounded() const{ return not hasBound(); }
[[nodiscard]] bool isBellowMin(double val_) const{ return (hasLowerBound() and val_ < min); }
[[nodiscard]] bool isAboveMax(double val_) const{ return (hasUpperBound() and val_ > max); }
[[nodiscard]] bool isInBounds(double val_) const{
// both bounds are inclusive [min, max]
if( hasLowerBound() and val_ < min ){ return false; }
if( hasUpperBound() and val_ > max ){ return false; }
if( isBellowMin(val_) ){ return false; }
if( isAboveMax(val_) ){ return false; }
return true;
}
[[nodiscard]] std::string toString() const{
Expand Down