21 #include <unordered_map> 24 #if __cplusplus > 201103L 25 #define CPPTOML_DEPRECATED(reason) [[deprecated(reason)]] 26 #elif defined(__clang__) 27 #define CPPTOML_DEPRECATED(reason) __attribute__((deprecated(reason))) 28 #elif defined(__GNUG__) 29 #define CPPTOML_DEPRECATED(reason) __attribute__((deprecated)) 30 #elif defined(_MSC_VER) 32 #define CPPTOML_DEPRECATED(reason) __declspec(deprecated) 34 #define CPPTOML_DEPRECATED(reason) [[deprecated(reason)]] 42 #if defined(CPPTOML_USE_MAP) 45 using string_to_base_map = std::map<std::string, std::shared_ptr<base>>;
49 using string_to_base_map
50 = std::unordered_map<std::string, std::shared_ptr<base>>;
67 explicit operator bool()
const 72 const T& operator*()
const 77 const T* operator->()
const 82 const T& value_or(
const T& alternative)
const 112 int minute_offset = 0;
124 dt.year = t.tm_year + 1900;
125 dt.month = t.tm_mon + 1;
128 dt.minute = t.tm_min;
129 dt.second = t.tm_sec;
132 strftime(buf, 16,
"%z", &t);
134 int offset = std::stoi(buf);
135 dt.hour_offset = offset / 100;
136 dt.minute_offset = offset % 100;
140 CPPTOML_DEPRECATED(
"from_local has been renamed to from_zoned")
143 return from_zoned(t);
149 dt.year = t.tm_year + 1900;
150 dt.month = t.tm_mon + 1;
153 dt.minute = t.tm_min;
154 dt.second = t.tm_sec;
159 CPPTOML_DEPRECATED(
"datetime has been renamed to offset_datetime")
165 fill_guard(std::ostream& os) : os_(os), fill_{os.fill()}
177 std::ostream::char_type fill_;
180 inline std::ostream& operator<<(std::ostream& os,
const local_date& dt)
186 os << setw(4) << dt.year <<
"-" << setw(2) << dt.month <<
"-" << setw(2)
192 inline std::ostream& operator<<(std::ostream& os,
const local_time& ltime)
198 os << setw(2) << ltime.hour <<
":" << setw(2) << ltime.minute <<
":" 199 << setw(2) << ltime.second;
201 if (ltime.microsecond > 0)
205 for (
int curr_us = ltime.microsecond; curr_us; power /= 10)
207 auto num = curr_us / power;
209 curr_us -= num * power;
216 inline std::ostream& operator<<(std::ostream& os,
const zone_offset& zo)
223 if (zo.hour_offset != 0 || zo.minute_offset != 0)
225 if (zo.hour_offset > 0)
233 os << setw(2) << std::abs(zo.hour_offset) <<
":" << setw(2)
234 << std::abs(zo.minute_offset);
244 inline std::ostream& operator<<(std::ostream& os,
const local_datetime& dt)
246 return os << static_cast<const local_date&>(dt) <<
"T" 247 << static_cast<const local_time&>(dt);
250 inline std::ostream& operator<<(std::ostream& os,
const offset_datetime& dt)
252 return os << static_cast<const local_datetime&>(dt)
253 << static_cast<const zone_offset&>(dt);
256 template <
class T,
class... Ts>
259 template <
class T,
class V>
264 template <
class T,
class V,
class... Ts>
267 const static bool value 276 :
is_one_of<T, std::string, int64_t, double, bool, local_date, local_time,
277 local_datetime, offset_datetime>
281 template <
class T,
class Enable =
void>
289 || std::is_convertible<T, std::string>::value;
294 enable_if<valid_value_or_string_convertible<T>::
297 using value_type =
typename std::
298 conditional<valid_value<typename std::decay<T>::type>
::value,
299 typename std::decay<T>::type, std::string>
::type;
303 static value_type construct(T&& val)
305 return value_type(val);
312 enable_if<!valid_value_or_string_convertible<T>::value
313 && std::is_floating_point<
314 typename std::decay<T>::type>::value>::
317 using value_type =
typename std::decay<T>::type;
321 static value_type construct(T&& val)
323 return value_type(val);
330 enable_if<!valid_value_or_string_convertible<T>::value
331 && std::is_signed<typename std::decay<T>::
334 using value_type = int64_t;
338 static value_type construct(T&& val)
340 if (val < std::numeric_limits<int64_t>::min())
341 throw std::underflow_error{
"constructed value cannot be " 342 "represented by a 64-bit signed " 345 if (val > std::numeric_limits<int64_t>::max())
346 throw std::overflow_error{
"constructed value cannot be represented " 347 "by a 64-bit signed integer"};
349 return static_cast<int64_t
>(val);
356 enable_if<!valid_value_or_string_convertible<T>::value
357 && std::is_unsigned<typename std::decay<T>::
360 using value_type = int64_t;
364 static value_type construct(T&& val)
366 if (val > static_cast<uint64_t>(std::numeric_limits<int64_t>::max()))
367 throw std::overflow_error{
"constructed value cannot be represented " 368 "by a 64-bit signed integer"};
370 return static_cast<int64_t
>(val);
391 inline std::shared_ptr<typename value_traits<T>::type> make_value(T&& val);
392 inline std::shared_ptr<array> make_array();
394 inline std::shared_ptr<T> make_element();
395 inline std::shared_ptr<table> make_table();
396 inline std::shared_ptr<table_array> make_table_array();
401 class base :
public std::enable_shared_from_this<base>
404 virtual ~
base() =
default;
406 virtual std::shared_ptr<base> clone()
const = 0;
430 return std::static_pointer_cast<
table>(shared_from_this());
447 return std::static_pointer_cast<
array>(shared_from_this());
465 return std::static_pointer_cast<
table_array>(shared_from_this());
474 std::shared_ptr<value<T>>
as();
477 std::shared_ptr<const value<T>>
as()
const;
479 template <
class Visitor,
class... Args>
480 void accept(Visitor&& visitor, Args&&... args)
const;
493 class value :
public base
501 friend std::shared_ptr<typename value_traits<U>::type>
502 cpptoml::make_value(U&& val);
507 std::shared_ptr<base> clone()
const override;
551 std::shared_ptr<typename value_traits<T>::type> make_value(T&& val)
553 using value_type =
typename value_traits<T>::type;
554 using enabler =
typename value_type::make_shared_enabler;
555 return std::make_shared<value_type>(
556 enabler{}, value_traits<T>::construct(std::forward<T>(val)));
562 return std::dynamic_pointer_cast<
value<T>>(shared_from_this());
568 inline std::shared_ptr<value<double>>
base::as()
570 if (
auto v = std::dynamic_pointer_cast<
value<double>>(shared_from_this()))
573 if (
auto v = std::dynamic_pointer_cast<
value<int64_t>>(shared_from_this()))
574 return make_value<double>(
static_cast<double>(v->get()));
580 inline std::shared_ptr<const value<T>>
base::as()
const 582 return std::dynamic_pointer_cast<
const value<T>>(shared_from_this());
588 inline std::shared_ptr<const value<double>>
base::as()
const 591 = std::dynamic_pointer_cast<
const value<double>>(shared_from_this()))
594 if (
auto v = as<int64_t>())
598 return make_value<double>(
static_cast<double>(v->get()));
618 friend std::shared_ptr<array> make_array();
620 std::shared_ptr<base> clone()
const override;
627 using size_type = std::size_t;
641 return values_.begin();
646 return values_.begin();
651 return values_.end();
656 return values_.end();
662 std::vector<std::shared_ptr<base>>&
get()
670 const std::vector<std::shared_ptr<base>>&
get()
const 675 std::shared_ptr<base> at(
size_t idx)
const 677 return values_.at(idx);
685 std::vector<std::shared_ptr<value<T>>>
array_of()
const 687 std::vector<std::shared_ptr<value<T>>> result(values_.size());
689 std::transform(values_.begin(), values_.end(), result.begin(),
690 [&](std::shared_ptr<base> v) {
return v->as<T>(); });
702 std::vector<T> result;
703 result.reserve(values_.size());
705 for (
const auto& val : values_)
707 if (
auto v = val->as<T>())
708 result.push_back(v->get());
713 return {std::move(result)};
722 std::vector<std::shared_ptr<array>> result(values_.size());
724 std::transform(values_.begin(), values_.end(), result.begin(),
725 [&](std::shared_ptr<base> v) -> std::shared_ptr<array> {
727 return std::static_pointer_cast<array>(v);
728 return std::shared_ptr<array>{};
740 if (values_.empty() || values_[0]->as<T>())
742 values_.push_back(val);
755 if (values_.empty() || values_[0]->is_array())
757 values_.push_back(val);
772 push_back(make_value(std::forward<T>(val)));
781 if (values_.empty() || values_[0]->as<T>())
783 return values_.insert(position,
value);
796 if (values_.empty() || values_[0]->is_array())
798 return values_.insert(position,
value);
813 return insert(position, make_value(std::forward<T>(val)));
821 return values_.erase(position);
843 template <
class InputIterator>
844 array(InputIterator begin, InputIterator end) : values_{begin, end}
849 array(
const array& obj) =
delete;
850 array& operator=(
const array& obj) =
delete;
852 std::vector<std::shared_ptr<base>> values_;
855 inline std::shared_ptr<array> make_array()
857 struct make_shared_enabler :
public array
859 make_shared_enabler()
865 return std::make_shared<make_shared_enabler>();
869 inline std::shared_ptr<array> make_element<array>()
879 inline typename array_of_trait<array>::return_type
880 array::get_array_of<array>()
const 882 std::vector<std::shared_ptr<array>> result;
883 result.reserve(values_.size());
885 for (
const auto& val : values_)
887 if (
auto v = val->as_array())
893 return {std::move(result)};
901 friend std::shared_ptr<table_array> make_table_array();
904 std::shared_ptr<base> clone()
const override;
906 using size_type = std::size_t;
920 return array_.begin();
925 return array_.begin();
943 std::vector<std::shared_ptr<table>>&
get()
948 const std::vector<std::shared_ptr<table>>&
get()
const 958 array_.push_back(val);
966 return array_.insert(position,
value);
974 return array_.erase(position);
999 table_array(
const table_array& obj) =
delete;
1000 table_array& operator=(
const table_array& rhs) =
delete;
1002 std::vector<std::shared_ptr<table>> array_;
1005 inline std::shared_ptr<table_array> make_table_array()
1007 struct make_shared_enabler :
public table_array
1009 make_shared_enabler()
1015 return std::make_shared<make_shared_enabler>();
1019 inline std::shared_ptr<table_array> make_element<table_array>()
1021 return make_table_array();
1028 typename std::enable_if<!std::is_floating_point<T>::value
1029 && std::is_signed<T>::value,
1031 get_impl(
const std::shared_ptr<base>& elem)
1033 if (
auto v = elem->as<int64_t>())
1035 if (v->get() < std::numeric_limits<T>::min())
1036 throw std::underflow_error{
1037 "T cannot represent the value requested in get"};
1039 if (v->get() > std::numeric_limits<T>::max())
1040 throw std::overflow_error{
1041 "T cannot represent the value requested in get"};
1043 return {
static_cast<T
>(v->get())};
1052 typename std::enable_if<!std::is_same<T, bool>::value
1053 && std::is_unsigned<T>::value,
1055 get_impl(
const std::shared_ptr<base>& elem)
1057 if (
auto v = elem->as<int64_t>())
1060 throw std::underflow_error{
"T cannot store negative value in get"};
1062 if (static_cast<uint64_t>(v->get()) > std::numeric_limits<T>::max())
1063 throw std::overflow_error{
1064 "T cannot represent the value requested in get"};
1066 return {
static_cast<T
>(v->get())};
1075 typename std::enable_if<!std::is_integral<T>::value
1076 || std::is_same<T, bool>::value,
1078 get_impl(
const std::shared_ptr<base>& elem)
1080 if (
auto v = elem->as<T>())
1097 friend std::shared_ptr<table> make_table();
1099 std::shared_ptr<base> clone()
const override;
1113 return map_.begin();
1118 return map_.begin();
1138 return map_.empty();
1146 return map_.find(key) != map_.end();
1156 return resolve_qualified(key);
1163 std::shared_ptr<base>
get(
const std::string& key)
const 1165 return map_.at(key);
1177 std::shared_ptr<base> p;
1178 resolve_qualified(key, &p);
1185 std::shared_ptr<table>
get_table(
const std::string& key)
const 1188 return std::static_pointer_cast<
table>(
get(key));
1206 std::shared_ptr<array>
get_array(
const std::string& key)
const 1237 std::shared_ptr<table_array>
1254 return get_impl<T>(
get(key));
1256 catch (
const std::out_of_range&)
1274 catch (
const std::out_of_range&)
1295 std::vector<T> result;
1296 result.reserve(v->get().size());
1298 for (
const auto& b : v->get())
1300 if (
auto val = b->as<T>())
1301 result.push_back(val->get());
1305 return {std::move(result)};
1327 std::vector<T> result;
1328 result.reserve(v->get().size());
1330 for (
const auto& b : v->get())
1332 if (
auto val = b->as<T>())
1333 result.push_back(val->get());
1337 return {std::move(result)};
1346 void insert(
const std::string& key,
const std::shared_ptr<base>&
value)
1359 insert(key, make_value(std::forward<T>(val)));
1376 table(
const table& obj) =
delete;
1377 table& operator=(
const table& rhs) =
delete;
1379 std::vector<std::string> split(
const std::string& value,
1380 char separator)
const 1382 std::vector<std::string> result;
1383 std::string::size_type p = 0;
1384 std::string::size_type q;
1385 while ((q = value.find(separator, p)) != std::string::npos)
1387 result.emplace_back(value, p, q - p);
1390 result.emplace_back(value, p);
1399 bool resolve_qualified(
const std::string& key,
1400 std::shared_ptr<base>* p =
nullptr)
const 1402 auto parts = split(key,
'.');
1403 auto last_key = parts.back();
1407 for (
const auto& part : parts)
1409 table = table->get_table(part).get();
1415 throw std::out_of_range{key +
" is not a valid key"};
1420 return table->map_.count(last_key) != 0;
1422 *p = table->map_.at(last_key);
1426 string_to_base_map map_;
1439 inline typename array_of_trait<array>::return_type
1440 table::get_array_of<array>(
const std::string& key)
const 1442 if (
auto v = get_array(key))
1444 std::vector<std::shared_ptr<array>> result;
1445 result.reserve(v->get().size());
1447 for (
const auto& b : v->get())
1449 if (
auto val = b->as_array())
1450 result.push_back(val);
1455 return {std::move(result)};
1472 table::get_qualified_array_of<array>(
const std::string& key)
const 1474 if (
auto v = get_array_qualified(key))
1476 std::vector<std::shared_ptr<array>> result;
1477 result.reserve(v->get().size());
1479 for (
const auto& b : v->get())
1481 if (
auto val = b->as_array())
1482 result.push_back(val);
1487 return {std::move(result)};
1493 std::shared_ptr<table> make_table()
1495 struct make_shared_enabler :
public table 1497 make_shared_enabler()
1503 return std::make_shared<make_shared_enabler>();
1507 inline std::shared_ptr<table> make_element<table>()
1509 return make_table();
1513 std::shared_ptr<base> value<T>::clone()
const 1515 return make_value(data_);
1518 inline std::shared_ptr<base> array::clone()
const 1520 auto result = make_array();
1521 result->reserve(values_.size());
1522 for (
const auto& ptr : values_)
1523 result->values_.push_back(ptr->clone());
1527 inline std::shared_ptr<base> table_array::clone()
const 1529 auto result = make_table_array();
1530 result->reserve(array_.size());
1531 for (
const auto& ptr : array_)
1532 result->array_.push_back(ptr->clone()->as_table());
1536 inline std::shared_ptr<base> table::clone()
const 1538 auto result = make_table();
1539 for (
const auto& pr : map_)
1540 result->insert(pr.first, pr.second->clone());
1555 : std::runtime_error{err +
" at line " + std::to_string(line_number)}
1560 inline bool is_number(
char c)
1562 return c >=
'0' && c <=
'9';
1568 template <
class OnError>
1572 consumer(std::string::iterator& it,
const std::string::iterator& end,
1574 : it_(it), end_(end), on_error_(std::forward<OnError>(on_error))
1579 void operator()(
char c)
1581 if (it_ == end_ || *it_ != c)
1586 template <std::
size_t N>
1587 void operator()(
const char (&str)[N])
1589 std::for_each(std::begin(str), std::end(str) - 1,
1590 [&](
char c) { (*this)(c); });
1593 int eat_digits(
int len)
1596 for (
int i = 0; i < len; ++i)
1598 if (!is_number(*it_) || it_ == end_)
1600 val = 10 * val + (*it_++ -
'0');
1611 std::string::iterator& it_;
1612 const std::string::iterator& end_;
1616 template <
class OnError>
1618 const std::string::iterator& end,
1628 inline std::istream& getline(std::istream& input, std::string& line)
1632 std::istream::sentry sentry{input,
true};
1633 auto sb = input.rdbuf();
1637 auto c = sb->sbumpc();
1640 if (sb->sgetc() ==
'\n')
1647 if (c == std::istream::traits_type::eof())
1650 input.setstate(std::ios::eofbit);
1654 line.push_back(static_cast<char>(c));
1668 parser(std::istream& stream) : input_(stream)
1681 std::shared_ptr<table> root = make_table();
1685 while (detail::getline(input_, line_))
1688 auto it = line_.begin();
1689 auto end = line_.end();
1690 consume_whitespace(it, end);
1691 if (it == end || *it ==
'#')
1695 curr_table = root.
get();
1696 parse_table(it, end, curr_table);
1700 parse_key_value(it, end, curr_table);
1701 consume_whitespace(it, end);
1702 eol_or_comment(it, end);
1709 #if defined _MSC_VER 1710 __declspec(noreturn)
1711 #elif defined __GNUC__ 1712 __attribute__((noreturn))
1714 void throw_parse_exception(
const std::string& err)
1719 void parse_table(std::string::iterator& it,
1720 const std::string::iterator& end, table*& curr_table)
1725 throw_parse_exception(
"Unexpected end of table");
1727 parse_table_array(it, end, curr_table);
1729 parse_single_table(it, end, curr_table);
1732 void parse_single_table(std::string::iterator& it,
1733 const std::string::iterator& end,
1736 if (it == end || *it ==
']')
1737 throw_parse_exception(
"Table name cannot be empty");
1739 std::string full_table_name;
1740 bool inserted =
false;
1741 while (it != end && *it !=
']')
1743 auto part = parse_key(it, end,
1744 [](
char c) {
return c ==
'.' || c ==
']'; });
1747 throw_parse_exception(
"Empty component of table name");
1749 if (!full_table_name.empty())
1750 full_table_name +=
".";
1751 full_table_name += part;
1753 if (curr_table->contains(part))
1755 auto b = curr_table->get(part);
1757 curr_table = static_cast<table*>(b.get());
1758 else if (b->is_table_array())
1759 curr_table = std::static_pointer_cast<table_array>(b)
1764 throw_parse_exception(
"Key " + full_table_name
1765 +
"already exists as a value");
1770 curr_table->insert(part, make_table());
1771 curr_table =
static_cast<table*
>(curr_table->get(part).get());
1773 consume_whitespace(it, end);
1774 if (it != end && *it ==
'.')
1776 consume_whitespace(it, end);
1780 throw_parse_exception(
1781 "Unterminated table declaration; did you forget a ']'?");
1787 = [](
const std::pair<
const std::string&,
1788 const std::shared_ptr<base>&>& p) {
1789 return p.second->is_value();
1796 if (curr_table->empty() || std::any_of(curr_table->begin(),
1797 curr_table->end(), is_value))
1799 throw_parse_exception(
"Redefinition of table " 1805 consume_whitespace(it, end);
1806 eol_or_comment(it, end);
1809 void parse_table_array(std::string::iterator& it,
1810 const std::string::iterator& end, table*& curr_table)
1813 if (it == end || *it ==
']')
1814 throw_parse_exception(
"Table array name cannot be empty");
1816 std::string full_ta_name;
1817 while (it != end && *it !=
']')
1819 auto part = parse_key(it, end,
1820 [](
char c) {
return c ==
'.' || c ==
']'; });
1823 throw_parse_exception(
"Empty component of table array name");
1825 if (!full_ta_name.empty())
1826 full_ta_name +=
".";
1827 full_ta_name += part;
1829 consume_whitespace(it, end);
1830 if (it != end && *it ==
'.')
1832 consume_whitespace(it, end);
1834 if (curr_table->contains(part))
1836 auto b = curr_table->get(part);
1840 if (it != end && *it ==
']')
1842 if (!b->is_table_array())
1843 throw_parse_exception(
"Key " + full_ta_name
1844 +
" is not a table array");
1845 auto v = b->as_table_array();
1846 v->get().push_back(make_table());
1847 curr_table = v->get().back().get();
1853 curr_table = static_cast<table*>(b.get());
1854 else if (b->is_table_array())
1855 curr_table = std::static_pointer_cast<table_array>(b)
1860 throw_parse_exception(
"Key " + full_ta_name
1861 +
" already exists as a value");
1869 if (it != end && *it ==
']')
1871 curr_table->insert(part, make_table_array());
1872 auto arr = std::static_pointer_cast<table_array>(
1873 curr_table->get(part));
1874 arr->get().push_back(make_table());
1875 curr_table = arr->get().back().get();
1881 curr_table->insert(part, make_table());
1883 =
static_cast<table*
>(curr_table->get(part).get());
1890 throw_parse_exception(
"Unterminated table array name");
1893 throw_parse_exception(
"Unterminated table array name");
1896 consume_whitespace(it, end);
1897 eol_or_comment(it, end);
1900 void parse_key_value(std::string::iterator& it, std::string::iterator& end,
1903 auto key = parse_key(it, end, [](
char c) {
return c ==
'='; });
1904 if (curr_table->contains(key))
1905 throw_parse_exception(
"Key " + key +
" already present");
1906 if (it == end || *it !=
'=')
1907 throw_parse_exception(
"Value must follow after a '='");
1909 consume_whitespace(it, end);
1910 curr_table->insert(key, parse_value(it, end));
1911 consume_whitespace(it, end);
1914 template <
class Function>
1915 std::string parse_key(std::string::iterator& it,
1916 const std::string::iterator& end, Function&& fun)
1918 consume_whitespace(it, end);
1921 return parse_quoted_key(it, end);
1925 auto bke = std::find_if(it, end, std::forward<Function>(fun));
1926 return parse_bare_key(it, bke);
1930 std::string parse_bare_key(std::string::iterator& it,
1931 const std::string::iterator& end)
1935 throw_parse_exception(
"Bare key missing name");
1940 consume_backwards_whitespace(key_end, it);
1942 std::string key{it, key_end};
1944 if (std::find(it, key_end,
'#') != key_end)
1946 throw_parse_exception(
"Bare key " + key +
" cannot contain #");
1949 if (std::find_if(it, key_end,
1950 [](
char c) {
return c ==
' ' || c ==
'\t'; })
1953 throw_parse_exception(
"Bare key " + key
1954 +
" cannot contain whitespace");
1957 if (std::find_if(it, key_end,
1958 [](
char c) {
return c ==
'[' || c ==
']'; })
1961 throw_parse_exception(
"Bare key " + key
1962 +
" cannot contain '[' or ']'");
1969 std::string parse_quoted_key(std::string::iterator& it,
1970 const std::string::iterator& end)
1972 return string_literal(it, end,
'"');
1975 enum class parse_type
1989 std::shared_ptr<base> parse_value(std::string::iterator& it,
1990 std::string::iterator& end)
1992 parse_type type = determine_value_type(it, end);
1995 case parse_type::STRING:
1996 return parse_string(it, end);
1997 case parse_type::LOCAL_TIME:
1998 return parse_time(it, end);
1999 case parse_type::LOCAL_DATE:
2000 case parse_type::LOCAL_DATETIME:
2001 case parse_type::OFFSET_DATETIME:
2002 return parse_date(it, end);
2003 case parse_type::INT:
2004 case parse_type::FLOAT:
2005 return parse_number(it, end);
2006 case parse_type::BOOL:
2007 return parse_bool(it, end);
2008 case parse_type::ARRAY:
2009 return parse_array(it, end);
2010 case parse_type::INLINE_TABLE:
2011 return parse_inline_table(it, end);
2013 throw_parse_exception(
"Failed to parse value");
2017 parse_type determine_value_type(
const std::string::iterator& it,
2018 const std::string::iterator& end)
2020 if (*it ==
'"' || *it ==
'\'')
2022 return parse_type::STRING;
2024 else if (is_time(it, end))
2026 return parse_type::LOCAL_TIME;
2028 else if (
auto dtype = date_type(it, end))
2032 else if (is_number(*it) || *it ==
'-' || *it ==
'+')
2034 return determine_number_type(it, end);
2036 else if (*it ==
't' || *it ==
'f')
2038 return parse_type::BOOL;
2040 else if (*it ==
'[')
2042 return parse_type::ARRAY;
2044 else if (*it ==
'{')
2046 return parse_type::INLINE_TABLE;
2048 throw_parse_exception(
"Failed to parse value type");
2051 parse_type determine_number_type(
const std::string::iterator& it,
2052 const std::string::iterator& end)
2056 if (*check_it ==
'-' || *check_it ==
'+')
2058 while (check_it != end && is_number(*check_it))
2060 if (check_it != end && *check_it ==
'.')
2063 while (check_it != end && is_number(*check_it))
2065 return parse_type::FLOAT;
2069 return parse_type::INT;
2073 std::shared_ptr<value<std::string>> parse_string(std::string::iterator& it,
2074 std::string::iterator& end)
2077 assert(delim ==
'"' || delim ==
'\'');
2083 if (check_it != end && *check_it == delim)
2086 if (check_it != end && *check_it == delim)
2089 return parse_multiline_string(it, end, delim);
2092 return make_value<std::string>(string_literal(it, end, delim));
2095 std::shared_ptr<value<std::string>>
2096 parse_multiline_string(std::string::iterator& it,
2097 std::string::iterator& end,
char delim)
2099 std::stringstream ss;
2101 auto is_ws = [](
char c) {
return c ==
' ' || c ==
'\t'; };
2103 bool consuming =
false;
2104 std::shared_ptr<value<std::string>> ret;
2107 = [&](std::string::iterator& it, std::string::iterator& end) {
2110 it = std::find_if_not(it, end, is_ws);
2122 if (delim ==
'"' && *it ==
'\\')
2128 consume_whitespace(check, end);
2135 ss << parse_escape_code(it, end);
2140 if (std::distance(it, end) >= 3)
2144 if (*check++ == delim && *check++ == delim
2145 && *check++ == delim)
2148 ret = make_value<std::string>(ss.str());
2158 handle_line(it, end);
2163 while (detail::getline(input_, line_))
2170 handle_line(it, end);
2179 throw_parse_exception(
"Unterminated multi-line basic string");
2182 std::string string_literal(std::string::iterator& it,
2183 const std::string::iterator& end,
char delim)
2190 if (delim ==
'"' && *it ==
'\\')
2192 val += parse_escape_code(it, end);
2194 else if (*it == delim)
2197 consume_whitespace(it, end);
2205 throw_parse_exception(
"Unterminated string literal");
2208 std::string parse_escape_code(std::string::iterator& it,
2209 const std::string::iterator& end)
2213 throw_parse_exception(
"Invalid escape sequence");
2219 else if (*it ==
't')
2223 else if (*it ==
'n')
2227 else if (*it ==
'f')
2231 else if (*it ==
'r')
2235 else if (*it ==
'"')
2239 else if (*it ==
'\\')
2243 else if (*it ==
'u' || *it ==
'U')
2245 return parse_unicode(it, end);
2249 throw_parse_exception(
"Invalid escape sequence");
2252 return std::string(1, value);
2255 std::string parse_unicode(std::string::iterator& it,
2256 const std::string::iterator& end)
2258 bool large = *it++ ==
'U';
2259 auto codepoint = parse_hex(it, end, large ? 0x10000000 : 0x1000);
2261 if ((codepoint > 0xd7ff && codepoint < 0xe000) || codepoint > 0x10ffff)
2263 throw_parse_exception(
2264 "Unicode escape sequence is not a Unicode scalar value");
2269 if (codepoint <= 0x7f)
2273 result +=
static_cast<char>(codepoint & 0x7f);
2275 else if (codepoint <= 0x7ff)
2283 result +=
static_cast<char>(0xc0 | ((codepoint >> 6) & 0x1f));
2288 result +=
static_cast<char>(0x80 | (codepoint & 0x3f));
2290 else if (codepoint <= 0xffff)
2298 result +=
static_cast<char>(0xe0 | ((codepoint >> 12) & 0x0f));
2299 result +=
static_cast<char>(0x80 | ((codepoint >> 6) & 0x1f));
2300 result +=
static_cast<char>(0x80 | (codepoint & 0x3f));
2310 result +=
static_cast<char>(0xf0 | ((codepoint >> 18) & 0x07));
2311 result +=
static_cast<char>(0x80 | ((codepoint >> 12) & 0x3f));
2312 result +=
static_cast<char>(0x80 | ((codepoint >> 6) & 0x3f));
2313 result +=
static_cast<char>(0x80 | (codepoint & 0x3f));
2318 uint32_t parse_hex(std::string::iterator& it,
2319 const std::string::iterator& end, uint32_t place)
2325 throw_parse_exception(
"Unexpected end of unicode sequence");
2328 throw_parse_exception(
"Invalid unicode escape sequence");
2330 value += place * hex_to_digit(*it++);
2338 return is_number(c) || (c >=
'a' && c <= 'f') || (c >=
'A' && c <=
'F');
2341 uint32_t hex_to_digit(
char c)
2344 return static_cast<uint32_t
>(c -
'0');
2345 return 10 +
static_cast<uint32_t
>(
2346 c - ((c >=
'a' && c <=
'f') ?
'a' :
'A'));
2349 std::shared_ptr<base> parse_number(std::string::iterator& it,
2350 const std::string::iterator& end)
2353 auto check_end = find_end_of_number(it, end);
2355 auto eat_sign = [&]() {
2356 if (check_it != end && (*check_it ==
'-' || *check_it ==
'+'))
2362 auto eat_numbers = [&]() {
2363 auto beg = check_it;
2364 while (check_it != end && is_number(*check_it))
2367 if (check_it != end && *check_it ==
'_')
2370 if (check_it == end || !is_number(*check_it))
2371 throw_parse_exception(
"Malformed number");
2375 if (check_it == beg)
2376 throw_parse_exception(
"Malformed number");
2379 auto check_no_leading_zero = [&]() {
2380 if (check_it != end && *check_it ==
'0' && check_it + 1 != check_end
2381 && check_it[1] !=
'.')
2383 throw_parse_exception(
"Numbers may not have leading zeros");
2387 check_no_leading_zero();
2391 && (*check_it ==
'.' || *check_it ==
'e' || *check_it ==
'E'))
2393 bool is_exp = *check_it ==
'e' || *check_it ==
'E';
2396 if (check_it == end)
2397 throw_parse_exception(
"Floats must have trailing digits");
2399 auto eat_exp = [&]() {
2401 check_no_leading_zero();
2410 if (!is_exp && check_it != end
2411 && (*check_it ==
'e' || *check_it ==
'E'))
2417 return parse_float(it, check_it);
2421 return parse_int(it, check_it);
2425 std::shared_ptr<value<int64_t>> parse_int(std::string::iterator& it,
2426 const std::string::iterator& end)
2428 std::string v{it, end};
2429 v.erase(std::remove(v.begin(), v.end(),
'_'), v.end());
2433 return make_value<int64_t>(std::stoll(v));
2435 catch (
const std::invalid_argument& ex)
2437 throw_parse_exception(
"Malformed number (invalid argument: " 2438 + std::string{ex.what()} +
")");
2440 catch (
const std::out_of_range& ex)
2442 throw_parse_exception(
"Malformed number (out of range: " 2443 + std::string{ex.what()} +
")");
2447 std::shared_ptr<value<double>> parse_float(std::string::iterator& it,
2448 const std::string::iterator& end)
2450 std::string v{it, end};
2451 v.erase(std::remove(v.begin(), v.end(),
'_'), v.end());
2455 return make_value<double>(std::stod(v));
2457 catch (
const std::invalid_argument& ex)
2459 throw_parse_exception(
"Malformed number (invalid argument: " 2460 + std::string{ex.what()} +
")");
2462 catch (
const std::out_of_range& ex)
2464 throw_parse_exception(
"Malformed number (out of range: " 2465 + std::string{ex.what()} +
")");
2469 std::shared_ptr<value<bool>> parse_bool(std::string::iterator& it,
2470 const std::string::iterator& end)
2472 auto eat = make_consumer(it, end, [
this]() {
2473 throw_parse_exception(
"Attempted to parse invalid boolean value");
2479 return make_value<bool>(
true);
2481 else if (*it ==
'f')
2484 return make_value<bool>(
false);
2491 std::string::iterator find_end_of_number(std::string::iterator it,
2492 std::string::iterator end)
2494 return std::find_if(it, end, [](
char c) {
2495 return !is_number(c) && c !=
'_' && c !=
'.' && c !=
'e' && c !=
'E' 2496 && c !=
'-' && c !=
'+';
2500 std::string::iterator find_end_of_date(std::string::iterator it,
2501 std::string::iterator end)
2503 return std::find_if(it, end, [](
char c) {
2504 return !is_number(c) && c !=
'T' && c !=
'Z' && c !=
':' && c !=
'-' 2505 && c !=
'+' && c !=
'.';
2509 std::string::iterator find_end_of_time(std::string::iterator it,
2510 std::string::iterator end)
2512 return std::find_if(it, end, [](
char c) {
2513 return !is_number(c) && c !=
':' && c !=
'.';
2517 local_time read_time(std::string::iterator& it,
2518 const std::string::iterator& end)
2520 auto time_end = find_end_of_time(it, end);
2522 auto eat = make_consumer(
2523 it, time_end, [&]() { throw_parse_exception(
"Malformed time"); });
2527 ltime.hour = eat.eat_digits(2);
2529 ltime.minute = eat.eat_digits(2);
2531 ltime.second = eat.eat_digits(2);
2534 if (it != time_end && *it ==
'.')
2537 while (it != time_end && is_number(*it))
2539 ltime.microsecond += power * (*it++ -
'0');
2545 throw_parse_exception(
"Malformed time");
2550 std::shared_ptr<value<local_time>>
2551 parse_time(std::string::iterator& it,
const std::string::iterator& end)
2553 return make_value(read_time(it, end));
2556 std::shared_ptr<base> parse_date(std::string::iterator& it,
2557 const std::string::iterator& end)
2559 auto date_end = find_end_of_date(it, end);
2561 auto eat = make_consumer(
2562 it, date_end, [&]() { throw_parse_exception(
"Malformed date"); });
2565 ldate.year = eat.eat_digits(4);
2567 ldate.month = eat.eat_digits(2);
2569 ldate.day = eat.eat_digits(2);
2572 return make_value(ldate);
2577 static_cast<local_date&
>(ldt) = ldate;
2578 static_cast<local_time&
>(ldt) = read_time(it, date_end);
2581 return make_value(ldt);
2584 static_cast<local_datetime&
>(dt) = ldt;
2588 if (*it ==
'+' || *it ==
'-')
2590 auto plus = *it ==
'+';
2593 hoff = eat.eat_digits(2);
2594 dt.hour_offset = (plus) ? hoff : -hoff;
2596 moff = eat.eat_digits(2);
2597 dt.minute_offset = (plus) ? moff : -moff;
2599 else if (*it ==
'Z')
2605 throw_parse_exception(
"Malformed date");
2607 return make_value(dt);
2610 std::shared_ptr<base> parse_array(std::string::iterator& it,
2611 std::string::iterator& end)
2622 skip_whitespace_and_comments(it, end);
2628 return make_array();
2631 auto val_end = std::find_if(
2632 it, end, [](
char c) {
return c ==
',' || c ==
']' || c ==
'#'; });
2633 parse_type type = determine_value_type(it, val_end);
2636 case parse_type::STRING:
2637 return parse_value_array<std::string>(it, end);
2638 case parse_type::LOCAL_TIME:
2639 return parse_value_array<local_time>(it, end);
2640 case parse_type::LOCAL_DATE:
2641 return parse_value_array<local_date>(it, end);
2642 case parse_type::LOCAL_DATETIME:
2643 return parse_value_array<local_datetime>(it, end);
2644 case parse_type::OFFSET_DATETIME:
2645 return parse_value_array<offset_datetime>(it, end);
2646 case parse_type::INT:
2647 return parse_value_array<int64_t>(it, end);
2648 case parse_type::FLOAT:
2649 return parse_value_array<double>(it, end);
2650 case parse_type::BOOL:
2651 return parse_value_array<bool>(it, end);
2652 case parse_type::ARRAY:
2653 return parse_object_array<array>(&parser::parse_array,
'[', it,
2655 case parse_type::INLINE_TABLE:
2656 return parse_object_array<table_array>(
2657 &parser::parse_inline_table,
'{', it, end);
2659 throw_parse_exception(
"Unable to parse array");
2663 template <
class Value>
2664 std::shared_ptr<array> parse_value_array(std::string::iterator& it,
2665 std::string::iterator& end)
2667 auto arr = make_array();
2668 while (it != end && *it !=
']')
2670 auto value = parse_value(it, end);
2671 if (
auto v = value->as<Value>())
2672 arr->get().push_back(value);
2674 throw_parse_exception(
"Arrays must be heterogeneous");
2675 skip_whitespace_and_comments(it, end);
2679 skip_whitespace_and_comments(it, end);
2686 template <
class Object,
class Function>
2687 std::shared_ptr<Object> parse_object_array(Function&& fun,
char delim,
2688 std::string::iterator& it,
2689 std::string::iterator& end)
2691 auto arr = make_element<Object>();
2693 while (it != end && *it !=
']')
2696 throw_parse_exception(
"Unexpected character in array");
2698 arr->get().push_back(((*this).*fun)(it, end));
2699 skip_whitespace_and_comments(it, end);
2705 skip_whitespace_and_comments(it, end);
2708 if (it == end || *it !=
']')
2709 throw_parse_exception(
"Unterminated array");
2715 std::shared_ptr<table> parse_inline_table(std::string::iterator& it,
2716 std::string::iterator& end)
2718 auto tbl = make_table();
2723 throw_parse_exception(
"Unterminated inline table");
2725 consume_whitespace(it, end);
2726 parse_key_value(it, end, tbl.get());
2727 consume_whitespace(it, end);
2728 }
while (*it ==
',');
2730 if (it == end || *it !=
'}')
2731 throw_parse_exception(
"Unterminated inline table");
2734 consume_whitespace(it, end);
2739 void skip_whitespace_and_comments(std::string::iterator& start,
2740 std::string::iterator& end)
2742 consume_whitespace(start, end);
2743 while (start == end || *start ==
'#')
2745 if (!detail::getline(input_, line_))
2746 throw_parse_exception(
"Unclosed array");
2748 start = line_.begin();
2750 consume_whitespace(start, end);
2754 void consume_whitespace(std::string::iterator& it,
2755 const std::string::iterator& end)
2757 while (it != end && (*it ==
' ' || *it ==
'\t'))
2761 void consume_backwards_whitespace(std::string::iterator& back,
2762 const std::string::iterator& front)
2764 while (back != front && (*back ==
' ' || *back ==
'\t'))
2768 void eol_or_comment(
const std::string::iterator& it,
2769 const std::string::iterator& end)
2771 if (it != end && *it !=
'#')
2772 throw_parse_exception(
"Unidentified trailing character '" 2774 +
"'---did you forget a '#'?");
2777 bool is_time(
const std::string::iterator& it,
2778 const std::string::iterator& end)
2780 auto time_end = find_end_of_time(it, end);
2781 auto len = std::distance(it, time_end);
2786 if (it[2] !=
':' || it[5] !=
':')
2790 return it[8] ==
'.' && len > 9;
2795 option<parse_type> date_type(
const std::string::iterator& it,
2796 const std::string::iterator& end)
2798 auto date_end = find_end_of_date(it, end);
2799 auto len = std::distance(it, date_end);
2804 if (it[4] !=
'-' || it[7] !=
'-')
2807 if (len >= 19 && it[10] ==
'T' && is_time(it + 11, date_end))
2810 auto time_end = find_end_of_time(it + 11, date_end);
2811 if (time_end == date_end)
2812 return {parse_type::LOCAL_DATETIME};
2814 return {parse_type::OFFSET_DATETIME};
2819 return {parse_type::LOCAL_DATE};
2825 std::istream& input_;
2827 std::size_t line_number_ = 0;
2834 inline std::shared_ptr<table>
parse_file(
const std::string& filename)
2836 #if defined(BOOST_NOWIDE_FSTREAM_INCLUDED_HPP) 2837 boost::nowide::ifstream file{filename.c_str()};
2838 #elif defined(NOWIDE_FSTREAM_INCLUDED_HPP) 2839 nowide::ifstream file{filename.c_str()};
2841 std::ifstream file{filename};
2843 if (!file.is_open())
2849 template <
class... Ts>
2855 template <
class Visitor,
class... Args>
2856 static void accept(
const base&, Visitor&&, Args&&...)
2862 template <
class T,
class... Ts>
2865 template <
class Visitor,
class... Args>
2866 static void accept(
const base& b, Visitor&& visitor, Args&&... args)
2868 if (
auto v = b.
as<T>())
2870 visitor.visit(*v, std::forward<Args>(args)...);
2875 std::forward<Args>(args)...);
2884 template <
class Visitor,
class... Args>
2889 using value_acceptor
2892 value_acceptor::accept(*
this, std::forward<Visitor>(visitor),
2893 std::forward<Args>(args)...);
2897 visitor.visit(static_cast<const table&>(*
this),
2898 std::forward<Args>(args)...);
2902 visitor.visit(static_cast<const array&>(*
this),
2903 std::forward<Args>(args)...);
2907 visitor.visit(static_cast<const table_array&>(*
this),
2908 std::forward<Args>(args)...);
2923 : stream_(s), indent_(indent_space), has_naked_endline_(false)
2944 std::vector<std::string> values;
2945 std::vector<std::string> tables;
2947 for (
const auto& i : t)
2949 if (i.second->is_table() || i.second->is_table_array())
2951 tables.push_back(i.first);
2955 values.push_back(i.first);
2959 for (
unsigned int i = 0; i < values.size(); ++i)
2961 path_.push_back(values[i]);
2967 t.get(values[i])->accept(*
this,
false);
2971 for (
unsigned int i = 0; i < tables.size(); ++i)
2973 path_.push_back(tables[i]);
2975 if (values.size() > 0 || i > 0)
2979 t.get(tables[i])->accept(*
this,
false);
2993 for (
unsigned int i = 0; i < a.
get().size(); ++i)
2998 if (a.
get()[i]->is_array())
3000 a.
get()[i]->as_array()->accept(*
this,
true);
3004 a.
get()[i]->accept(*
this,
true);
3016 for (
unsigned int j = 0; j < t.get().size(); ++j)
3021 t.get()[j]->accept(*
this,
true);
3033 for (
auto it = str.begin(); it != str.end(); ++it)
3039 else if (*it ==
'\t')
3043 else if (*it ==
'\n')
3047 else if (*it ==
'\f')
3051 else if (*it ==
'\r')
3055 else if (*it ==
'"')
3059 else if (*it ==
'\\')
3063 else if (*it >= 0x0000 && *it <= 0x001f)
3066 std::stringstream ss;
3067 ss << std::hex << static_cast<uint32_t>(*it);
3094 std::ios::fmtflags flags{stream_.flags()};
3096 stream_ << std::showpoint;
3099 stream_.flags(flags);
3120 write((v.get() ?
"true" :
"false"));
3139 for (
unsigned int i = 0; i < path_.size(); ++i)
3146 if (path_[i].find_first_not_of(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcde" 3147 "fghijklmnopqrstuvwxyz0123456789" 3149 == std::string::npos)
3180 if (path_.back().find_first_not_of(
"ABCDEFGHIJKLMNOPQRSTUVWXYZabcde" 3181 "fghijklmnopqrstuvwxyz0123456789" 3183 == std::string::npos)
3185 write(path_.back());
3205 for (std::size_t i = 1; i < path_.size(); ++i)
3216 has_naked_endline_ =
false;
3224 if (!has_naked_endline_)
3227 has_naked_endline_ =
true;
3232 std::ostream& stream_;
3233 const std::string indent_;
3234 std::vector<std::string> path_;
3235 bool has_naked_endline_;
3238 inline std::ostream& operator<<(std::ostream& stream,
const base& b)
3240 toml_writer writer{stream};
3246 std::ostream& operator<<(std::ostream& stream, const value<T>& v)
3248 toml_writer writer{stream};
3253 inline std::ostream& operator<<(std::ostream& stream,
const table& t)
3255 toml_writer writer{stream};
3260 inline std::ostream& operator<<(std::ostream& stream,
const table_array& t)
3262 toml_writer writer{stream};
3267 inline std::ostream& operator<<(std::ostream& stream,
const array& a)
3269 toml_writer writer{stream};
std::shared_ptr< base > get_qualified(const std::string &key) const
Obtains the base for a given key.
Definition: cpptoml.h:1175
Definition: cpptoml.h:615
iterator insert(iterator position, const std::shared_ptr< value< T >> &value)
Insert a value into the array.
Definition: cpptoml.h:779
void insert(const std::string &key, const std::shared_ptr< base > &value)
Adds an element to the keytable.
Definition: cpptoml.h:1346
std::shared_ptr< value< T > > as()
Attempts to coerce the TOML element into a concrete TOML value of type T.
Definition: cpptoml.h:560
iterator insert(iterator position, const std::shared_ptr< array > &value)
Insert an array into the array.
Definition: cpptoml.h:794
void reserve(size_type n)
Reserve space for n tables.
Definition: cpptoml.h:988
void push_back(const std::shared_ptr< value< T >> &val)
Add a value to the end of the array.
Definition: cpptoml.h:738
array_of_trait< T >::return_type get_qualified_array_of(const std::string &key) const
Helper function that attempts to get an array of values of a given type corresponding to the template...
Definition: cpptoml.h:1323
std::shared_ptr< table_array > as_table_array()
Converts the TOML element into a table array.
Definition: cpptoml.h:462
std::shared_ptr< array > get_array_qualified(const std::string &key) const
Obtains an array for a given key.
Definition: cpptoml.h:1216
Definition: cpptoml.h:282
virtual bool is_table_array() const override
Determines if the given TOML element is an array of tables.
Definition: cpptoml.h:938
void visit(const value< T > &v, bool=false)
Output a base value of the TOML tree.
Definition: cpptoml.h:2933
Definition: cpptoml.h:379
void write(const value< std::string > &v)
Write out a string.
Definition: cpptoml.h:3082
void visit(const table &t, bool in_array=false)
Output a table element of the TOML tree.
Definition: cpptoml.h:2941
static std::string escape_string(const std::string &str)
Escape a string for output.
Definition: cpptoml.h:3030
iterator erase(iterator position)
Erase an element from the array.
Definition: cpptoml.h:972
std::shared_ptr< base > get(const std::string &key) const
Obtains the base for a given key.
Definition: cpptoml.h:1163
A generic base TOML value used for type erasure.
Definition: cpptoml.h:401
bool contains(const std::string &key) const
Determines if this key table contains the given key.
Definition: cpptoml.h:1144
std::shared_ptr< array > as_array()
Converts the TOML element to an array.
Definition: cpptoml.h:444
std::enable_if< is_one_of< T, int64_t, local_date, local_time, local_datetime, offset_datetime >::value >::type write(const value< T > &v)
Write out an integer, local_date, local_time, local_datetime, or offset_datetime. ...
Definition: cpptoml.h:3110
virtual bool is_table() const
Determines if the given TOML element is a table.
Definition: cpptoml.h:419
void clear()
Clear the array.
Definition: cpptoml.h:827
std::vector< std::shared_ptr< table > >::const_iterator const_iterator
arrays can be iterated over.
Definition: cpptoml.h:916
std::shared_ptr< table_array > get_table_array(const std::string &key) const
Obtains a table_array for a given key, if possible.
Definition: cpptoml.h:1226
Definition: cpptoml.h:285
Writer that can be passed to accept() functions of cpptoml objects and will output valid TOML to a st...
Definition: cpptoml.h:2916
virtual bool is_array() const override
Determines if the TOML element is an array of "leaf" elements.
Definition: cpptoml.h:622
virtual bool is_array() const
Determines if the TOML element is an array of "leaf" elements.
Definition: cpptoml.h:436
string_to_base_map::const_iterator const_iterator
tables can be iterated over.
Definition: cpptoml.h:1109
void write(const value< double > &v)
Write out a double.
Definition: cpptoml.h:3092
Helper object for consuming expected characters.
Definition: cpptoml.h:1569
Exception class for all TOML parsing errors.
Definition: cpptoml.h:1547
value(const T &val)
Constructs a value from the given data.
Definition: cpptoml.h:542
The parser class.
Definition: cpptoml.h:1662
Definition: cpptoml.h:101
std::shared_ptr< table > get_table_qualified(const std::string &key) const
Obtains a table for a given key, if possible.
Definition: cpptoml.h:1196
Represents a TOML keytable.
Definition: cpptoml.h:1093
std::shared_ptr< table > parse()
Parses the stream this parser was created on until EOF.
Definition: cpptoml.h:1679
virtual bool is_value() const
Determines if the given TOML element is a value.
Definition: cpptoml.h:411
Definition: cpptoml.h:898
void push_back(T &&val, typename value_traits< T >::type *=0)
Convenience function for adding a simple element to the end of the array.
Definition: cpptoml.h:770
parser(std::istream &stream)
Parsers are constructed from streams.
Definition: cpptoml.h:1668
void write(const value< bool > &v)
Write out a boolean.
Definition: cpptoml.h:3118
std::shared_ptr< array > get_array(const std::string &key) const
Obtains an array for a given key.
Definition: cpptoml.h:1206
std::shared_ptr< table > get_table(const std::string &key) const
Obtains a table for a given key, if possible.
Definition: cpptoml.h:1185
std::shared_ptr< table_array > get_table_array_qualified(const std::string &key) const
Obtains a table_array for a given key, if possible.
Definition: cpptoml.h:1238
void visit(const table_array &t, bool=false)
Output a table_array element of the TOML tree.
Definition: cpptoml.h:3014
void reserve(size_type n)
Reserve space for n values.
Definition: cpptoml.h:835
std::vector< std::shared_ptr< base > >::const_iterator const_iterator
arrays can be iterated over.
Definition: cpptoml.h:637
Definition: cpptoml.h:115
void accept(Visitor &&visitor, Args &&... args) const
base implementation of accept() that calls visitor.visit() on the concrete class. ...
Definition: cpptoml.h:2885
void erase(const std::string &key)
Removes an element from the table.
Definition: cpptoml.h:1365
Definition: cpptoml.h:275
array_of_trait< T >::return_type get_array_of() const
Obtains a option<vector<T>>.
Definition: cpptoml.h:700
bool contains_qualified(const std::string &key) const
Determines if this key table contains the given key.
Definition: cpptoml.h:1154
iterator erase(iterator position)
Erase an element from the array.
Definition: cpptoml.h:819
toml_writer(std::ostream &s, const std::string &indent_space="\)
Construct a toml_writer that will write to the given stream.
Definition: cpptoml.h:2922
Definition: cpptoml.h:257
void insert(const std::string &key, T &&val, typename value_traits< T >::type *=0)
Convenience shorthand for adding a simple element to the keytable.
Definition: cpptoml.h:1356
iterator insert(iterator position, const std::shared_ptr< table > &value)
Insert a table into the array.
Definition: cpptoml.h:964
array_of_trait< T >::return_type get_array_of(const std::string &key) const
Helper function that attempts to get an array of values of a given type corresponding to the template...
Definition: cpptoml.h:1291
Definition: cpptoml.h:162
Exception class for array insertion errors.
Definition: cpptoml.h:607
void indent()
Indent the proper number of tabs given the size of the path.
Definition: cpptoml.h:3203
bool is_table() const override
Determines if the given TOML element is a table.
Definition: cpptoml.h:1131
std::vector< std::shared_ptr< table > >::iterator iterator
arrays can be iterated over
Definition: cpptoml.h:911
void visit(const array &a, bool=false)
Output an array element of the TOML tree.
Definition: cpptoml.h:2989
string_to_base_map::iterator iterator
tables can be iterated over.
Definition: cpptoml.h:1104
void write_table_header(bool in_array=false)
Write out the header of a table.
Definition: cpptoml.h:3126
void write(const T &v)
Write a value out to the stream.
Definition: cpptoml.h:3213
std::vector< std::shared_ptr< base > > & get()
Obtains the array (vector) of base values.
Definition: cpptoml.h:662
void push_back(const std::shared_ptr< array > &val)
Add an array to the end of the array.
Definition: cpptoml.h:753
Definition: cpptoml.h:109
Definition: cpptoml.h:119
std::shared_ptr< table > parse_file(const std::string &filename)
Utility function to parse a file as a TOML file.
Definition: cpptoml.h:2834
std::vector< std::shared_ptr< base > >::iterator iterator
arrays can be iterated over
Definition: cpptoml.h:632
Definition: cpptoml.h:2850
void write_table_item_header(const base &b)
Write out the identifier for an item in a table.
Definition: cpptoml.h:3174
iterator insert(iterator position, T &&val, typename value_traits< T >::type *=0)
Convenience function for inserting a simple element in the array.
Definition: cpptoml.h:810
std::vector< std::shared_ptr< array > > nested_array() const
Obtains an array of arrays.
Definition: cpptoml.h:720
option< T > get_qualified_as(const std::string &key) const
Helper function that attempts to get a value corresponding to the template parameter from a given key...
Definition: cpptoml.h:1268
A concrete TOML value representing the "leaves" of the "tree".
Definition: cpptoml.h:272
virtual bool is_table_array() const
Determines if the given TOML element is an array of tables.
Definition: cpptoml.h:454
void endline()
Write an endline out to the stream.
Definition: cpptoml.h:3222
void clear()
Clear the array.
Definition: cpptoml.h:980
std::vector< std::shared_ptr< value< T > > > array_of() const
Obtains an array of value<T>s.
Definition: cpptoml.h:685
Definition: cpptoml.h:495
std::shared_ptr< table > as_table()
Converts the TOML element into a table.
Definition: cpptoml.h:427
option< T > get_as(const std::string &key) const
Helper function that attempts to get a value corresponding to the template parameter from a given key...
Definition: cpptoml.h:1250
void push_back(const std::shared_ptr< table > &val)
Add a table to the end of the array.
Definition: cpptoml.h:956
bool is_value() const override
Determines if the given TOML element is a value.
Definition: cpptoml.h:515