MAIA bb96820c
Multiphysics at AIA
Loading...
Searching...
No Matches
cpptoml.h
Go to the documentation of this file.
1
7// Copyright (c) 2014 Chase Geigle
8//
9// Permission is hereby granted, free of charge, to any person obtaining a copy of
10// this software and associated documentation files (the "Software"), to deal in
11// the Software without restriction, including without limitation the rights to
12// use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of
13// the Software, and to permit persons to whom the Software is furnished to do so,
14// subject to the following conditions:
15//
16// The above copyright notice and this permission notice shall be included in all
17// copies or substantial portions of the Software.
18//
19// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
20// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
21// FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
22// COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
23// IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
24// CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
25
26// Note: This version of cpptoml.h is based on commit '8e1df9f48e1950b1c9da098d2c4d88ae41b3dd9c',
27// which is the current status of 'master' in https://github.com/sloede/cpptoml.git on
28// Mon Jun 4 10:43:16 CEST 2018.
29
30#ifndef _CPPTOML_H_
31#define _CPPTOML_H_
32
33#include <algorithm>
34#include <cassert>
35#include <clocale>
36#include <cstdint>
37#include <cstring>
38#include <fstream>
39#include <iomanip>
40#include <iostream>
41#include <limits>
42#include <map>
43#include <memory>
44#include <sstream>
45#include <stdexcept>
46#include <string>
47#include <unordered_map>
48#include <vector>
49#include "INCLUDE/maiamacro.h"
50#include "UTIL/functions.h"
51
52#if __cplusplus > 201103L
53#define CPPTOML_DEPRECATED(reason) [[deprecated(reason)]]
54#elif defined(__clang__)
55#define CPPTOML_DEPRECATED(reason) __attribute__((deprecated(reason)))
56#elif defined(__GNUG__)
57#define CPPTOML_DEPRECATED(reason) __attribute__((deprecated))
58#elif defined(_MSC_VER)
59#if _MSC_VER < 1910
60#define CPPTOML_DEPRECATED(reason) __declspec(deprecated)
61#else
62#define CPPTOML_DEPRECATED(reason) [[deprecated(reason)]]
63#endif
64#endif
65
66namespace cpptoml {
67class writer; // forward declaration
68class base; // forward declaration
69#if defined(CPPTOML_USE_MAP)
70// a std::map will ensure that entries a sorted, albeit at a slight
71// performance penalty relative to the (default) unordered_map
72using string_to_base_map = std::map<std::string, std::shared_ptr<base>>;
73#else
74// by default an unordered_map is used for best performance as the
75// toml specification does not require entries to be sorted
76using string_to_base_map = std::unordered_map<std::string, std::shared_ptr<base>>;
77#endif
78
79// if defined, `base` will retain type information in form of an enum class
80// such that static_cast can be used instead of dynamic_cast
81#define CPPTOML_NO_RTTI
82#define CPPTOML_NO_EXCEPTIONS
83
84#if defined(CPPTOML_NO_EXCEPTIONS)
85// if defined, exception handling will be crudely disabled
86#define THROW_(exception, reason) die(reason, __FILE__, __LINE__)
87#define THROW2_(exception, reason, input_line) die(reason, input_line, __FILE__, __LINE__)
88
89[[noreturn]] inline void die(const std::string& reason, const std::string& file, const int line) {
90 std::cerr << file << ":" << std::to_string(line) << ": error: " << reason << std::endl;
91 TERM(-1);
92}
93
94[[noreturn]] inline void die(const std::string& reason, const int input_line, const std::string& file, const int line) {
95 std::cerr << file << ":" << std::to_string(line) << ": error: " << reason << " at line " << input_line << std::endl;
96 TERM(-1);
97}
98#else
99#define THROW_(exception, reason) \
100 throw exception { reason }
101#define THROW2_(exception, reason, input_line) \
102 throw exception { reason, input_line }
103#endif
104
105template <class T>
106class option {
107 public:
108 option() : empty_{true} {
109 // nothing
110 }
111
112 option(T value) : empty_{false}, value_(std::move(value)) {
113 // nothing
114 }
115
116 explicit operator MBool() const { return !empty_; }
117
118 const T& operator*() const { return value_; }
119
120 const T* operator->() const { return &value_; }
121
122 const T& value_or(const T& alternative) const {
123 if(!empty_) return value_;
124 return alternative;
125 }
126
127 private:
130};
131
133 int year = 0;
134 int month = 0;
135 int day = 0;
136};
137
139 int hour = 0;
140 int minute = 0;
141 int second = 0;
142 int microsecond = 0;
143};
144
146 int hour_offset = 0;
148};
149
151
153 static inline offset_datetime from_zoned(const tm& t) {
155 dt.year = t.tm_year + 1900;
156 dt.month = t.tm_mon + 1;
157 dt.day = t.tm_mday;
158 dt.hour = t.tm_hour;
159 dt.minute = t.tm_min;
160 dt.second = t.tm_sec;
161
162 char buf[16];
163 strftime(buf, 16, "%z", &t);
164
165 int offset = std::stoi(buf);
166 dt.hour_offset = offset / 100;
167 dt.minute_offset = offset % 100;
168 return dt;
169 }
170
171 CPPTOML_DEPRECATED("from_local has been renamed to from_zoned")
172 static inline offset_datetime from_local(const tm& t) { return from_zoned(t); }
173
174 static inline offset_datetime from_utc(const tm& t) {
176 dt.year = t.tm_year + 1900;
177 dt.month = t.tm_mon + 1;
178 dt.day = t.tm_mday;
179 dt.hour = t.tm_hour;
180 dt.minute = t.tm_min;
181 dt.second = t.tm_sec;
182 return dt;
183 }
184};
185
186CPPTOML_DEPRECATED("datetime has been renamed to offset_datetime")
187typedef offset_datetime datetime;
188
190 public:
191 explicit fill_guard(std::ostream& os) : os_(os), fill_{os.fill()} {
192 // nothing
193 }
194
195 ~fill_guard() { os_.fill(fill_); }
196
197 private:
198 std::ostream& os_;
199 std::ostream::char_type fill_;
200};
201
202inline std::ostream& operator<<(std::ostream& os, const local_date& dt) {
203 fill_guard g{os};
204 os.fill('0');
205
206 using std::setw;
207 os << setw(4) << dt.year << "-" << setw(2) << dt.month << "-" << setw(2) << dt.day;
208
209 return os;
210}
211
212inline std::ostream& operator<<(std::ostream& os, const local_time& ltime) {
213 fill_guard g{os};
214 os.fill('0');
215
216 using std::setw;
217 os << setw(2) << ltime.hour << ":" << setw(2) << ltime.minute << ":" << setw(2) << ltime.second;
218
219 if(ltime.microsecond > 0) {
220 os << ".";
221 int power = 100000;
222 for(int curr_us = ltime.microsecond; curr_us; power /= 10) {
223 auto num = curr_us / power;
224 os << num;
225 curr_us -= num * power;
226 }
227 }
228
229 return os;
230}
231
232inline std::ostream& operator<<(std::ostream& os, const zone_offset& zo) {
233 fill_guard g{os};
234 os.fill('0');
235
236 using std::setw;
237
238 if(zo.hour_offset != 0 || zo.minute_offset != 0) {
239 if(zo.hour_offset > 0) {
240 os << "+";
241 } else {
242 os << "-";
243 }
244 os << setw(2) << std::abs(zo.hour_offset) << ":" << setw(2) << std::abs(zo.minute_offset);
245 } else {
246 os << "Z";
247 }
248
249 return os;
250}
251
252inline std::ostream& operator<<(std::ostream& os, const local_datetime& dt) {
253 return os << static_cast<const local_date&>(dt) << "T" << static_cast<const local_time&>(dt);
254}
255
256inline std::ostream& operator<<(std::ostream& os, const offset_datetime& dt) {
257 return os << static_cast<const local_datetime&>(dt) << static_cast<const zone_offset&>(dt);
258}
259
260template <class T, class... Ts>
262
263template <class T, class V>
264struct is_one_of<T, V> : std::is_same<T, V> {};
265
266template <class T, class V, class... Ts>
267struct is_one_of<T, V, Ts...> {
268 const static MBool value = std::is_same<T, V>::value || is_one_of<T, Ts...>::value;
269};
270
271template <class T>
272class value;
273
274template <class T>
276 : is_one_of<T, std::string, int64_t, double, MBool, local_date, local_time, local_datetime, offset_datetime> {};
277
278template <class T, class Enable = void>
280
281template <class T>
283 const static MBool value =
284 valid_value<typename std::decay<T>::type>::value || std::is_convertible<T, std::string>::value;
285};
286
287template <class T>
288struct value_traits<T, typename std::enable_if<valid_value_or_string_convertible<T>::value>::type> {
289 using value_type = typename std::conditional<valid_value<typename std::decay<T>::type>::value,
290 typename std::decay<T>::type, std::string>::type;
291
293
294 static value_type construct(T&& val) { return value_type(val); }
295};
296
297template <class T>
298struct value_traits<T, typename std::enable_if<!valid_value_or_string_convertible<T>::value
299 && std::is_floating_point<typename std::decay<T>::type>::value>::type> {
300 using value_type = typename std::decay<T>::type;
301
303
304 static value_type construct(T&& val) { return value_type(val); }
305};
306
307template <class T>
308struct value_traits<T, typename std::enable_if<!valid_value_or_string_convertible<T>::value
309 && std::is_signed<typename std::decay<T>::type>::value>::type> {
310 using value_type = int64_t;
311
313
314 static value_type construct(T&& val) {
315 if(val < std::numeric_limits<int64_t>::min())
316 THROW_(std::underflow_error, "constructed value cannot be "
317 "represented by a 64-bit signed "
318 "integer");
319
320 if(val > std::numeric_limits<int64_t>::max())
321 THROW_(std::overflow_error, "constructed value cannot be represented "
322 "by a 64-bit signed integer");
323
324 return static_cast<int64_t>(val);
325 }
326};
327
328template <class T>
329struct value_traits<T, typename std::enable_if<!valid_value_or_string_convertible<T>::value
330 && std::is_unsigned<typename std::decay<T>::type>::value>::type> {
331 using value_type = int64_t;
332
334
335 static value_type construct(T&& val) {
336 if(val > static_cast<uint64_t>(std::numeric_limits<int64_t>::max()))
337 THROW_(std::overflow_error, "constructed value cannot be represented "
338 "by a 64-bit signed integer");
339
340 return static_cast<int64_t>(val);
341 }
342};
343
344class array;
345class table;
346class table_array;
347
348template <class T>
351};
352
353template <>
356};
357
358template <class T>
359inline std::shared_ptr<typename value_traits<T>::type> make_value(T&& val);
360inline std::shared_ptr<array> make_array();
361template <class T>
362inline std::shared_ptr<T> make_element();
363inline std::shared_ptr<table> make_table();
364inline std::shared_ptr<table_array> make_table_array();
365
366#if defined(CPPTOML_NO_RTTI)
368enum class base_type {
369 NONE,
370 STRING,
375 INT,
376 FLOAT,
377 BOOL,
378 TABLE,
379 ARRAY,
381};
382
384template <class T>
386
387template <>
388struct base_type_traits<std::string> {
389 static const base_type type = base_type::STRING;
390};
391
392template <>
394 static const base_type type = base_type::LOCAL_TIME;
395};
396
397template <>
399 static const base_type type = base_type::LOCAL_DATE;
400};
401
402template <>
405};
406
407template <>
410};
411
412#ifdef MAIA_MS_COMPILER
413template <>
414struct base_type_traits<int> {
415 static const base_type type = base_type::INT;
416};
417#endif
418
419template <>
420struct base_type_traits<int64_t> {
421 static const base_type type = base_type::INT;
422};
423
424template <>
425struct base_type_traits<double> {
426 static const base_type type = base_type::FLOAT;
427};
428
429template <>
431 static const base_type type = base_type::BOOL;
432};
433
434template <>
436 static const base_type type = base_type::TABLE;
437};
438
439template <>
441 static const base_type type = base_type::ARRAY;
442};
443
444template <>
447};
448#endif
449
453class base : public std::enable_shared_from_this<base> {
454 public:
455 virtual ~base() = default;
456
457 virtual std::shared_ptr<base> clone() const = 0;
458
462 virtual MBool is_value() const { return false; }
463
467 virtual MBool is_table() const { return false; }
468
472 std::shared_ptr<table> as_table() {
473 if(is_table()) return std::static_pointer_cast<table>(shared_from_this());
474 return nullptr;
475 }
479 virtual MBool is_array() const { return false; }
480
484 std::shared_ptr<array> as_array() {
485 if(is_array()) return std::static_pointer_cast<array>(shared_from_this());
486 return nullptr;
487 }
488
492 virtual MBool is_table_array() const { return false; }
493
497 std::shared_ptr<table_array> as_table_array() {
498 if(is_table_array()) return std::static_pointer_cast<table_array>(shared_from_this());
499 return nullptr;
500 }
501
506 template <class T>
507 std::shared_ptr<value<T>> as();
508
509 template <class T>
510 std::shared_ptr<const value<T>> as() const;
511
512 template <class Visitor, class... Args>
513 void accept(Visitor&& visitor, Args&&... args) const;
514
515#if defined(CPPTOML_NO_RTTI)
516 base_type type() const { return type_; }
517
518 protected:
519 explicit base(const base_type t) : type_(t) {
520 // nothing
521 }
522
523 private:
525
526#else
527 protected:
529 // nothing
530 }
531#endif
532};
533
537template <class T>
538class value : public base {
540 // nothing; this is a private key accessible only to friends
541 };
542
543 template <class U>
544 friend std::shared_ptr<typename value_traits<U>::type> cpptoml::make_value(U&& val);
545
546 public:
547#ifndef MAIA_MS_COMPILER
548 static_assert(valid_value<T>::value, "invalid value type");
549#endif
550
551 std::shared_ptr<base> clone() const override;
552
553 value(const make_shared_enabler&, const T& val) : value(val) {
554 // nothing; note that users cannot actually invoke this function
555 // because they lack access to the make_shared_enabler.
556 }
557
558 MBool is_value() const override { return true; }
559
563 T& get() { return data_; }
564
568 const T& get() const { return data_; }
569
570 private:
572
576#if defined(CPPTOML_NO_RTTI)
577 explicit value(const T& val) : base(base_type_traits<T>::type), data_(val) {}
578#else
579 explicit value(const T& val) : data_(val) {}
580#endif
581
582 public:
583 value(const value& val) = delete;
584 value& operator=(const value& val) = delete;
585};
586
587template <class T>
588std::shared_ptr<typename value_traits<T>::type> make_value(T&& val) {
589 using value_type = typename value_traits<T>::type;
590 using enabler = typename value_type::make_shared_enabler;
591 return std::make_shared<value_type>(enabler{}, value_traits<T>::construct(std::forward<T>(val)));
592}
593
594template <class T>
595inline std::shared_ptr<value<T>> base::as() {
596#if defined(CPPTOML_NO_RTTI)
598 return std::static_pointer_cast<value<T>>(shared_from_this());
599 else
600 return nullptr;
601#else
602 return std::dynamic_pointer_cast<value<T>>(shared_from_this());
603#endif
604}
605
606// special case value<double> to allow getting an integer parameter as a
607// double value
608template <>
609inline std::shared_ptr<value<double>> base::as() {
610#if defined(CPPTOML_NO_RTTI)
611 if(type() == base_type::FLOAT) return std::static_pointer_cast<value<double>>(shared_from_this());
612
613 if(type() == base_type::INT) {
614 auto v = std::static_pointer_cast<value<int64_t>>(shared_from_this());
615 return make_value<double>(static_cast<double>(v->get()));
616 }
617#else
618 if(auto v = std::dynamic_pointer_cast<value<double>>(shared_from_this())) return v;
619
620 if(auto v = std::dynamic_pointer_cast<value<int64_t>>(shared_from_this()))
621 return make_value<double>(static_cast<double>(v->get()));
622#endif
623
624 return nullptr;
625}
626
627template <class T>
628inline std::shared_ptr<const value<T>> base::as() const {
629#if defined(CPPTOML_NO_RTTI)
631 return std::static_pointer_cast<const value<T>>(shared_from_this());
632 else
633 return nullptr;
634#else
635 return std::dynamic_pointer_cast<const value<T>>(shared_from_this());
636#endif
637}
638
639// special case value<double> to allow getting an integer parameter as a
640// double value
641template <>
642inline std::shared_ptr<const value<double>> base::as() const {
643#if defined(CPPTOML_NO_RTTI)
644 if(type() == base_type::FLOAT) return std::static_pointer_cast<const value<double>>(shared_from_this());
645
646 if(type() == base_type::INT) {
647 auto v = as<int64_t>();
648 // labels:IO the below has to be a non-const value<double> due to a bug in
649 // libc++: https://llvm.org/bugs/show_bug.cgi?id=18843
650 return make_value<double>(static_cast<double>(v->get()));
651 }
652#else
653 if(auto v = std::dynamic_pointer_cast<const value<double>>(shared_from_this())) return v;
654
655 if(auto v = as<int64_t>()) {
656 // labels:IO the below has to be a non-const value<double> due to a bug in
657 // libc++: https://llvm.org/bugs/show_bug.cgi?id=18843
658 return make_value<double>(static_cast<double>(v->get()));
659 }
660#endif
661
662 return nullptr;
663}
664
668class array_exception : public std::runtime_error {
669 public:
670 explicit array_exception(const std::string& err) : std::runtime_error{err} {}
671};
672
673class array : public base {
674 public:
675 friend std::shared_ptr<array> make_array();
676
677 std::shared_ptr<base> clone() const override;
678
679 MBool is_array() const override { return true; }
680
681 using size_type = std::size_t;
682
686 using iterator = std::vector<std::shared_ptr<base>>::iterator;
687
691 using const_iterator = std::vector<std::shared_ptr<base>>::const_iterator;
692
693 iterator begin() { return values_.begin(); }
694
695 const_iterator begin() const { return values_.begin(); }
696
697 iterator end() { return values_.end(); }
698
699 const_iterator end() const { return values_.end(); }
700
704 std::vector<std::shared_ptr<base>>& get() { return values_; }
705
709 const std::vector<std::shared_ptr<base>>& get() const { return values_; }
710
711 std::shared_ptr<base> at(size_t idx) const { return values_.at(idx); }
712
717 template <class T>
718 std::vector<std::shared_ptr<value<T>>> array_of() const {
719 std::vector<std::shared_ptr<value<T>>> result(values_.size());
720
721 std::transform(values_.begin(), values_.end(), result.begin(),
722 [&](const std::shared_ptr<base>& v) { return v->as<T>(); });
723
724 return result;
725 }
726
731 template <class T>
733 std::vector<T> result;
734 result.reserve(values_.size());
735
736 for(const auto& val : values_) {
737 if(auto v = val->as<T>())
738 result.push_back(v->get());
739 else
740 return {};
741 }
742
743 return {std::move(result)};
744 }
745
750 std::vector<std::shared_ptr<array>> nested_array() const {
751 std::vector<std::shared_ptr<array>> result(values_.size());
752
753 std::transform(values_.begin(), values_.end(), result.begin(),
754 [&](const std::shared_ptr<base>& v) -> std::shared_ptr<array> {
755 if(v->is_array()) return std::static_pointer_cast<array>(v);
756 return std::shared_ptr<array>{};
757 });
758
759 return result;
760 }
761
765 template <class T>
766 void push_back(const std::shared_ptr<value<T>>& val) {
767 if(values_.empty() || values_[0]->as<T>()) {
768 values_.push_back(val);
769 } else {
770 THROW_(array_exception, "Arrays must be homogenous.");
771 }
772 }
773
777 void push_back(const std::shared_ptr<array>& val) {
778 if(values_.empty() || values_[0]->is_array()) {
779 values_.push_back(val);
780 } else {
781 THROW_(array_exception, "Arrays must be homogenous.");
782 }
783 }
784
789 template <class T>
790 void push_back(T&& val, typename value_traits<T>::type* = 0) {
791 push_back(make_value(std::forward<T>(val)));
792 }
793
797 template <class T>
798 iterator insert(iterator position, const std::shared_ptr<value<T>>& value) {
799 if(values_.empty() || values_[0]->as<T>()) {
800 return values_.insert(position, value);
801 } else {
802 THROW_(array_exception, "Arrays must be homogenous.");
803 }
804 }
805
809 iterator insert(iterator position, const std::shared_ptr<array>& value) {
810 if(values_.empty() || values_[0]->is_array()) {
811 return values_.insert(position, value);
812 } else {
813 THROW_(array_exception, "Arrays must be homogenous.");
814 }
815 }
816
820 template <class T>
821 iterator insert(iterator position, T&& val, typename value_traits<T>::type* = 0) {
822 return insert(position, make_value(std::forward<T>(val)));
823 }
824
828 iterator erase(iterator position) { return values_.erase(position); }
829
833 void clear() { values_.clear(); }
834
838 void reserve(size_type n) { values_.reserve(n); }
839
840#if not defined(MAIA_INTEL_COMPILER) and not defined(MAIA_PGI_COMPILER)
841 private:
842#endif
843#if defined(CPPTOML_NO_RTTI)
845 // empty
846 }
847#else
848 array() = default;
849#endif
850
851 template <class InputIterator>
852 array(InputIterator begin, InputIterator end) : values_{begin, end} {
853 // nothing
854 }
855
856 public:
857 array(const array& obj) = delete;
858 array& operator=(const array& obj) = delete;
859
860 private:
861 std::vector<std::shared_ptr<base>> values_;
862};
863
864#if defined(MAIA_INTEL_COMPILER)
865namespace ARRAY_ {
867 public:
869};
870} // namespace ARRAY_
871#endif
872
873inline std::shared_ptr<array> make_array() {
874#if not defined(MAIA_INTEL_COMPILER)
875 struct make_shared_enabler : public array {
876 make_shared_enabler() = default;
877 };
878
879 return std::make_shared<make_shared_enabler>();
880#else
881 return std::make_shared<ARRAY_::make_shared_enabler>();
882#endif
883}
884
885template <>
886inline std::shared_ptr<array> make_element<array>() {
887 return make_array();
888}
889
894template <>
895inline typename array_of_trait<array>::return_type array::get_array_of<array>() const {
896 std::vector<std::shared_ptr<array>> result;
897 result.reserve(values_.size());
898
899 for(const auto& val : values_) {
900 if(auto v = val->as_array())
901 result.push_back(v);
902 else
903 return {};
904 }
905
906 return {std::move(result)};
907}
908
909class table;
910
911class table_array : public base {
912 friend class table;
913 friend std::shared_ptr<table_array> make_table_array();
914
915 public:
916 std::shared_ptr<base> clone() const override;
917
918 using size_type = std::size_t;
919
923 using iterator = std::vector<std::shared_ptr<table>>::iterator;
924
928 using const_iterator = std::vector<std::shared_ptr<table>>::const_iterator;
929
930 iterator begin() { return array_.begin(); }
931
932 const_iterator begin() const { return array_.begin(); }
933
934 iterator end() { return array_.end(); }
935
936 const_iterator end() const { return array_.end(); }
937
938 MBool is_table_array() const override { return true; }
939
940 std::vector<std::shared_ptr<table>>& get() { return array_; }
941
942 const std::vector<std::shared_ptr<table>>& get() const { return array_; }
943
947 void push_back(const std::shared_ptr<table>& val) { array_.push_back(val); }
948
952 iterator insert(iterator position, const std::shared_ptr<table>& value) { return array_.insert(position, value); }
953
957 iterator erase(iterator position) { return array_.erase(position); }
958
962 void clear() { array_.clear(); }
963
967 void reserve(size_type n) { array_.reserve(n); }
968
969#if not defined(MAIA_INTEL_COMPILER) and not defined(MAIA_PGI_COMPILER)
970 private:
971#endif
972#if defined(CPPTOML_NO_RTTI)
974 // nothing
975 }
976#else
978 // nothing
979 }
980#endif
981
982 public:
983 table_array(const table_array& obj) = delete;
984 table_array& operator=(const table_array& rhs) = delete;
985
986 private:
987 std::vector<std::shared_ptr<table>> array_;
988};
989
990#if defined(MAIA_INTEL_COMPILER)
991namespace TABLE_ARRAY_ {
993 public:
995};
996} // namespace TABLE_ARRAY_
997#endif
998
999inline std::shared_ptr<table_array> make_table_array() {
1000#if not defined(MAIA_INTEL_COMPILER)
1001 struct make_shared_enabler : public table_array {
1002 make_shared_enabler() = default;
1003 };
1004
1005 return std::make_shared<make_shared_enabler>();
1006#else
1007 return std::make_shared<TABLE_ARRAY_::make_shared_enabler>();
1008#endif
1009}
1010
1011template <>
1012inline std::shared_ptr<table_array> make_element<table_array>() {
1013 return make_table_array();
1014}
1015
1016// The below are overloads for fetching specific value types out of a value
1017// where special casting behavior (like bounds checking) is desired
1018
1019template <class T>
1020typename std::enable_if<!std::is_floating_point<T>::value && std::is_signed<T>::value, option<T>>::type
1021get_impl(const std::shared_ptr<base>& elem) {
1022 if(auto v = elem->as<int64_t>()) {
1023 if(v->get() < std::numeric_limits<T>::min())
1024 THROW_(std::underflow_error, "T cannot represent the value requested in get");
1025
1026 if(v->get() > std::numeric_limits<T>::max())
1027 THROW_(std::overflow_error, "T cannot represent the value requested in get");
1028
1029 return {static_cast<T>(v->get())};
1030 } else {
1031 return {};
1032 }
1033}
1034
1035template <class T>
1036typename std::enable_if<!std::is_same<T, MBool>::value && std::is_unsigned<T>::value, option<T>>::type
1037get_impl(const std::shared_ptr<base>& elem) {
1038 if(auto v = elem->as<int64_t>()) {
1039 if(v->get() < 0) THROW_(std::underflow_error, "T cannot store negative value in get");
1040
1041 if(static_cast<uint64_t>(v->get()) > std::numeric_limits<T>::max())
1042 THROW_(std::overflow_error, "T cannot represent the value requested in get");
1043
1044 return {static_cast<T>(v->get())};
1045 } else {
1046 return {};
1047 }
1048}
1049
1050template <class T>
1051typename std::enable_if<!std::is_integral<T>::value || std::is_same<T, MBool>::value, option<T>>::type
1052get_impl(const std::shared_ptr<base>& elem) {
1053 if(auto v = elem->as<T>()) {
1054 return {v->get()};
1055 } else {
1056 return {};
1057 }
1058}
1059
1063class table : public base {
1064 public:
1065 friend class table_array;
1066 friend std::shared_ptr<table> make_table();
1067
1068 std::shared_ptr<base> clone() const override;
1069
1073 using iterator = string_to_base_map::iterator;
1074
1078 using const_iterator = string_to_base_map::const_iterator;
1079
1080 iterator begin() { return map_.begin(); }
1081
1082 const_iterator begin() const { return map_.begin(); }
1083
1084 iterator end() { return map_.end(); }
1085
1086 const_iterator end() const { return map_.end(); }
1087
1088 MBool is_table() const override { return true; }
1089
1090 MBool empty() const { return map_.empty(); }
1091
1095 MBool contains(const std::string& key) const { return map_.find(key) != map_.end(); }
1096
1102 MBool contains_qualified(const std::string& key) const { return resolve_qualified(key); }
1103
1108 std::shared_ptr<base> get(const std::string& key) const { return map_.at(key); }
1109
1117 std::shared_ptr<base> get_qualified(const std::string& key) const {
1118 std::shared_ptr<base> p;
1119 resolve_qualified(key, &p);
1120 return p;
1121 }
1122
1126 std::shared_ptr<table> get_table(const std::string& key) const {
1127 if(contains(key) && get(key)->is_table()) return std::static_pointer_cast<table>(get(key));
1128 return nullptr;
1129 }
1130
1135 std::shared_ptr<table> get_table_qualified(const std::string& key) const {
1136 if(contains_qualified(key) && get_qualified(key)->is_table())
1137 return std::static_pointer_cast<table>(get_qualified(key));
1138 return nullptr;
1139 }
1140
1144 std::shared_ptr<array> get_array(const std::string& key) const {
1145 if(!contains(key)) return nullptr;
1146 return get(key)->as_array();
1147 }
1148
1152 std::shared_ptr<array> get_array_qualified(const std::string& key) const {
1153 if(!contains_qualified(key)) return nullptr;
1154 return get_qualified(key)->as_array();
1155 }
1156
1160 std::shared_ptr<table_array> get_table_array(const std::string& key) const {
1161 if(!contains(key)) return nullptr;
1162 return get(key)->as_table_array();
1163 }
1164
1169 std::shared_ptr<table_array> get_table_array_qualified(const std::string& key) const {
1170 if(!contains_qualified(key)) return nullptr;
1171 return get_qualified(key)->as_table_array();
1172 }
1173
1178 template <class T>
1179 option<T> get_as(const std::string& key) const {
1180#ifndef CPPTOML_NO_EXCEPTIONS
1181 try {
1182 return get_impl<T>(get(key));
1183 } catch(const std::out_of_range&) {
1184 return {};
1185 }
1186#else
1187 if(contains(key)) {
1188 return get_impl<T>(get(key));
1189 } else {
1190 return {};
1191 }
1192#endif
1193 }
1194
1200 template <class T>
1201 option<T> get_qualified_as(const std::string& key) const {
1202#ifndef CPPTOML_NO_EXCEPTIONS
1203 try {
1204 return get_impl<T>(get_qualified(key));
1205 } catch(const std::out_of_range&) {
1206 return {};
1207 }
1208#else
1209 if(contains_qualified(key)) {
1210 return get_impl<T>(get_qualified(key));
1211 } else {
1212 return {};
1213 }
1214#endif
1215 }
1216
1226 template <class T>
1227 inline typename array_of_trait<T>::return_type get_array_of(const std::string& key) const {
1228 if(auto v = get_array(key)) {
1229 std::vector<T> result;
1230 result.reserve(v->get().size());
1231
1232 for(const auto& b : v->get()) {
1233 if(auto val = b->as<T>())
1234 result.push_back(val->get());
1235 else
1236 return {};
1237 }
1238 return {std::move(result)};
1239 }
1240
1241 return {};
1242 }
1243
1254 template <class T>
1255 inline typename array_of_trait<T>::return_type get_qualified_array_of(const std::string& key) const {
1256 if(auto v = get_array_qualified(key)) {
1257 std::vector<T> result;
1258 result.reserve(v->get().size());
1259
1260 for(const auto& b : v->get()) {
1261 if(auto val = b->as<T>())
1262 result.push_back(val->get());
1263 else
1264 return {};
1265 }
1266 return {std::move(result)};
1267 }
1268
1269 return {};
1270 }
1271
1275 void insert(const std::string& key, const std::shared_ptr<base>& value) { map_[key] = value; }
1276
1281 template <class T>
1282 void insert(const std::string& key, T&& val, typename value_traits<T>::type* = 0) {
1283 insert(key, make_value(std::forward<T>(val)));
1284 }
1285
1289 void erase(const std::string& key) { map_.erase(key); }
1290
1291#if not defined(MAIA_INTEL_COMPILER) and not defined(MAIA_PGI_COMPILER)
1292 private:
1293#endif
1294#if defined(CPPTOML_NO_RTTI)
1296 // nothing
1297 }
1298#else
1300 // nothing
1301 }
1302#endif
1303
1304 public:
1305 table(const table& obj) = delete;
1306 table& operator=(const table& rhs) = delete;
1307
1308 private:
1309 std::vector<std::string> split(const std::string& value, char separator) const {
1310 std::vector<std::string> result;
1311 std::string::size_type p = 0;
1312 std::string::size_type q;
1313 while((q = value.find(separator, p)) != std::string::npos) {
1314 result.emplace_back(value, p, q - p);
1315 p = q + 1;
1316 }
1317 result.emplace_back(value, p);
1318 return result;
1319 }
1320
1321 // If output parameter p is specified, fill it with the pointer to the
1322 // specified entry and throw std::out_of_range if it couldn't be found.
1323 //
1324 // Otherwise, just return true if the entry could be found or false
1325 // otherwise and do not throw.
1326 MBool resolve_qualified(const std::string& key, std::shared_ptr<base>* p = nullptr) const {
1327 auto parts = split(key, '.');
1328 auto last_key = parts.back();
1329 parts.pop_back();
1330
1331 auto cur_table = this;
1332 for(const auto& part : parts) {
1333 cur_table = cur_table->get_table(part).get();
1334 if(!cur_table) {
1335#ifndef CPPTOML_NO_EXCEPTIONS
1336 if(!p) return false;
1337
1338 throw std::out_of_range{key + " is not a valid key"};
1339#else
1340 return false;
1341#endif
1342 }
1343 }
1344
1345 if(!p) return cur_table->map_.count(last_key) != 0;
1346
1347 *p = cur_table->map_.at(last_key);
1348 return true;
1349 }
1350
1352};
1353
1363template <>
1364inline typename array_of_trait<array>::return_type table::get_array_of<array>(const std::string& key) const {
1365 if(auto v = get_array(key)) {
1366 std::vector<std::shared_ptr<array>> result;
1367 result.reserve(v->get().size());
1368
1369 for(const auto& b : v->get()) {
1370 if(auto val = b->as_array())
1371 result.push_back(val);
1372 else
1373 return {};
1374 }
1375
1376 return {std::move(result)};
1377 }
1378
1379 return {};
1380}
1381
1391template <>
1392inline typename array_of_trait<array>::return_type table::get_qualified_array_of<array>(const std::string& key) const {
1393 if(auto v = get_array_qualified(key)) {
1394 std::vector<std::shared_ptr<array>> result;
1395 result.reserve(v->get().size());
1396
1397 for(const auto& b : v->get()) {
1398 if(auto val = b->as_array())
1399 result.push_back(val);
1400 else
1401 return {};
1402 }
1403
1404 return {std::move(result)};
1405 }
1406
1407 return {};
1408}
1409
1410#if defined(MAIA_INTEL_COMPILER)
1412 public:
1414};
1415#endif
1416
1417std::shared_ptr<table> make_table() {
1418#if not defined(MAIA_INTEL_COMPILER)
1419 struct make_shared_enabler : public table {
1420 make_shared_enabler() = default;
1421 };
1422#endif
1423
1424 return std::make_shared<make_shared_enabler>();
1425}
1426
1427template <>
1428inline std::shared_ptr<table> make_element<table>() {
1429 return make_table();
1430}
1431
1432template <class T>
1433std::shared_ptr<base> value<T>::clone() const {
1434 return make_value(data_);
1435}
1436
1437inline std::shared_ptr<base> array::clone() const {
1438 auto result = make_array();
1439 result->reserve(values_.size());
1440 for(const auto& ptr : values_)
1441 result->values_.push_back(ptr->clone());
1442 return result;
1443}
1444
1445inline std::shared_ptr<base> table_array::clone() const {
1446 auto result = make_table_array();
1447 result->reserve(array_.size());
1448 for(const auto& ptr : array_)
1449 result->array_.push_back(ptr->clone()->as_table());
1450 return result;
1451}
1452
1453inline std::shared_ptr<base> table::clone() const {
1454 auto result = make_table();
1455 for(const auto& pr : map_)
1456 result->insert(pr.first, pr.second->clone());
1457 return result;
1458}
1459
1463class parse_exception : public std::runtime_error {
1464 public:
1465 parse_exception(const std::string& err) : std::runtime_error{err} {}
1466
1467 parse_exception(const std::string& err, std::size_t line_number)
1468 : std::runtime_error{err + " at line " + std::to_string(line_number)} {}
1469};
1470
1471inline MBool is_number(char c) { return c >= '0' && c <= '9'; }
1472
1476template <class OnError>
1478 public:
1479 consumer(std::string::iterator& it, const std::string::iterator& end, OnError&& on_error)
1480 : it_(it), end_(end), on_error_(std::forward<OnError>(on_error)) {
1481 // nothing
1482 }
1483
1484 void operator()(char c) {
1485 if(it_ == end_ || *it_ != c) on_error_();
1486 ++it_;
1487 }
1488
1489 template <std::size_t N>
1490 void operator()(const char (&str)[N]) {
1491 std::for_each(std::begin(str), std::end(str) - 1, [&](char c) { (*this)(c); });
1492 }
1493
1494 int eat_digits(int len) {
1495 int val = 0;
1496 for(int i = 0; i < len; ++i) {
1497 if(!is_number(*it_) || it_ == end_) on_error_();
1498 val = 10 * val + (*it_++ - '0');
1499 }
1500 return val;
1501 }
1502
1503 void error() { on_error_(); }
1504
1505 private:
1506 std::string::iterator& it_;
1507 const std::string::iterator& end_;
1508 OnError on_error_;
1509};
1510
1511template <class OnError>
1512consumer<OnError> make_consumer(std::string::iterator& it, const std::string::iterator& end, OnError&& on_error) {
1513 return consumer<OnError>(it, end, std::forward<OnError>(on_error));
1514}
1515
1516// replacement for std::getline to handle incorrectly line-ended files
1517// https://stackoverflow.com/questions/6089231/getting-std-ifstream-to-handle-lf-cr-and-crlf
1518namespace detail {
1519inline std::istream& getline(std::istream& input, std::string& line) {
1520 line.clear();
1521
1522 std::istream::sentry sentry{input, true};
1523 auto sb = input.rdbuf();
1524
1525 while(true) {
1526 auto c = sb->sbumpc();
1527 if(c == '\r') {
1528 if(sb->sgetc() == '\n') c = sb->sbumpc();
1529 }
1530
1531 if(c == '\n') return input;
1532
1533 if(c == std::istream::traits_type::eof()) {
1534 if(line.empty()) input.setstate(std::ios::eofbit);
1535 return input;
1536 }
1537
1538 line.push_back(static_cast<char>(c));
1539 }
1540}
1541} // namespace detail
1542
1546class parser {
1547 public:
1551 explicit parser(std::istream& stream) : input_(stream) {
1552 // nothing
1553 }
1554
1555 parser& operator=(const parser& parser) = delete;
1556
1561 std::shared_ptr<table> parse() {
1562 std::shared_ptr<table> root = make_table();
1563
1564 table* curr_table = root.get();
1565
1566 while(detail::getline(input_, line_)) {
1567 line_number_++;
1568 auto it = line_.begin();
1569 auto end = line_.end();
1570 consume_whitespace(it, end);
1571 if(it == end || *it == '#') continue;
1572 if(*it == '[') {
1573 curr_table = root.get();
1574 parse_table(it, end, curr_table);
1575 } else {
1576 parse_key_value(it, end, curr_table);
1577 consume_whitespace(it, end);
1578 eol_or_comment(it, end);
1579 }
1580 }
1581 return root;
1582 }
1583
1584 private:
1585#if defined _MSC_VER
1586 __declspec(noreturn)
1587#elif defined __GNUC__
1588 __attribute__((noreturn))
1589#endif
1590 void throw_parse_exception(const std::string& err) {
1591 THROW2_(parse_exception, err, line_number_);
1592 }
1593
1594 void parse_table(std::string::iterator& it, const std::string::iterator& end, table*& curr_table) {
1595 // remove the beginning keytable marker
1596 ++it;
1597 if(it == end) throw_parse_exception("Unexpected end of table");
1598 if(*it == '[')
1599 parse_table_array(it, end, curr_table);
1600 else
1601 parse_single_table(it, end, curr_table);
1602 }
1603
1604 void parse_single_table(std::string::iterator& it, const std::string::iterator& end, table*& curr_table) {
1605 if(it == end || *it == ']') throw_parse_exception("Table name cannot be empty");
1606
1607 std::string full_table_name;
1608 MBool inserted = false;
1609
1610 auto key_end = [](char c) { return c == ']'; };
1611
1612 auto key_part_handler = [&](const std::string& part) {
1613 if(part.empty()) throw_parse_exception("Empty component of table name");
1614
1615 if(!full_table_name.empty()) full_table_name += '.';
1616 full_table_name += part;
1617
1618 if(curr_table->contains(part)) {
1619 // Necessary fix for PGI compiler
1620 // auto b = curr_table->get(part);
1621 std::shared_ptr<base> b = curr_table->get(part);
1622 if(b->is_table())
1623 curr_table = static_cast<table*>(b.get());
1624 else if(b->is_table_array())
1625 curr_table = std::static_pointer_cast<table_array>(b)->get().back().get();
1626 else
1627 throw_parse_exception("Key " + full_table_name + "already exists as a value");
1628 } else {
1629 inserted = true;
1630 curr_table->insert(part, make_table());
1631 curr_table = static_cast<table*>(curr_table->get(part).get());
1632 }
1633 };
1634
1635 key_part_handler(parse_key(it, end, key_end, key_part_handler));
1636
1637 if(it == end) throw_parse_exception("Unterminated table declaration; did you forget a ']'?");
1638
1639 if(*it != ']') {
1640 std::string errmsg{"Unexpected character in table definition: "};
1641 errmsg += '"';
1642 errmsg += *it;
1643 errmsg += '"';
1644 throw_parse_exception(errmsg);
1645 }
1646
1647 // table already existed
1648 if(!inserted) {
1649 auto is_value = [](const std::pair<const std::string&, const std::shared_ptr<base>&>& p) {
1650 return p.second->is_value();
1651 };
1652
1653 // if there are any values, we can't add values to this table
1654 // since it has already been defined. If there aren't any
1655 // values, then it was implicitly created by something like
1656 // [a.b]
1657 if(curr_table->empty() || std::any_of(curr_table->begin(), curr_table->end(), is_value)) {
1658 throw_parse_exception("Redefinition of table " + full_table_name);
1659 }
1660 }
1661
1662 ++it;
1663 consume_whitespace(it, end);
1664 eol_or_comment(it, end);
1665 }
1666
1667 void parse_table_array(std::string::iterator& it, const std::string::iterator& end, table*& curr_table) {
1668 ++it;
1669 if(it == end || *it == ']') throw_parse_exception("Table array name cannot be empty");
1670
1671 auto key_end = [](char c) { return c == ']'; };
1672
1673
1674 std::string full_ta_name;
1675 auto key_part_handler = [&](const std::string& part) {
1676 if(part.empty()) throw_parse_exception("Empty component of table array name");
1677
1678 if(!full_ta_name.empty()) full_ta_name += '.';
1679 full_ta_name += part;
1680
1681 if(curr_table->contains(part)) {
1682 // Necessary fix for PGI compiler
1683 // auto b = curr_table->get(part);
1684 std::shared_ptr<base> b = curr_table->get(part);
1685
1686 // if this is the end of the table array name, add an
1687 // element to the table array that we just looked up
1688 if(it != end && *it == ']') {
1689 if(!b->is_table_array()) throw_parse_exception("Key " + full_ta_name + " is not a table array");
1690 auto v = b->as_table_array();
1691 v->get().push_back(make_table());
1692 curr_table = v->get().back().get();
1693 }
1694 // otherwise, just keep traversing down the key name
1695 else {
1696 if(b->is_table())
1697 curr_table = static_cast<table*>(b.get());
1698 else if(b->is_table_array())
1699 curr_table = std::static_pointer_cast<table_array>(b)->get().back().get();
1700 else
1701 throw_parse_exception("Key " + full_ta_name + " already exists as a value");
1702 }
1703 } else {
1704 // if this is the end of the table array name, add a new
1705 // table array and a new table inside that array for us to
1706 // add keys to next
1707 if(it != end && *it == ']') {
1708 curr_table->insert(part, make_table_array());
1709 auto arr = std::static_pointer_cast<table_array>(curr_table->get(part));
1710 arr->get().push_back(make_table());
1711 curr_table = arr->get().back().get();
1712 }
1713 // otherwise, create the implicitly defined table and move
1714 // down to it
1715 else {
1716 curr_table->insert(part, make_table());
1717 curr_table = static_cast<table*>(curr_table->get(part).get());
1718 }
1719 }
1720 };
1721
1722 key_part_handler(parse_key(it, end, key_end, key_part_handler));
1723
1724 // consume the last "]]"
1725 auto eat = make_consumer(it, end, [this]() { throw_parse_exception("Unterminated table array name"); });
1726 eat(']');
1727 eat(']');
1728
1729 consume_whitespace(it, end);
1730 eol_or_comment(it, end);
1731 }
1732
1733 void parse_key_value(std::string::iterator& it, std::string::iterator& end, table* curr_table) {
1734 auto key_end = [](char c) { return c == '='; };
1735
1736 auto key_part_handler = [&](const std::string& part) {
1737 // two cases: this key part exists already, in which case it must
1738 // be a table, or it doesn't exist in which case we must create
1739 // an implicitly defined table
1740 if(curr_table->contains(part)) {
1741 auto val = curr_table->get(part);
1742 if(val->is_table()) {
1743 curr_table = static_cast<table*>(val.get());
1744 } else {
1745 throw_parse_exception("Key " + part + " already exists as a value");
1746 }
1747 } else {
1748 auto newtable = make_table();
1749 curr_table->insert(part, newtable);
1750 curr_table = newtable.get();
1751 }
1752 };
1753
1754 auto key = parse_key(it, end, key_end, key_part_handler);
1755
1756 if(curr_table->contains(key)) throw_parse_exception("Key " + key + " already present");
1757 if(it == end || *it != '=') throw_parse_exception("Value must follow after a '='");
1758 ++it;
1759 consume_whitespace(it, end);
1760 curr_table->insert(key, parse_value(it, end));
1761 consume_whitespace(it, end);
1762 }
1763
1764 template <class KeyEndFinder, class KeyPartHandler>
1765 std::string parse_key(std::string::iterator& it, const std::string::iterator& end, KeyEndFinder&& key_end,
1766 KeyPartHandler&& key_part_handler) {
1767 // parse the key as a series of one or more simple-keys joined with '.'
1768 while(it != end && !key_end(*it)) {
1769 auto part = parse_simple_key(it, end);
1770 consume_whitespace(it, end);
1771
1772 if(it == end || key_end(*it)) {
1773 return part;
1774 }
1775
1776 if(*it != '.') {
1777 std::string errmsg{"Unexpected character in key: "};
1778 errmsg += '"';
1779 errmsg += *it;
1780 errmsg += '"';
1781 throw_parse_exception(errmsg);
1782 }
1783
1784 key_part_handler(part);
1785
1786 // consume the dot
1787 ++it;
1788 }
1789
1790 throw_parse_exception("Unexpected end of key");
1791 }
1792
1793 std::string parse_simple_key(std::string::iterator& it, const std::string::iterator& end) {
1794 consume_whitespace(it, end);
1795
1796
1797 if(it == end) throw_parse_exception("Unexpected end of key (blank key?)");
1798
1799 if(*it == '"' || *it == '\'') {
1800 return string_literal(it, end, *it);
1801 } else {
1802 auto bke = std::find_if(it, end, [](char c) { return c == '.' || c == '=' || c == ']'; });
1803 return parse_bare_key(it, bke);
1804 }
1805 }
1806
1807
1808 std::string parse_bare_key(std::string::iterator& it, const std::string::iterator& end) {
1809 if(it == end) {
1810 throw_parse_exception("Bare key missing name");
1811 }
1812
1813 auto key_end = end;
1814 --key_end;
1815 consume_backwards_whitespace(key_end, it);
1816 ++key_end;
1817 std::string key{it, key_end};
1818
1819 if(std::find(it, key_end, '#') != key_end) {
1820 throw_parse_exception("Bare key " + key + " cannot contain #");
1821 }
1822
1823 if(std::find_if(it, key_end, [](char c) { return c == ' ' || c == '\t'; }) != key_end) {
1824 throw_parse_exception("Bare key " + key + " cannot contain whitespace");
1825 }
1826
1827 if(std::find_if(it, key_end, [](char c) { return c == '[' || c == ']'; }) != key_end) {
1828 throw_parse_exception("Bare key " + key + " cannot contain '[' or ']'");
1829 }
1830
1831 it = end;
1832 return key;
1833 }
1834
1835 enum class parse_type {
1836 STRING = 1,
1837 LOCAL_TIME,
1838 LOCAL_DATE,
1841 INT,
1842 FLOAT,
1843 BOOL,
1844 ARRAY,
1845 INLINE_TABLE
1846 };
1847
1848 std::shared_ptr<base> parse_value(std::string::iterator& it, std::string::iterator& end) {
1849 parse_type type = determine_value_type(it, end);
1850 switch(type) {
1851 case parse_type::STRING:
1852 return parse_string(it, end);
1853 case parse_type::LOCAL_TIME:
1854 return parse_time(it, end);
1855 case parse_type::LOCAL_DATE:
1856 case parse_type::LOCAL_DATETIME:
1857 case parse_type::OFFSET_DATETIME:
1858 return parse_date(it, end);
1859 case parse_type::INT:
1860 case parse_type::FLOAT:
1861 return parse_number(it, end);
1862 case parse_type::BOOL:
1863 return parse_bool(it, end);
1864 case parse_type::ARRAY:
1865 return parse_array(it, end);
1866 case parse_type::INLINE_TABLE:
1867 return parse_inline_table(it, end);
1868 default:
1869 throw_parse_exception("Failed to parse value");
1870 }
1871 }
1872
1873 parse_type determine_value_type(const std::string::iterator& it, const std::string::iterator& end) {
1874 if(it == end) {
1875 throw_parse_exception("Failed to parse value type");
1876 }
1877 if(*it == '"' || *it == '\'') {
1878 return parse_type::STRING;
1879 } else if(is_time(it, end)) {
1880 return parse_type::LOCAL_TIME;
1881 } else if(auto dtype = date_type(it, end)) {
1882 return *dtype;
1883 } else if(is_number(*it) || *it == '-' || *it == '+') {
1884 return determine_number_type(it, end);
1885 } else if(*it == 't' || *it == 'f') {
1886 return parse_type::BOOL;
1887 } else if(*it == '[') {
1888 return parse_type::ARRAY;
1889 } else if(*it == '{') {
1890 return parse_type::INLINE_TABLE;
1891 }
1892 throw_parse_exception("Failed to parse value type");
1893 }
1894
1895 static parse_type determine_number_type(const std::string::iterator& it, const std::string::iterator& end) {
1896 // determine if we are an integer or a float
1897 auto check_it = it;
1898 if(*check_it == '-' || *check_it == '+') ++check_it;
1899 while(check_it != end && is_number(*check_it))
1900 ++check_it;
1901 if(check_it != end && *check_it == '.') {
1902 ++check_it;
1903 while(check_it != end && is_number(*check_it))
1904 ++check_it;
1905 return parse_type::FLOAT;
1906 } else {
1907 return parse_type::INT;
1908 }
1909 }
1910
1911 std::shared_ptr<value<std::string>> parse_string(std::string::iterator& it, std::string::iterator& end) {
1912 auto delim = *it;
1913 assert(delim == '"' || delim == '\'');
1914
1915 // end is non-const here because we have to be able to potentially
1916 // parse multiple lines in a string, not just one
1917 auto check_it = it;
1918 ++check_it;
1919 if(check_it != end && *check_it == delim) {
1920 ++check_it;
1921 if(check_it != end && *check_it == delim) {
1922 it = ++check_it;
1923 return parse_multiline_string(it, end, delim);
1924 }
1925 }
1926 return make_value<std::string>(string_literal(it, end, delim));
1927 }
1928
1929 std::shared_ptr<value<std::string>> parse_multiline_string(std::string::iterator& it, std::string::iterator& end,
1930 char delim) {
1931 std::stringstream ss;
1932
1933 auto is_ws = [](char c) { return c == ' ' || c == '\t'; };
1934
1935 MBool consuming = false;
1936 std::shared_ptr<value<std::string>> ret;
1937
1938 auto handle_line = [&](std::string::iterator& local_it, std::string::iterator& local_end) {
1939 if(consuming) {
1940 local_it = std::find_if_not(local_it, local_end, is_ws);
1941
1942 // whole line is whitespace
1943 if(local_it == local_end) return;
1944 }
1945
1946 consuming = false;
1947
1948 while(local_it != local_end) {
1949 // handle escaped characters
1950 if(delim == '"' && *local_it == '\\') {
1951 auto check = local_it;
1952 // check if this is an actual escape sequence or a
1953 // whitespace escaping backslash
1954 ++check;
1955 consume_whitespace(check, local_end);
1956 if(check == local_end) {
1957 consuming = true;
1958 break;
1959 }
1960
1961 ss << parse_escape_code(local_it, local_end);
1962 continue;
1963 }
1964
1965 // if we can end the string
1966 if(std::distance(local_it, local_end) >= 3) {
1967 auto check = local_it;
1968 // check for """
1969 if(*check++ == delim && *check++ == delim && *check++ == delim) {
1970 local_it = check;
1971 ret = make_value<std::string>(ss.str());
1972 break;
1973 }
1974 }
1975
1976 ss << *local_it++;
1977 }
1978 };
1979
1980 // handle the remainder of the current line
1981 handle_line(it, end);
1982 if(ret) return ret;
1983
1984 // start eating lines
1985 while(detail::getline(input_, line_)) {
1986 ++line_number_;
1987
1988 it = line_.begin();
1989 end = line_.end();
1990
1991 handle_line(it, end);
1992
1993 if(ret) return ret;
1994
1995 if(!consuming) ss << std::endl;
1996 }
1997
1998 throw_parse_exception("Unterminated multi-line basic string");
1999 }
2000
2001 std::string string_literal(std::string::iterator& it, const std::string::iterator& end, char delim) {
2002 ++it;
2003 std::string val;
2004 while(it != end) {
2005 // handle escaped characters
2006 if(delim == '"' && *it == '\\') {
2007 val += parse_escape_code(it, end);
2008 } else if(*it == delim) {
2009 ++it;
2010 consume_whitespace(it, end);
2011 return val;
2012 } else {
2013 val += *it++;
2014 }
2015 }
2016 throw_parse_exception("Unterminated string literal");
2017 }
2018
2019 std::string parse_escape_code(std::string::iterator& it, const std::string::iterator& end) {
2020 ++it;
2021 if(it == end) throw_parse_exception("Invalid escape sequence");
2022 char value;
2023 if(*it == 'b') {
2024 value = '\b';
2025 } else if(*it == 't') {
2026 value = '\t';
2027 } else if(*it == 'n') {
2028 value = '\n';
2029 } else if(*it == 'f') {
2030 value = '\f';
2031 } else if(*it == 'r') {
2032 value = '\r';
2033 } else if(*it == '"') {
2034 value = '"';
2035 } else if(*it == '\\') {
2036 value = '\\';
2037 } else if(*it == 'u' || *it == 'U') {
2038 return parse_unicode(it, end);
2039 } else {
2040 throw_parse_exception("Invalid escape sequence");
2041 }
2042 ++it;
2043 return std::string(1, value);
2044 }
2045
2046 std::string parse_unicode(std::string::iterator& it, const std::string::iterator& end) {
2047 MBool large = *it++ == 'U';
2048 auto codepoint = parse_hex(it, end, large ? 0x10000000 : 0x1000);
2049
2050 if((codepoint > 0xd7ff && codepoint < 0xe000) || codepoint > 0x10ffff) {
2051 throw_parse_exception("Unicode escape sequence is not a Unicode scalar value");
2052 }
2053
2054 std::string result;
2055 // See Table 3-6 of the Unicode standard
2056 if(codepoint <= 0x7f) {
2057 // 1-byte codepoints: 00000000 0xxxxxxx
2058 // repr: 0xxxxxxx
2059 result += static_cast<char>(codepoint & 0x7f);
2060 } else if(codepoint <= 0x7ff) {
2061 // 2-byte codepoints: 00000yyy yyxxxxxx
2062 // repr: 110yyyyy 10xxxxxx
2063 //
2064 // 0x1f = 00011111
2065 // 0xc0 = 11000000
2066 //
2067 result += static_cast<char>(0xc0 | ((codepoint >> 6) & 0x1f));
2068 //
2069 // 0x80 = 10000000
2070 // 0x3f = 00111111
2071 //
2072 result += static_cast<char>(0x80 | (codepoint & 0x3f));
2073 } else if(codepoint <= 0xffff) {
2074 // 3-byte codepoints: zzzzyyyy yyxxxxxx
2075 // repr: 1110zzzz 10yyyyyy 10xxxxxx
2076 //
2077 // 0xe0 = 11100000
2078 // 0x0f = 00001111
2079 //
2080 result += static_cast<char>(0xe0 | ((codepoint >> 12) & 0x0f));
2081 result += static_cast<char>(0x80 | ((codepoint >> 6) & 0x1f));
2082 result += static_cast<char>(0x80 | (codepoint & 0x3f));
2083 } else {
2084 // 4-byte codepoints: 000uuuuu zzzzyyyy yyxxxxxx
2085 // repr: 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx
2086 //
2087 // 0xf0 = 11110000
2088 // 0x07 = 00000111
2089 //
2090 result += static_cast<char>(0xf0 | ((codepoint >> 18) & 0x07));
2091 result += static_cast<char>(0x80 | ((codepoint >> 12) & 0x3f));
2092 result += static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f));
2093 result += static_cast<char>(0x80 | (codepoint & 0x3f));
2094 }
2095 return result;
2096 }
2097
2098 uint32_t parse_hex(std::string::iterator& it, const std::string::iterator& end, uint32_t place) {
2099 uint32_t value = 0;
2100 while(place > 0) {
2101 if(it == end) throw_parse_exception("Unexpected end of unicode sequence");
2102
2103 if(!is_hex(*it)) throw_parse_exception("Invalid unicode escape sequence");
2104
2105 value += place * hex_to_digit(*it++);
2106 place /= 16;
2107 }
2108 return value;
2109 }
2110
2111 static MBool is_hex(char c) { return is_number(c) || (c >= 'a' && c <= 'f') || (c >= 'A' && c <= 'F'); }
2112
2113 static uint32_t hex_to_digit(char c) {
2114 if(is_number(c)) return static_cast<uint32_t>(c - '0');
2115 return 10 + static_cast<uint32_t>(c - ((c >= 'a' && c <= 'f') ? 'a' : 'A'));
2116 }
2117
2118 std::shared_ptr<base> parse_number(std::string::iterator& it, const std::string::iterator& end) {
2119 auto check_it = it;
2120 auto check_end = find_end_of_number(it, end);
2121
2122 auto eat_sign = [&]() {
2123 if(check_it != end && (*check_it == '-' || *check_it == '+')) ++check_it;
2124 };
2125
2126 eat_sign();
2127
2128 auto eat_numbers = [&]() {
2129 auto beg = check_it;
2130 while(check_it != end && is_number(*check_it)) {
2131 ++check_it;
2132 if(check_it != end && *check_it == '_') {
2133 ++check_it;
2134 if(check_it == end || !is_number(*check_it)) throw_parse_exception("Malformed number");
2135 }
2136 }
2137
2138 if(check_it == beg) throw_parse_exception("Malformed number");
2139 };
2140
2141 auto check_no_leading_zero = [&]() {
2142 if(check_it != end && *check_it == '0' && check_it + 1 != check_end && check_it[1] != '.') {
2143 throw_parse_exception("Numbers may not have leading zeros");
2144 }
2145 };
2146
2147 check_no_leading_zero();
2148 eat_numbers();
2149
2150 if(check_it != end && (*check_it == '.' || *check_it == 'e' || *check_it == 'E')) {
2151 MBool is_exp = *check_it == 'e' || *check_it == 'E';
2152
2153 ++check_it;
2154 if(check_it == end) throw_parse_exception("Floats must have trailing digits");
2155
2156 auto eat_exp = [&]() {
2157 eat_sign();
2158 check_no_leading_zero();
2159 eat_numbers();
2160 };
2161
2162 if(is_exp)
2163 eat_exp();
2164 else
2165 eat_numbers();
2166
2167 if(!is_exp && check_it != end && (*check_it == 'e' || *check_it == 'E')) {
2168 ++check_it;
2169 eat_exp();
2170 }
2171
2172 return parse_float(it, check_it);
2173 } else {
2174 return parse_int(it, check_it);
2175 }
2176 }
2177
2178 std::shared_ptr<value<int64_t>> parse_int(std::string::iterator& it, const std::string::iterator& end) {
2179 std::string v{it, end};
2180 v.erase(std::remove(v.begin(), v.end(), '_'), v.end());
2181 it = end;
2182#ifndef CPPTOML_NO_EXCEPTIONS
2183 try
2184#endif
2185 {
2186 return make_value<int64_t>(std::stoll(v));
2187 }
2188#ifndef CPPTOML_NO_EXCEPTIONS
2189 catch(const std::invalid_argument& ex) {
2190 throw_parse_exception("Malformed number (invalid argument: " + std::string{ex.what()} + ")");
2191 } catch(const std::out_of_range& ex) {
2192 throw_parse_exception("Malformed number (out of range: " + std::string{ex.what()} + ")");
2193 }
2194#endif
2195 }
2196
2197 std::shared_ptr<value<double>> parse_float(std::string::iterator& it, const std::string::iterator& end) {
2198 std::string v{it, end};
2199 v.erase(std::remove(v.begin(), v.end(), '_'), v.end());
2200 it = end;
2201 char decimal_point = std::localeconv()->decimal_point[0];
2202 std::replace(v.begin(), v.end(), '.', decimal_point);
2203#ifndef CPPTOML_NO_EXCEPTIONS
2204 try
2205#endif
2206 {
2207 return make_value<double>(std::stod(v));
2208 }
2209#ifndef CPPTOML_NO_EXCEPTIONS
2210 catch(const std::invalid_argument& ex) {
2211 throw_parse_exception("Malformed number (invalid argument: " + std::string{ex.what()} + ")");
2212 } catch(const std::out_of_range& ex) {
2213 throw_parse_exception("Malformed number (out of range: " + std::string{ex.what()} + ")");
2214 }
2215#endif
2216 }
2217
2218 std::shared_ptr<value<MBool>> parse_bool(std::string::iterator& it, const std::string::iterator& end) {
2219 auto eat = make_consumer(it, end, [this]() { throw_parse_exception("Attempted to parse invalid boolean value"); });
2220
2221 if(*it == 't') {
2222 eat("true");
2223 return make_value<MBool>(true);
2224 } else if(*it == 'f') {
2225 eat("false");
2226 return make_value<MBool>(false);
2227 }
2228
2229 eat.error();
2230 return nullptr;
2231 }
2232
2233 static std::string::iterator find_end_of_number(std::string::iterator it, std::string::iterator end) {
2234 return std::find_if(it, end, [](char c) {
2235 return !is_number(c) && c != '_' && c != '.' && c != 'e' && c != 'E' && c != '-' && c != '+';
2236 });
2237 }
2238
2239 static std::string::iterator find_end_of_date(std::string::iterator it, std::string::iterator end) {
2240 return std::find_if(it, end, [](char c) {
2241 return !is_number(c) && c != 'T' && c != 'Z' && c != ':' && c != '-' && c != '+' && c != '.';
2242 });
2243 }
2244
2245 static std::string::iterator find_end_of_time(std::string::iterator it, std::string::iterator end) {
2246 return std::find_if(it, end, [](char c) { return !is_number(c) && c != ':' && c != '.'; });
2247 }
2248
2249 local_time read_time(std::string::iterator& it, const std::string::iterator& end) {
2250 auto time_end = find_end_of_time(it, end);
2251
2252 auto eat = make_consumer(it, time_end, [&]() { throw_parse_exception("Malformed time"); });
2253
2254 local_time ltime;
2255
2256 ltime.hour = eat.eat_digits(2);
2257 eat(':');
2258 ltime.minute = eat.eat_digits(2);
2259 eat(':');
2260 ltime.second = eat.eat_digits(2);
2261
2262 int power = 100000;
2263 if(it != time_end && *it == '.') {
2264 ++it;
2265 while(it != time_end && is_number(*it)) {
2266 ltime.microsecond += power * (*it++ - '0');
2267 power /= 10;
2268 }
2269 }
2270
2271 if(it != time_end) throw_parse_exception("Malformed time");
2272
2273 return ltime;
2274 }
2275
2276 std::shared_ptr<value<local_time>> parse_time(std::string::iterator& it, const std::string::iterator& end) {
2277 return make_value(read_time(it, end));
2278 }
2279
2280 std::shared_ptr<base> parse_date(std::string::iterator& it, const std::string::iterator& end) {
2281 auto date_end = find_end_of_date(it, end);
2282
2283 auto eat = make_consumer(it, date_end, [&]() { throw_parse_exception("Malformed date"); });
2284
2285 local_date ldate;
2286 ldate.year = eat.eat_digits(4);
2287 eat('-');
2288 ldate.month = eat.eat_digits(2);
2289 eat('-');
2290 ldate.day = eat.eat_digits(2);
2291
2292 if(it == date_end) return make_value(ldate);
2293
2294 eat('T');
2295
2296 local_datetime ldt;
2297 static_cast<local_date&>(ldt) = ldate;
2298 static_cast<local_time&>(ldt) = read_time(it, date_end);
2299
2300 if(it == date_end) return make_value(ldt);
2301
2302 offset_datetime dt;
2303 static_cast<local_datetime&>(dt) = ldt;
2304
2305 int hoff = 0;
2306 int moff = 0;
2307 if(*it == '+' || *it == '-') {
2308 auto plus = *it == '+';
2309 ++it;
2310
2311 hoff = eat.eat_digits(2);
2312 dt.hour_offset = (plus) ? hoff : -hoff;
2313 eat(':');
2314 moff = eat.eat_digits(2);
2315 dt.minute_offset = (plus) ? moff : -moff;
2316 } else if(*it == 'Z') {
2317 ++it;
2318 }
2319
2320 if(it != date_end) throw_parse_exception("Malformed date");
2321
2322 return make_value(dt);
2323 }
2324
2325 std::shared_ptr<base> parse_array(std::string::iterator& it, std::string::iterator& end) {
2326 // this gets ugly because of the "homogeneity" restriction:
2327 // arrays can either be of only one type, or contain arrays
2328 // (each of those arrays could be of different types, though)
2329 //
2330 // because of the latter portion, we don't really have a choice
2331 // but to represent them as arrays of base values...
2332 ++it;
2333
2334 // ugh---have to read the first value to determine array type...
2335 skip_whitespace_and_comments(it, end);
2336
2337 // edge case---empty array
2338 if(*it == ']') {
2339 ++it;
2340 return make_array();
2341 }
2342
2343 auto val_end = std::find_if(it, end, [](char c) { return c == ',' || c == ']' || c == '#'; });
2344 parse_type type = determine_value_type(it, val_end);
2345 switch(type) {
2346 case parse_type::STRING:
2347 return parse_value_array<std::string>(it, end);
2348 case parse_type::LOCAL_TIME:
2349 return parse_value_array<local_time>(it, end);
2350 case parse_type::LOCAL_DATE:
2351 return parse_value_array<local_date>(it, end);
2352 case parse_type::LOCAL_DATETIME:
2353 return parse_value_array<local_datetime>(it, end);
2354 case parse_type::OFFSET_DATETIME:
2355 return parse_value_array<offset_datetime>(it, end);
2356 case parse_type::INT:
2357 return parse_value_array<int64_t>(it, end);
2358 case parse_type::FLOAT:
2359 return parse_value_array<double>(it, end);
2360 case parse_type::BOOL:
2361 return parse_value_array<MBool>(it, end);
2362 case parse_type::ARRAY:
2363 return parse_object_array<array>(&parser::parse_array, '[', it, end);
2364 case parse_type::INLINE_TABLE:
2365 return parse_object_array<table_array>(&parser::parse_inline_table, '{', it, end);
2366 default:
2367 throw_parse_exception("Unable to parse array");
2368 }
2369 }
2370
2371 template <class Value>
2372 std::shared_ptr<array> parse_value_array(std::string::iterator& it, std::string::iterator& end) {
2373 auto arr = make_array();
2374 while(it != end && *it != ']') {
2375 auto val = parse_value(it, end);
2376 if(auto v = val->as<Value>())
2377 arr->get().push_back(val);
2378 else
2379 throw_parse_exception("Arrays must be homogeneous");
2380 skip_whitespace_and_comments(it, end);
2381 if(*it != ',') break;
2382 ++it;
2383 skip_whitespace_and_comments(it, end);
2384 }
2385 if(it != end) ++it;
2386 return arr;
2387 }
2388
2389 template <class Object, class Function>
2390 std::shared_ptr<Object> parse_object_array(Function&& fun, char delim, std::string::iterator& it,
2391 std::string::iterator& end) {
2392 auto arr = make_element<Object>();
2393
2394 while(it != end && *it != ']') {
2395 if(*it != delim) throw_parse_exception("Unexpected character in array");
2396
2397 arr->get().push_back(((*this).*fun)(it, end));
2398 skip_whitespace_and_comments(it, end);
2399
2400 if(*it != ',') break;
2401
2402 ++it;
2403 skip_whitespace_and_comments(it, end);
2404 }
2405
2406 if(it == end || *it != ']') throw_parse_exception("Unterminated array");
2407
2408 ++it;
2409 return arr;
2410 }
2411
2412 std::shared_ptr<table> parse_inline_table(std::string::iterator& it, std::string::iterator& end) {
2413 auto tbl = make_table();
2414 do {
2415 ++it;
2416 if(it == end) throw_parse_exception("Unterminated inline table");
2417
2418 consume_whitespace(it, end);
2419 parse_key_value(it, end, tbl.get());
2420 consume_whitespace(it, end);
2421 } while(*it == ',');
2422
2423 if(it == end || *it != '}') throw_parse_exception("Unterminated inline table");
2424
2425 ++it;
2426 consume_whitespace(it, end);
2427
2428 return tbl;
2429 }
2430
2431 void skip_whitespace_and_comments(std::string::iterator& start, std::string::iterator& end) {
2432 consume_whitespace(start, end);
2433 while(start == end || *start == '#') {
2434 if(!detail::getline(input_, line_)) throw_parse_exception("Unclosed array");
2435 line_number_++;
2436 start = line_.begin();
2437 end = line_.end();
2438 consume_whitespace(start, end);
2439 }
2440 }
2441
2442 static void consume_whitespace(std::string::iterator& it, const std::string::iterator& end) {
2443 while(it != end && (*it == ' ' || *it == '\t'))
2444 ++it;
2445 }
2446
2447 static void consume_backwards_whitespace(std::string::iterator& back, const std::string::iterator& front) {
2448 while(back != front && (*back == ' ' || *back == '\t'))
2449 --back;
2450 }
2451
2452 void eol_or_comment(const std::string::iterator& it, const std::string::iterator& end) {
2453 if(it != end && *it != '#')
2454 throw_parse_exception("Unidentified trailing character '" + std::string{*it} + "'---did you forget a '#'?");
2455 }
2456
2457 static MBool is_time(const std::string::iterator& it, const std::string::iterator& end) {
2458 auto time_end = find_end_of_time(it, end);
2459 auto len = std::distance(it, time_end);
2460
2461 if(len < 8) return false;
2462
2463 if(it[2] != ':' || it[5] != ':') return false;
2464
2465 if(len > 8) return it[8] == '.' && len > 9;
2466
2467 return true;
2468 }
2469
2470 static option<parse_type> date_type(const std::string::iterator& it, const std::string::iterator& end) {
2471 auto date_end = find_end_of_date(it, end);
2472 auto len = std::distance(it, date_end);
2473
2474 if(len < 10) return {};
2475
2476 if(it[4] != '-' || it[7] != '-') return {};
2477
2478 if(len >= 19 && it[10] == 'T' && is_time(it + 11, date_end)) {
2479 // datetime type
2480 auto time_end = find_end_of_time(it + 11, date_end);
2481 if(time_end == date_end)
2482 return {parse_type::LOCAL_DATETIME};
2483 else
2484 return {parse_type::OFFSET_DATETIME};
2485 } else if(len == 10) {
2486 // just a regular date
2487 return {parse_type::LOCAL_DATE};
2488 }
2489
2490 return {};
2491 }
2492
2493 std::istream& input_;
2494 std::string line_;
2495 std::size_t line_number_ = 0;
2496};
2497
2502inline std::shared_ptr<table> parse_file(const std::string& filename) {
2503#if defined(BOOST_NOWIDE_FSTREAM_INCLUDED_HPP)
2504 boost::nowide::ifstream file{filename.c_str()};
2505#elif defined(NOWIDE_FSTREAM_INCLUDED_HPP)
2506 nowide::ifstream file{filename.c_str()};
2507#else
2508 std::ifstream file{filename};
2509#endif
2510 if(!file.is_open()) THROW_(parse_exception, filename + " could not be opened for parsing");
2511 parser p{file};
2512 return p.parse();
2513}
2514
2515template <class... Ts>
2517
2518template <>
2520 template <class Visitor, class... Args>
2521 static void accept(const base&, Visitor&&, Args&&...) {
2522 // nothing
2523 }
2524};
2525
2526template <class T, class... Ts>
2527struct value_accept<T, Ts...> {
2528 template <class Visitor, class... Args>
2529 static void accept(const base& b, Visitor&& visitor, Args&&... args) {
2530 if(auto v = b.as<T>()) {
2531 visitor.visit(*v, std::forward<Args>(args)...);
2532 } else {
2533 value_accept<Ts...>::accept(b, std::forward<Visitor>(visitor), std::forward<Args>(args)...);
2534 }
2535 }
2536};
2537
2542template <class Visitor, class... Args>
2543void base::accept(Visitor&& visitor, Args&&... args) const {
2544#if defined(MAIA_GCC_COMPILER)
2545#pragma GCC diagnostic push
2546#pragma GCC diagnostic ignored "-Wnull-dereference"
2547#endif
2548
2549 if(is_value()) {
2550 using value_acceptor =
2552 value_acceptor::accept(*this, std::forward<Visitor>(visitor), std::forward<Args>(args)...);
2553 } else if(is_table()) {
2554 visitor.visit(static_cast<const table&>(*this), std::forward<Args>(args)...);
2555 } else if(is_array()) {
2556 visitor.visit(static_cast<const array&>(*this), std::forward<Args>(args)...);
2557 } else if(is_table_array()) {
2558 visitor.visit(static_cast<const table_array&>(*this), std::forward<Args>(args)...);
2559 }
2560#if defined(MAIA_GCC_COMPILER)
2561#pragma GCC diagnostic pop
2562#endif
2563}
2564
2570 public:
2574 explicit toml_writer(std::ostream& s, std::string indent_space = "\t")
2575 : stream_(s), indent_(std::move(indent_space)), has_naked_endline_(false) {
2576 // nothing
2577 }
2578
2579 public:
2583 template <class T>
2584 void visit(const value<T>& v, MBool = false) {
2585 write(v);
2586 }
2587
2591 void visit(const table& t, MBool in_array = false) {
2592 write_table_header(in_array);
2593 std::vector<std::string> values;
2594 std::vector<std::string> tables;
2595
2596 for(const auto& i : t) {
2597 if(i.second->is_table() || i.second->is_table_array()) {
2598 tables.push_back(i.first);
2599 } else {
2600 values.push_back(i.first);
2601 }
2602 }
2603
2604 for(MUint i = 0; i < values.size(); ++i) {
2605 path_.push_back(values[i]);
2606
2607 if(i > 0) endline();
2608
2609 write_table_item_header(*t.get(values[i]));
2610 t.get(values[i])->accept(*this, false);
2611 path_.pop_back();
2612 }
2613
2614 for(MUint i = 0; i < tables.size(); ++i) {
2615 path_.push_back(tables[i]);
2616
2617 if(!values.empty() || i > 0) endline();
2618
2619 write_table_item_header(*t.get(tables[i]));
2620 t.get(tables[i])->accept(*this, false);
2621 path_.pop_back();
2622 }
2623
2624 endline();
2625 }
2626
2630 void visit(const array& a, MBool = false) {
2631 write("[");
2632
2633 for(MUint i = 0; i < a.get().size(); ++i) {
2634 if(i > 0) write(", ");
2635
2636 if(a.get()[i]->is_array()) {
2637 a.get()[i]->as_array()->accept(*this, true);
2638 } else {
2639 a.get()[i]->accept(*this, true);
2640 }
2641 }
2642
2643 write("]");
2644 }
2645
2649 void visit(const table_array& t, MBool = false) {
2650 for(MUint j = 0; j < t.get().size(); ++j) {
2651 if(j > 0) endline();
2652
2653 t.get()[j]->accept(*this, true);
2654 }
2655
2656 endline();
2657 }
2658
2662 static std::string escape_string(const std::string& str) {
2663 std::string res;
2664 for(char it : str) {
2665 if(it == '\b') {
2666 res += "\\b";
2667 } else if(it == '\t') {
2668 res += "\\t";
2669 } else if(it == '\n') {
2670 res += "\\n";
2671 } else if(it == '\f') {
2672 res += "\\f";
2673 } else if(it == '\r') {
2674 res += "\\r";
2675 } else if(it == '"') {
2676 res += "\\\"";
2677 } else if(it == '\\') {
2678 res += "\\\\";
2679 } else if((uint32_t)it <= 0x001f) {
2680 res += "\\u";
2681 std::stringstream ss;
2682 ss << std::hex << static_cast<uint32_t>(it);
2683 res += ss.str();
2684 } else {
2685 res += it;
2686 }
2687 }
2688 return res;
2689 }
2690
2691 protected:
2695 void write(const value<std::string>& v) {
2696 write("\"");
2697 write(escape_string(v.get()));
2698 write("\"");
2699 }
2700
2704 void write(const value<double>& v) {
2705 std::ios::fmtflags flags{stream_.flags()};
2706
2707 stream_ << std::showpoint;
2708 write(v.get());
2709
2710 stream_.flags(flags);
2711 }
2712
2717 template <class T>
2718 typename std::enable_if<is_one_of<T, int64_t, local_date, local_time, local_datetime, offset_datetime>::value>::type
2719 write(const value<T>& v) {
2720 write(v.get());
2721 }
2722
2726 void write(const value<MBool>& v) { write((v.get() ? "true" : "false")); }
2727
2731 void write_table_header(MBool in_array = false) {
2732 if(!path_.empty()) {
2733 indent();
2734
2735 write("[");
2736
2737 if(in_array) {
2738 write("[");
2739 }
2740
2741 for(MUint i = 0; i < path_.size(); ++i) {
2742 if(i > 0) {
2743 write(".");
2744 }
2745
2746 if(path_[i].find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
2747 "fghijklmnopqrstuvwxyz0123456789"
2748 "_-")
2749 == std::string::npos) {
2750 write(path_[i]);
2751 } else {
2752 write("\"");
2753 write(escape_string(path_[i]));
2754 write("\"");
2755 }
2756 }
2757
2758 if(in_array) {
2759 write("]");
2760 }
2761
2762 write("]");
2763 endline();
2764 }
2765 }
2766
2771 if(!b.is_table() && !b.is_table_array()) {
2772 indent();
2773
2774 if(path_.back().find_first_not_of("ABCDEFGHIJKLMNOPQRSTUVWXYZabcde"
2775 "fghijklmnopqrstuvwxyz0123456789"
2776 "_-")
2777 == std::string::npos) {
2778 write(path_.back());
2779 } else {
2780 write("\"");
2781 write(escape_string(path_.back()));
2782 write("\"");
2783 }
2784
2785 write(" = ");
2786 }
2787 }
2788
2789 private:
2794 void indent() {
2795 for(std::size_t i = 1; i < path_.size(); ++i)
2796 write(indent_);
2797 }
2798
2802 template <class T>
2803 void write(const T& v) {
2804 stream_ << v;
2805 has_naked_endline_ = false;
2806 }
2807
2811 void endline() {
2812 if(!has_naked_endline_) {
2813 stream_ << "\n";
2814 has_naked_endline_ = true;
2815 }
2816 }
2817
2818 private:
2819 std::ostream& stream_;
2820 const std::string indent_;
2821 std::vector<std::string> path_;
2823};
2824
2825inline std::ostream& operator<<(std::ostream& stream, const base& b) {
2826 toml_writer writer{stream};
2827 b.accept(writer);
2828 return stream;
2829}
2830
2831template <class T>
2832std::ostream& operator<<(std::ostream& stream, const value<T>& v) {
2833 toml_writer writer{stream};
2834 v.accept(writer);
2835 return stream;
2836}
2837
2838inline std::ostream& operator<<(std::ostream& stream, const table& t) {
2839 toml_writer writer{stream};
2840 t.accept(writer);
2841 return stream;
2842}
2843
2844inline std::ostream& operator<<(std::ostream& stream, const table_array& t) {
2845 toml_writer writer{stream};
2846 t.accept(writer);
2847 return stream;
2848}
2849
2850inline std::ostream& operator<<(std::ostream& stream, const array& a) {
2851 toml_writer writer{stream};
2852 a.accept(writer);
2853 return stream;
2854}
2855} // namespace cpptoml
2856
2857#if defined(CPPTOML_NO_EXCEPTIONS)
2858// if defined, re-enable exception handling after this file
2859#undef THROW_
2860#undef THROW2_
2861#endif
2862
2863#endif
array_exception(const std::string &err)
Definition: cpptoml.h:670
std::vector< std::shared_ptr< base > > values_
Definition: cpptoml.h:861
const std::vector< std::shared_ptr< base > > & get() const
Definition: cpptoml.h:709
const_iterator begin() const
Definition: cpptoml.h:695
array(const array &obj)=delete
array & operator=(const array &obj)=delete
iterator end()
Definition: cpptoml.h:697
iterator insert(iterator position, const std::shared_ptr< array > &value)
Definition: cpptoml.h:809
std::shared_ptr< base > at(size_t idx) const
Definition: cpptoml.h:711
std::vector< std::shared_ptr< array > > nested_array() const
Definition: cpptoml.h:750
void reserve(size_type n)
Definition: cpptoml.h:838
array_of_trait< T >::return_type get_array_of() const
Definition: cpptoml.h:732
iterator insert(iterator position, const std::shared_ptr< value< T > > &value)
Definition: cpptoml.h:798
iterator erase(iterator position)
Definition: cpptoml.h:828
std::vector< std::shared_ptr< value< T > > > array_of() const
Definition: cpptoml.h:718
void push_back(const std::shared_ptr< value< T > > &val)
Definition: cpptoml.h:766
iterator begin()
Definition: cpptoml.h:693
const_iterator end() const
Definition: cpptoml.h:699
std::size_t size_type
Definition: cpptoml.h:681
void clear()
Definition: cpptoml.h:833
friend std::shared_ptr< array > make_array()
Definition: cpptoml.h:873
array()=default
MBool is_array() const override
Definition: cpptoml.h:679
iterator insert(iterator position, T &&val, typename value_traits< T >::type *=0)
Definition: cpptoml.h:821
void push_back(T &&val, typename value_traits< T >::type *=0)
Definition: cpptoml.h:790
std::vector< std::shared_ptr< base > >::const_iterator const_iterator
Definition: cpptoml.h:691
void push_back(const std::shared_ptr< array > &val)
Definition: cpptoml.h:777
array(InputIterator begin, InputIterator end)
Definition: cpptoml.h:852
std::shared_ptr< base > clone() const override
Definition: cpptoml.h:1437
std::vector< std::shared_ptr< base > >::iterator iterator
Definition: cpptoml.h:686
std::vector< std::shared_ptr< base > > & get()
Definition: cpptoml.h:704
virtual MBool is_array() const
Definition: cpptoml.h:479
std::shared_ptr< table > as_table()
Definition: cpptoml.h:472
virtual ~base()=default
virtual MBool is_table_array() const
Definition: cpptoml.h:492
virtual std::shared_ptr< base > clone() const =0
const base_type type_
Definition: cpptoml.h:524
virtual MBool is_table() const
Definition: cpptoml.h:467
virtual MBool is_value() const
Definition: cpptoml.h:462
void accept(Visitor &&visitor, Args &&... args) const
Definition: cpptoml.h:2543
std::shared_ptr< table_array > as_table_array()
Definition: cpptoml.h:497
std::shared_ptr< value< T > > as()
Definition: cpptoml.h:595
base_type type() const
Definition: cpptoml.h:516
std::shared_ptr< array > as_array()
Definition: cpptoml.h:484
base(const base_type t)
Definition: cpptoml.h:519
std::string::iterator & it_
Definition: cpptoml.h:1506
OnError on_error_
Definition: cpptoml.h:1508
int eat_digits(int len)
Definition: cpptoml.h:1494
void operator()(const char(&str)[N])
Definition: cpptoml.h:1490
void operator()(char c)
Definition: cpptoml.h:1484
consumer(std::string::iterator &it, const std::string::iterator &end, OnError &&on_error)
Definition: cpptoml.h:1479
const std::string::iterator & end_
Definition: cpptoml.h:1507
std::ostream::char_type fill_
Definition: cpptoml.h:199
std::ostream & os_
Definition: cpptoml.h:198
fill_guard(std::ostream &os)
Definition: cpptoml.h:191
const T * operator->() const
Definition: cpptoml.h:120
MBool empty_
Definition: cpptoml.h:128
const T & operator*() const
Definition: cpptoml.h:118
const T & value_or(const T &alternative) const
Definition: cpptoml.h:122
option(T value)
Definition: cpptoml.h:112
parse_exception(const std::string &err, std::size_t line_number)
Definition: cpptoml.h:1467
parse_exception(const std::string &err)
Definition: cpptoml.h:1465
std::istream & input_
Definition: cpptoml.h:2493
parser & operator=(const parser &parser)=delete
std::shared_ptr< value< local_time > > parse_time(std::string::iterator &it, const std::string::iterator &end)
Definition: cpptoml.h:2276
std::shared_ptr< base > parse_array(std::string::iterator &it, std::string::iterator &end)
Definition: cpptoml.h:2325
std::shared_ptr< base > parse_date(std::string::iterator &it, const std::string::iterator &end)
Definition: cpptoml.h:2280
std::shared_ptr< table > parse_inline_table(std::string::iterator &it, std::string::iterator &end)
Definition: cpptoml.h:2412
std::string parse_bare_key(std::string::iterator &it, const std::string::iterator &end)
Definition: cpptoml.h:1808
void parse_single_table(std::string::iterator &it, const std::string::iterator &end, table *&curr_table)
Definition: cpptoml.h:1604
std::shared_ptr< value< std::string > > parse_multiline_string(std::string::iterator &it, std::string::iterator &end, char delim)
Definition: cpptoml.h:1929
static option< parse_type > date_type(const std::string::iterator &it, const std::string::iterator &end)
Definition: cpptoml.h:2470
static std::string::iterator find_end_of_date(std::string::iterator it, std::string::iterator end)
Definition: cpptoml.h:2239
void parse_key_value(std::string::iterator &it, std::string::iterator &end, table *curr_table)
Definition: cpptoml.h:1733
static void consume_backwards_whitespace(std::string::iterator &back, const std::string::iterator &front)
Definition: cpptoml.h:2447
static void consume_whitespace(std::string::iterator &it, const std::string::iterator &end)
Definition: cpptoml.h:2442
std::string parse_simple_key(std::string::iterator &it, const std::string::iterator &end)
Definition: cpptoml.h:1793
std::string parse_unicode(std::string::iterator &it, const std::string::iterator &end)
Definition: cpptoml.h:2046
std::shared_ptr< table > parse()
Definition: cpptoml.h:1561
void parse_table(std::string::iterator &it, const std::string::iterator &end, table *&curr_table)
Definition: cpptoml.h:1594
uint32_t parse_hex(std::string::iterator &it, const std::string::iterator &end, uint32_t place)
Definition: cpptoml.h:2098
std::shared_ptr< value< double > > parse_float(std::string::iterator &it, const std::string::iterator &end)
Definition: cpptoml.h:2197
void eol_or_comment(const std::string::iterator &it, const std::string::iterator &end)
Definition: cpptoml.h:2452
static parse_type determine_number_type(const std::string::iterator &it, const std::string::iterator &end)
Definition: cpptoml.h:1895
parser(std::istream &stream)
Definition: cpptoml.h:1551
std::string parse_escape_code(std::string::iterator &it, const std::string::iterator &end)
Definition: cpptoml.h:2019
std::shared_ptr< base > parse_value(std::string::iterator &it, std::string::iterator &end)
Definition: cpptoml.h:1848
std::shared_ptr< Object > parse_object_array(Function &&fun, char delim, std::string::iterator &it, std::string::iterator &end)
Definition: cpptoml.h:2390
static MBool is_hex(char c)
Definition: cpptoml.h:2111
void parse_table_array(std::string::iterator &it, const std::string::iterator &end, table *&curr_table)
Definition: cpptoml.h:1667
std::string string_literal(std::string::iterator &it, const std::string::iterator &end, char delim)
Definition: cpptoml.h:2001
std::string parse_key(std::string::iterator &it, const std::string::iterator &end, KeyEndFinder &&key_end, KeyPartHandler &&key_part_handler)
Definition: cpptoml.h:1765
static uint32_t hex_to_digit(char c)
Definition: cpptoml.h:2113
static std::string::iterator find_end_of_number(std::string::iterator it, std::string::iterator end)
Definition: cpptoml.h:2233
local_time read_time(std::string::iterator &it, const std::string::iterator &end)
Definition: cpptoml.h:2249
void skip_whitespace_and_comments(std::string::iterator &start, std::string::iterator &end)
Definition: cpptoml.h:2431
std::shared_ptr< array > parse_value_array(std::string::iterator &it, std::string::iterator &end)
Definition: cpptoml.h:2372
std::string line_
Definition: cpptoml.h:2494
static std::string::iterator find_end_of_time(std::string::iterator it, std::string::iterator end)
Definition: cpptoml.h:2245
parse_type determine_value_type(const std::string::iterator &it, const std::string::iterator &end)
Definition: cpptoml.h:1873
std::shared_ptr< value< std::string > > parse_string(std::string::iterator &it, std::string::iterator &end)
Definition: cpptoml.h:1911
std::shared_ptr< base > parse_number(std::string::iterator &it, const std::string::iterator &end)
Definition: cpptoml.h:2118
__declspec(noreturn) __attribute__((noreturn)) void throw_parse_exception(const std
Definition: cpptoml.h:1586
static MBool is_time(const std::string::iterator &it, const std::string::iterator &end)
Definition: cpptoml.h:2457
std::shared_ptr< value< int64_t > > parse_int(std::string::iterator &it, const std::string::iterator &end)
Definition: cpptoml.h:2178
std::shared_ptr< value< MBool > > parse_bool(std::string::iterator &it, const std::string::iterator &end)
Definition: cpptoml.h:2218
MBool is_table_array() const override
Definition: cpptoml.h:938
table_array & operator=(const table_array &rhs)=delete
const_iterator begin() const
Definition: cpptoml.h:932
const std::vector< std::shared_ptr< table > > & get() const
Definition: cpptoml.h:942
std::vector< std::shared_ptr< table > >::iterator iterator
Definition: cpptoml.h:923
void push_back(const std::shared_ptr< table > &val)
Definition: cpptoml.h:947
std::size_t size_type
Definition: cpptoml.h:918
iterator end()
Definition: cpptoml.h:934
iterator erase(iterator position)
Definition: cpptoml.h:957
void reserve(size_type n)
Definition: cpptoml.h:967
table_array(const table_array &obj)=delete
iterator insert(iterator position, const std::shared_ptr< table > &value)
Definition: cpptoml.h:952
std::vector< std::shared_ptr< table > > array_
Definition: cpptoml.h:987
std::vector< std::shared_ptr< table > >::const_iterator const_iterator
Definition: cpptoml.h:928
const_iterator end() const
Definition: cpptoml.h:936
std::vector< std::shared_ptr< table > > & get()
Definition: cpptoml.h:940
iterator begin()
Definition: cpptoml.h:930
std::shared_ptr< base > get(const std::string &key) const
Definition: cpptoml.h:1108
void insert(const std::string &key, T &&val, typename value_traits< T >::type *=0)
Definition: cpptoml.h:1282
std::shared_ptr< table > get_table(const std::string &key) const
Definition: cpptoml.h:1126
option< T > get_qualified_as(const std::string &key) const
Definition: cpptoml.h:1201
const_iterator begin() const
Definition: cpptoml.h:1082
string_to_base_map::iterator iterator
Definition: cpptoml.h:1073
array_of_trait< T >::return_type get_array_of(const std::string &key) const
Definition: cpptoml.h:1227
void insert(const std::string &key, const std::shared_ptr< base > &value)
Definition: cpptoml.h:1275
std::shared_ptr< base > get_qualified(const std::string &key) const
Definition: cpptoml.h:1117
iterator end()
Definition: cpptoml.h:1084
MBool is_table() const override
Definition: cpptoml.h:1088
option< T > get_as(const std::string &key) const
Definition: cpptoml.h:1179
string_to_base_map map_
Definition: cpptoml.h:1351
void erase(const std::string &key)
Definition: cpptoml.h:1289
MBool empty() const
Definition: cpptoml.h:1090
MBool contains(const std::string &key) const
Definition: cpptoml.h:1095
iterator begin()
Definition: cpptoml.h:1080
table & operator=(const table &rhs)=delete
string_to_base_map::const_iterator const_iterator
Definition: cpptoml.h:1078
std::shared_ptr< array > get_array(const std::string &key) const
Definition: cpptoml.h:1144
std::shared_ptr< table_array > get_table_array(const std::string &key) const
Definition: cpptoml.h:1160
std::shared_ptr< table > get_table_qualified(const std::string &key) const
Definition: cpptoml.h:1135
const_iterator end() const
Definition: cpptoml.h:1086
MBool contains_qualified(const std::string &key) const
Definition: cpptoml.h:1102
std::shared_ptr< array > get_array_qualified(const std::string &key) const
Definition: cpptoml.h:1152
std::vector< std::string > split(const std::string &value, char separator) const
Definition: cpptoml.h:1309
std::shared_ptr< table_array > get_table_array_qualified(const std::string &key) const
Definition: cpptoml.h:1169
MBool resolve_qualified(const std::string &key, std::shared_ptr< base > *p=nullptr) const
Definition: cpptoml.h:1326
array_of_trait< T >::return_type get_qualified_array_of(const std::string &key) const
Definition: cpptoml.h:1255
table(const table &obj)=delete
std::vector< std::string > path_
Definition: cpptoml.h:2821
void write_table_item_header(const base &b)
Definition: cpptoml.h:2770
void write(const T &v)
Definition: cpptoml.h:2803
toml_writer(std::ostream &s, std::string indent_space="\t")
Definition: cpptoml.h:2574
std::enable_if< is_one_of< T, int64_t, local_date, local_time, local_datetime, offset_datetime >::value >::type write(const value< T > &v)
Definition: cpptoml.h:2719
void write_table_header(MBool in_array=false)
Definition: cpptoml.h:2731
MBool has_naked_endline_
Definition: cpptoml.h:2822
void visit(const table &t, MBool in_array=false)
Definition: cpptoml.h:2591
const std::string indent_
Definition: cpptoml.h:2820
void visit(const table_array &t, MBool=false)
Definition: cpptoml.h:2649
void write(const value< MBool > &v)
Definition: cpptoml.h:2726
void write(const value< double > &v)
Definition: cpptoml.h:2704
static std::string escape_string(const std::string &str)
Definition: cpptoml.h:2662
std::ostream & stream_
Definition: cpptoml.h:2819
void write(const value< std::string > &v)
Definition: cpptoml.h:2695
void visit(const value< T > &v, MBool=false)
Definition: cpptoml.h:2584
void visit(const array &a, MBool=false)
Definition: cpptoml.h:2630
MBool is_value() const override
Definition: cpptoml.h:558
value & operator=(const value &val)=delete
std::shared_ptr< base > clone() const override
Definition: cpptoml.h:1433
value(const T &val)
Definition: cpptoml.h:577
const T & get() const
Definition: cpptoml.h:568
value(const make_shared_enabler &, const T &val)
Definition: cpptoml.h:553
value(const value &val)=delete
constexpr std::array< T, n > make_array(const T v)
std::ostream & operator<<(std::ostream &os, const LPTEllipsoidal< nDim > &m)
uint32_t MUint
Definition: maiatypes.h:63
bool MBool
Definition: maiatypes.h:58
std::istream & getline(std::istream &input, std::string &line)
Definition: cpptoml.h:1519
std::shared_ptr< table > make_table()
Definition: cpptoml.h:1417
MBool is_number(char c)
Definition: cpptoml.h:1471
std::map< std::string, std::shared_ptr< base > > string_to_base_map
Definition: cpptoml.h:72
std::shared_ptr< table > parse_file(const std::string &filename)
Definition: cpptoml.h:2502
void die(const std::string &reason, const std::string &file, const int line)
Definition: cpptoml.h:89
std::shared_ptr< T > make_element()
CPPTOML_DEPRECATED("datetime has been renamed to offset_datetime") typedef offset_datetime datetime
std::ostream & operator<<(std::ostream &os, const local_date &dt)
Definition: cpptoml.h:202
std::shared_ptr< table_array > make_table_array()
Definition: cpptoml.h:999
consumer< OnError > make_consumer(std::string::iterator &it, const std::string::iterator &end, OnError &&on_error)
Definition: cpptoml.h:1512
std::shared_ptr< typename value_traits< T >::type > make_value(T &&val)
Definition: cpptoml.h:588
std::shared_ptr< array > make_array()
Definition: cpptoml.h:873
std::enable_if<!std::is_floating_point< T >::value &&std::is_signed< T >::value, option< T > >::type get_impl(const std::shared_ptr< base > &elem)
Definition: cpptoml.h:1021
base_type
Base type used to store underlying data type explicitly if RTTI is disabled.
Definition: cpptoml.h:368
Definition: contexttypes.h:19
Type traits class to convert C++ types to enum member.
Definition: cpptoml.h:385
static offset_datetime from_zoned(const tm &t)
Definition: cpptoml.h:153
static offset_datetime from_utc(const tm &t)
Definition: cpptoml.h:174
CPPTOML_DEPRECATED("from_local has been renamed to from_zoned") static inline offset_datetime from_local(const tm &t)
Definition: cpptoml.h:171
static void accept(const base &b, Visitor &&visitor, Args &&... args)
Definition: cpptoml.h:2529
static void accept(const base &, Visitor &&, Args &&...)
Definition: cpptoml.h:2521
typename std::conditional< valid_value< typename std::decay< T >::type >::value, typename std::decay< T >::type, std::string >::type value_type
Definition: cpptoml.h:290