23#include <unordered_map>
27#ifdef PARSNIP_DICTIONARY_SORTED
49 virtual const char *what() const noexcept
override {
55 inline const char *
where () const noexcept {
56 return location.empty() ? nullptr : location.c_str();
88 static const struct dictionary_t {
90 static const struct list_t {
95 using StringType = std::string;
96 using ListType = std::vector<Data>;
111#ifdef PARSNIP_DICTIONARY_SORTED
112 using DictionaryType = std::map<std::string, Data>;
114 using DictionaryType = std::unordered_map<std::string, Data>;
119 DictionaryType *dictionary;
131 void mandateType (
Type type)
const;
133 inline void loadDictionary(){};
136 template <
typename... More>
137 void loadDictionary (
const char *name,
Data &&value, More &&... remainder) {
138 (*(data.dictionary))[name] = std::move (value);
139 loadDictionary (std::forward<More> (remainder)...);
142 inline void loadArray(){};
145 template <
typename... More>
146 void loadArray (Data &&value, More... remainder) {
147 data.list->push_back (std::move (value));
148 loadArray (std::forward<More> (remainder)...);
152 using size_type = ListType::size_type;
155 struct iterator : std::iterator<std::forward_iterator_tag, Data> {
156 const ListType *list =
nullptr;
157 ListType::size_type position = 0;
160 const Data &operator*()
const noexcept;
163 bool operator!= (
const iterator &compare)
const noexcept;
167 Data (std::nullptr_t null =
nullptr) {
174 Data (
const char *value,
bool type_certainty =
true) {
175 data.str =
new StringType (value);
180 inline Data (
const std::string &value,
bool type_certainty =
true) {
181 data.str =
new StringType (value);
186 template <
typename T,
188 =
typename std::enable_if<!std::is_same<T, bool>::value && std::is_integral<T>::value,
int>::type>
189 inline Data (T value)
noexcept {
191 data.integer = value;
195 inline Data (
double value)
noexcept {
201 inline Data (
bool value)
noexcept {
203 data.boolean = value;
210 template <
typename... T>
212 loadDictionary (std::forward<T> (params)...);
218 template <
typename... T>
220 loadArray (std::forward<T> (params)...);
250 inline bool operator!= (
const Data &compare)
const {
258 inline bool isNull (
void)
const noexcept {
264 long asLong (
int base = 0)
const;
272 template <
typename DataType,
273 typename =
typename std::enable_if<std::is_same<DataType, std::string>::value>::type>
274 inline const std::string &
as()
const {
282 template <
typename DataType,
284 =
typename std::enable_if<!std::is_same<DataType, bool>::value && std::is_integral<DataType>::value>::type>
285 inline DataType
as (
int base = 0)
const {
286 long result =
asLong (base);
287#pragma GCC diagnostic push
288#pragma GCC diagnostic ignored "-Wsign-compare"
289 if (result < std::numeric_limits<DataType>::lowest() || result > std::numeric_limits<DataType>::max()) {
290#pragma GCC diagnostic pop
300 template <typename DataType, typename = typename std::enable_if<std::is_floating_point<DataType>::value>::type>
301 inline DataType
as()
const {
303 if (result < std::numeric_limits<DataType>::lowest() || result > std::numeric_limits<DataType>::max()) {
311 template <typename DataType, typename = typename std::enable_if<std::is_same<DataType, bool>::value>::type>
312 inline bool as()
const {
318 template <typename DataType, typename = typename std::enable_if<std::is_same<DataType, Data>::value>::type>
332 template <
typename Container,
333 typename =
typename std::enable_if<std::is_class<Container>::value && !std::is_same<Container, Data>::value
334 && !std::is_same<Container, std::string>::value>::type>
335 inline Container
as(std::nullptr_t null =
nullptr)
const {
338 for (
const auto &item : *(data.list)) {
339 result.push_back (item.as <
typename Container::value_type>());
350 template <
typename Datatype>
351 inline Datatype
getOr (
const std::string &name,
const Datatype &defvalue)
const {
352 return (
contains (name) ? (*
this)[name].as<Datatype>() : defvalue);
358 inline StringType
getOr (
const std::string &name,
const char *defvalue)
const {
359 return (
contains (name) ? (*
this)[name].
asString() : StringType (defvalue));
368 return (
contains (name) ? (*
this)[name] : defvalue);
381 template <
typename Datatype>
382 inline std::vector<Datatype>
toList ()
const {
384 return as<std::vector <Datatype>> ();
385 }
else if (
datatype == Type::Dictionary) {
388 std::vector<Datatype> results;
389 results.push_back (as <Datatype>());
396 bool contains (
const std::string &word)
const;
397 void remove (
const std::string &word);
398 inline const Data &at (
const std::string &word)
const {
399 return (*
this) [word];
409 template <typename DataType, typename = typename std::enable_if<std::is_trivial<DataType>::value>::type>
410 void foreach (std::function<
void (
const std::string &, DataType)> func)
const {
411 mandateType (Type::Dictionary);
412 for (
const auto &it : *(data.dictionary)) {
413 func (it.first, it.second.as<DataType>());
418 template <
typename DataType>
419 void foreach (std::function<
void (
const std::string &,
const DataType &)> func)
const {
420 mandateType (Type::Dictionary);
421 for (
const auto &it : *(data.dictionary)) {
422 func (it.first, it.second.as<DataType>());
429 void remove (size_type index);
432 size_type
size()
const;
441 (
datatype == Type::Dictionary && (*data.dictionary).empty()));
452 template <typename DataType, typename = typename std::enable_if<std::is_trivial<Type>::value>::type>
453 void foreach (std::function<
void (
const DataType)> func)
const {
455 for (
const auto &it : *(data.list)) {
456 func (it.as<DataType>());
461 template <
typename DataType>
462 void foreach (std::function<
void (
const DataType &)> func)
const {
464 for (
const auto &it : *(data.list)) {
465 func (it.as<DataType>());
492 template <
typename T = Data>
494 Data data (Type::Dictionary);
495 for (
auto &it : initial_data) {
496 data [it.first] = it.second;
503 template <
typename... T>
506 data.loadArray (std::forward<T> (params)...);
512 std::ostream &
toJson (std::ostream &target,
int indent =
NoIndent,
bool suppress =
false)
const;
513 std::ostream &dumpJson (
const std::string &intro, std::ostream &target = std::clog)
const;
516 Data
parse_json (std::istream &from,
bool check_termination =
true);
520#ifdef PARSNIP_JSON_TRACK_POSITION
521 class StreamPositionCounter;
522 using InputStream = StreamPositionCounter;
524 using InputStream = std::istream;
529#ifdef PARSNIP_JSON_TRACK_POSITION
533 unsigned character = 0;
534 Location () =
default;
535 Location (
const Location &) =
default;
536 Location &operator =(
const Location &) =
default;
537 Location (
unsigned l,
unsigned c): line (l), character (c) {};
540 const Location error_location {};
544 inline Location
where()
const {
545 return error_location;
569 inline std::ostream &operator<< (std::ostream &out,
const Parsnip::Data &data) {
579 Exception (
"wrong list size", std::to_string (size) +
" (expected " + std::to_string (min) +
"-" + std::to_string (max) +
"") {};
601 class SchemaBaseRef:
public std::unique_ptr<class SchemaBase, SchemaBaseDeleter> {
609 using SchemaRef = std::shared_ptr <class Schema>;
615 using OptionSchemas = std::unordered_map <class OptionParser *, SchemaRef>;
616 using Dependencies = std::set <std::string>;
617 static const Dependencies NoDependencies;
622 std::ostream &dump (std::ostream &target,
int indent,
bool suppress_indent)
const;
632 void addMember (
const char *name,
const SchemaBase &new_schema,
bool mandatory =
false,
633 const Dependencies &dependencies = NoDependencies);
634 void replaceMember (
const char *name,
const SchemaBase &new_schema);
635 void removeMember (
const char *name);
637 void validate (
const Data &)
const;
638 std::ostream &dump (
const std::string &intro, std::ostream &target = std::clog)
const;
A meta-schema that determines if any, all, or exactly one or none of its subschemas are valid.
Definition parsnip_schema.h:358
Generic data type.
Definition parsnip.h:81
static Data make_list(T &&... params)
List factory.
Definition parsnip.h:504
bool as() const
Extract data as a boolean.
Definition parsnip.h:312
DataType as() const
Extract data as a floating point type.
Definition parsnip.h:301
Data(list_t, T... params)
List constructor.
Definition parsnip.h:219
int asInteger(int base=0) const
Return value of data as an integer.
Definition parsnip_types.cpp:267
Data(dictionary_t, T... params)
Dictionary constructor.
Definition parsnip.h:211
Datatype getOr(const std::string &name, const Datatype &defvalue) const
Extract a value if a member exists, otherwise use a default.
Definition parsnip.h:351
static constexpr int NoIndent
Prevent indentation.
Definition parsnip.h:93
static const struct Parsnip::Data::dictionary_t Dictionary
Dictionary flag type/value.
const Data & operator[](const std::string &word) const
Dictionary member accessor.
Definition parsnip_types.cpp:300
void release()
Release any stored data and restore to an "empty" state.
Definition parsnip_types.cpp:112
bool empty() const
Empty check.
Definition parsnip.h:438
const std::string & as() const
Extract data as a string (templated version).
Definition parsnip.h:274
void remove(const std::string &word)
Remove key from dictionary.
Definition parsnip_types.cpp:317
ListType asList() const
Return data as a list.
Definition parsnip_types.cpp:280
double asDouble() const
Return value of data as a double. If the data is a string, parse it as a float.
Definition parsnip_types.cpp:189
Data(std::nullptr_t null=nullptr)
Default constructor.
Definition parsnip.h:167
bool contains(const std::string &word) const
Check if a key exists in a dictionary.
Definition parsnip_types.cpp:328
bool operator==(const Data &compare) const
Compare two structures.
Definition parsnip_types.cpp:143
Type
Types that may be stored in the data.
Definition parsnip.h:99
@ String
The value is string, even if the string contains a number.
@ List
Dictionary keyed by string.
@ Integer
Value is an integer but may also be accessed as a real.
@ Null
Nothing is present.
@ FlexibleString
The value is a string, but may convert to a number if the value is numeric.
StringType getOr(const std::string &name, const char *defvalue) const
Specialization of 'getOr' that accepts a const char * default; otherwise, overload resolution chooses...
Definition parsnip.h:358
bool isNull(void) const noexcept
Check if data contains a value.
Definition parsnip.h:258
static const char * type_name(Type ty)
Return the name corresponding to a type.
Definition parsnip_types.cpp:385
std::string toJson(int indent=NoIndent) const
Return serial data encoded using JSON.
Definition parsnip_json.cpp:150
Data & operator=(Data &&from) noexcept
Move assignment.
Definition parsnip.h:231
Data(bool value) noexcept
Boolean constructor.
Definition parsnip.h:201
DataType as(int base=0) const
Extract data as an integer type, except boolean.
Definition parsnip.h:285
Data(T value) noexcept
Integer constructor.
Definition parsnip.h:189
const StringType & asString() const
Retrieve string value.
Definition parsnip_types.cpp:133
Data(double value) noexcept
Floating point constructor.
Definition parsnip.h:195
Data::iterator end() const
Retrieve end iterator.
Definition parsnip.h:479
Container as(std::nullptr_t null=nullptr) const
Return contents of a list as a specific datatype.
Definition parsnip.h:335
size_type size() const
Retrieve number of entries in a list.
Definition parsnip_types.cpp:377
static Data make_dictionary(std::initializer_list< std::pair< const char *, const T > > initial_data)
Dictionary factory.
Definition parsnip.h:493
const Data & as() const
Retrieve data as the object itself.
Definition parsnip.h:319
bool asBoolean() const
Return value of data as a boolean. If the data is a string, translate "true" and "false".
Definition parsnip_types.cpp:217
Type datatype
Type presently stored in object.
Definition parsnip.h:117
static constexpr bool Flexible
Flag to make strings flexible.
Definition parsnip.h:92
Data(const char *value, bool type_certainty=true)
String constructor.
Definition parsnip.h:174
Data(Data &&from) noexcept
Move construction.
Definition parsnip.h:224
Data getOr(const std::string &name, const Data &defvalue) const
Specialization of getOr for Data.
Definition parsnip.h:367
static const struct Parsnip::Data::list_t List
List flag type/value.
Data::iterator begin() const
Retrieve forward iterator.
Definition parsnip.h:472
const Data & makeFlexible() const
IF a data item is a string, change it to a flexible string.
Definition parsnip_types.cpp:41
std::vector< Datatype > toList() const
Return a list or a single item in a container.
Definition parsnip.h:382
Data(const std::string &value, bool type_certainty=true)
String constructor, accepting C++ string.
Definition parsnip.h:180
void push_back(const Data &value)
List back-inserter.
Definition parsnip_types.cpp:363
long asLong(int base=0) const
Return value of data as a long integer.
Definition parsnip_types.cpp:238
DataRangeError indicates a value received in a stream can't be represented.
Definition parsnip.h:73
Schema component for validating dictionaries.
Definition parsnip_schema.h:307
Class representing issues related to serialization & parsing.
Definition parsnip.h:41
void addBacktraceLocation(const std::string &)
Insert a new portion of the exception location at the front.
Definition parsnip_types.cpp:23
Exception(const std::string &why)
Construct an exception.
Definition parsnip.h:61
const char * where() const noexcept
Retrieve the exception location information.
Definition parsnip.h:55
Exception(const std::string &why, const std::string &detail)
Construct an exception.
Definition parsnip.h:66
std::string reason
Storage for the exception explanation.
Definition parsnip.h:45
The data's type is inconsistent with the use requested of it.
Definition parsnip.h:560
The list size does not meet schema requirements.
Definition parsnip.h:575
They key is not specified in the schema.
Definition parsnip.h:583
An element requested from a constant dictionary does not exist.
Definition parsnip.h:554
A class for parsing command line options (name-value pairs, for instance).
Definition parsnip_command.h:82
Schema adapter component that allows use of schemas from option parsers.
Definition parsnip_schema.h:258
Definition parsnip_schema.h:28
Smart pointer for schemas, with unusual ability to be copied.
Definition parsnip.h:601
Parsing/command patterns produce schema inconsistency.
Definition parsnip.h:589
Schema for one JSON object.
Definition parsnip.h:612
Serialization and parsing library.
Definition parsnip.h:38
Data parse_json(std::istream &from, bool check_termination=true)
Parse a stream as JSON data.
Definition parsnip_json.cpp:529
An iterator used to walk items in Data's lists.
Definition parsnip.h:155
Helper functor for schema smart pointers.
Definition parsnip.h:596