changeset 318:3b355fa948c7

config: use TOML instead of INI unfortunately, INI is not enough, and causes some paths including semicolons to break with our current storage of the library folders. so, I decided to switch to TOML which does support real arrays...
author Paper <paper@paper.us.eu.org>
date Wed, 12 Jun 2024 05:25:41 -0400
parents b1f4d1867ab1
children d928ec7b6a0d
files Makefile.am dep/mini/ini.h dep/toml11/LICENSE dep/toml11/toml.hpp dep/toml11/toml/color.hpp dep/toml11/toml/combinator.hpp dep/toml11/toml/comments.hpp dep/toml11/toml/datetime.hpp dep/toml11/toml/exception.hpp dep/toml11/toml/from.hpp dep/toml11/toml/get.hpp dep/toml11/toml/into.hpp dep/toml11/toml/lexer.hpp dep/toml11/toml/literal.hpp dep/toml11/toml/macros.hpp dep/toml11/toml/parser.hpp dep/toml11/toml/region.hpp dep/toml11/toml/result.hpp dep/toml11/toml/serializer.hpp dep/toml11/toml/source_location.hpp dep/toml11/toml/storage.hpp dep/toml11/toml/string.hpp dep/toml11/toml/traits.hpp dep/toml11/toml/types.hpp dep/toml11/toml/utility.hpp dep/toml11/toml/value.hpp dep/toml11/toml/version.hpp include/core/config.h include/core/ini.h src/core/config.cc src/core/ini.cc src/gui/dialog/about.cc
diffstat 32 files changed, 11471 insertions(+), 911 deletions(-) [+]
line wrap: on
line diff
--- a/Makefile.am	Wed Jun 12 04:07:10 2024 -0400
+++ b/Makefile.am	Wed Jun 12 05:25:41 2024 -0400
@@ -162,7 +162,6 @@
 	include/core/config.h		\
 	include/core/date.h		\
 	include/core/filesystem.h			\
-	include/core/ini.h		\
 	include/core/json.h			\
 	include/core/strings.h			\
 	include/core/time.h			\
@@ -178,7 +177,30 @@
 	include/track/media.h			\
 	dep/json/json.hpp	\
 	dep/json/json_fwd.hpp	\
-	dep/mini/ini.h	\
+	dep/toml11/toml.hpp \
+	dep/toml11/toml/color.hpp \
+	dep/toml11/toml/combinator.hpp \
+	dep/toml11/toml/comments.hpp \
+	dep/toml11/toml/datetime.hpp \
+	dep/toml11/toml/exception.hpp \
+	dep/toml11/toml/from.hpp \
+	dep/toml11/toml/get.hpp \
+	dep/toml11/toml/into.hpp \
+	dep/toml11/toml/lexer.hpp \
+	dep/toml11/toml/literal.hpp \
+	dep/toml11/toml/macros.hpp \
+	dep/toml11/toml/parser.hpp \
+	dep/toml11/toml/region.hpp \
+	dep/toml11/toml/result.hpp \
+	dep/toml11/toml/serializer.hpp \
+	dep/toml11/toml/source_location.hpp \
+	dep/toml11/toml/storage.hpp \
+	dep/toml11/toml/string.hpp \
+	dep/toml11/toml/traits.hpp \
+	dep/toml11/toml/types.hpp \
+	dep/toml11/toml/utility.hpp \
+	dep/toml11/toml/value.hpp \
+	dep/toml11/toml/version.hpp \
 	dep/semver/semver.hpp	\
 	$(minori_qtheaders)
 
@@ -196,7 +218,6 @@
 	src/core/date.cc		\
 	src/core/filesystem.cc		\
 	src/core/http.cc		\
-	src/core/ini.cc			\
 	src/core/json.cc		\
 	src/core/session.cc     \
 	src/core/strings.cc		\
--- a/dep/mini/ini.h	Wed Jun 12 04:07:10 2024 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,789 +0,0 @@
-/*
- * The MIT License (MIT)
- * Copyright (c) 2018 Danijel Durakovic
- *
- * Permission is hereby granted, free of charge, to any person obtaining a copy of
- * this software and associated documentation files (the "Software"), to deal in
- * the Software without restriction, including without limitation the rights to
- * use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
- * of the Software, and to permit persons to whom the Software is furnished to do
- * so, subject to the following conditions:
- *
- * The above copyright notice and this permission notice shall be included in all
- * copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS
- * FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR
- * COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER
- * IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
- * CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- *
- */
-
-///////////////////////////////////////////////////////////////////////////////
-//
-//  /mINI/ v0.9.14
-//  An INI file reader and writer for the modern age.
-//
-///////////////////////////////////////////////////////////////////////////////
-//
-//  A tiny utility library for manipulating INI files with a straightforward
-//  API and a minimal footprint. It conforms to the (somewhat) standard INI
-//  format - sections and keys are case insensitive and all leading and
-//  trailing whitespace is ignored. Comments are lines that begin with a
-//  semicolon. Trailing comments are allowed on section lines.
-//
-//  Files are read on demand, upon which data is kept in memory and the file
-//  is closed. This utility supports lazy writing, which only writes changes
-//  and updates to a file and preserves custom formatting and comments. A lazy
-//  write invoked by a write() call will read the output file, find what
-//  changes have been made and update the file accordingly. If you only need to
-//  generate files, use generate() instead. Section and key order is preserved
-//  on read, write and insert.
-//
-///////////////////////////////////////////////////////////////////////////////
-//
-//  /* BASIC USAGE EXAMPLE: */
-//
-//  /* read from file */
-//  mINI::INIFile file("myfile.ini");
-//  mINI::INIStructure ini;
-//  file.read(ini);
-//
-//  /* read value; gets a reference to actual value in the structure.
-//     if key or section don't exist, a new empty value will be created */
-//  std::string& value = ini["section"]["key"];
-//
-//  /* read value safely; gets a copy of value in the structure.
-//     does not alter the structure */
-//  std::string value = ini.get("section").get("key");
-//
-//  /* set or update values */
-//  ini["section"]["key"] = "value";
-//
-//  /* set multiple values */
-//  ini["section2"].set({
-//      {"key1", "value1"},
-//      {"key2", "value2"}
-//  });
-//
-//  /* write updates back to file, preserving comments and formatting */
-//  file.write(ini);
-//
-//  /* or generate a file (overwrites the original) */
-//  file.generate(ini);
-//
-///////////////////////////////////////////////////////////////////////////////
-//
-//  Long live the INI file!!!
-//
-///////////////////////////////////////////////////////////////////////////////
-
-#ifndef MINI_INI_H_
-#define MINI_INI_H_
-
-#include <string>
-#include <sstream>
-#include <algorithm>
-#include <utility>
-#include <unordered_map>
-#include <vector>
-#include <memory>
-#include <fstream>
-#include <sys/stat.h>
-#include <cctype>
-
-namespace mINI
-{
-	namespace INIStringUtil
-	{
-		const char* const whitespaceDelimiters = " \t\n\r\f\v";
-		inline void trim(std::string& str)
-		{
-			str.erase(str.find_last_not_of(whitespaceDelimiters) + 1);
-			str.erase(0, str.find_first_not_of(whitespaceDelimiters));
-		}
-#ifndef MINI_CASE_SENSITIVE
-		inline void toLower(std::string& str)
-		{
-			std::transform(str.begin(), str.end(), str.begin(), [](const char c) {
-				return static_cast<char>(std::tolower(c));
-			});
-		}
-#endif
-		inline void replace(std::string& str, std::string const& a, std::string const& b)
-		{
-			if (!a.empty())
-			{
-				std::size_t pos = 0;
-				while ((pos = str.find(a, pos)) != std::string::npos)
-				{
-					str.replace(pos, a.size(), b);
-					pos += b.size();
-				}
-			}
-		}
-#ifdef _WIN32
-		const char* const endl = "\r\n";
-#else
-		const char* const endl = "\n";
-#endif
-	}
-
-	template<typename T>
-	class INIMap
-	{
-	private:
-		using T_DataIndexMap = std::unordered_map<std::string, std::size_t>;
-		using T_DataItem = std::pair<std::string, T>;
-		using T_DataContainer = std::vector<T_DataItem>;
-		using T_MultiArgs = typename std::vector<std::pair<std::string, T>>;
-
-		T_DataIndexMap dataIndexMap;
-		T_DataContainer data;
-
-		inline std::size_t setEmpty(std::string& key)
-		{
-			std::size_t index = data.size();
-			dataIndexMap[key] = index;
-			data.emplace_back(key, T());
-			return index;
-		}
-
-	public:
-		using const_iterator = typename T_DataContainer::const_iterator;
-
-		INIMap() { }
-
-		INIMap(INIMap const& other)
-		{
-			std::size_t data_size = other.data.size();
-			for (std::size_t i = 0; i < data_size; ++i)
-			{
-				auto const& key = other.data[i].first;
-				auto const& obj = other.data[i].second;
-				data.emplace_back(key, obj);
-			}
-			dataIndexMap = T_DataIndexMap(other.dataIndexMap);
-		}
-
-		T& operator[](std::string key)
-		{
-			INIStringUtil::trim(key);
-#ifndef MINI_CASE_SENSITIVE
-			INIStringUtil::toLower(key);
-#endif
-			auto it = dataIndexMap.find(key);
-			bool hasIt = (it != dataIndexMap.end());
-			std::size_t index = (hasIt) ? it->second : setEmpty(key);
-			return data[index].second;
-		}
-		T get(std::string key) const
-		{
-			INIStringUtil::trim(key);
-#ifndef MINI_CASE_SENSITIVE
-			INIStringUtil::toLower(key);
-#endif
-			auto it = dataIndexMap.find(key);
-			if (it == dataIndexMap.end())
-			{
-				return T();
-			}
-			return T(data[it->second].second);
-		}
-		bool has(std::string key) const
-		{
-			INIStringUtil::trim(key);
-#ifndef MINI_CASE_SENSITIVE
-			INIStringUtil::toLower(key);
-#endif
-			return (dataIndexMap.count(key) == 1);
-		}
-		void set(std::string key, T obj)
-		{
-			INIStringUtil::trim(key);
-#ifndef MINI_CASE_SENSITIVE
-			INIStringUtil::toLower(key);
-#endif
-			auto it = dataIndexMap.find(key);
-			if (it != dataIndexMap.end())
-			{
-				data[it->second].second = obj;
-			}
-			else
-			{
-				dataIndexMap[key] = data.size();
-				data.emplace_back(key, obj);
-			}
-		}
-		void set(T_MultiArgs const& multiArgs)
-		{
-			for (auto const& it : multiArgs)
-			{
-				auto const& key = it.first;
-				auto const& obj = it.second;
-				set(key, obj);
-			}
-		}
-		bool remove(std::string key)
-		{
-			INIStringUtil::trim(key);
-#ifndef MINI_CASE_SENSITIVE
-			INIStringUtil::toLower(key);
-#endif
-			auto it = dataIndexMap.find(key);
-			if (it != dataIndexMap.end())
-			{
-				std::size_t index = it->second;
-				data.erase(data.begin() + index);
-				dataIndexMap.erase(it);
-				for (auto& it2 : dataIndexMap)
-				{
-					auto& vi = it2.second;
-					if (vi > index)
-					{
-						vi--;
-					}
-				}
-				return true;
-			}
-			return false;
-		}
-		void clear()
-		{
-			data.clear();
-			dataIndexMap.clear();
-		}
-		std::size_t size() const
-		{
-			return data.size();
-		}
-		const_iterator begin() const { return data.begin(); }
-		const_iterator end() const { return data.end(); }
-	};
-
-	using INIStructure = INIMap<INIMap<std::string>>;
-
-	namespace INIParser
-	{
-		using T_ParseValues = std::pair<std::string, std::string>;
-
-		enum class PDataType : char
-		{
-			PDATA_NONE,
-			PDATA_COMMENT,
-			PDATA_SECTION,
-			PDATA_KEYVALUE,
-			PDATA_UNKNOWN
-		};
-
-		inline PDataType parseLine(std::string line, T_ParseValues& parseData)
-		{
-			parseData.first.clear();
-			parseData.second.clear();
-			INIStringUtil::trim(line);
-			if (line.empty())
-			{
-				return PDataType::PDATA_NONE;
-			}
-			char firstCharacter = line[0];
-			if (firstCharacter == ';')
-			{
-				return PDataType::PDATA_COMMENT;
-			}
-			if (firstCharacter == '[')
-			{
-				auto commentAt = line.find_first_of(';');
-				if (commentAt != std::string::npos)
-				{
-					line = line.substr(0, commentAt);
-				}
-				auto closingBracketAt = line.find_last_of(']');
-				if (closingBracketAt != std::string::npos)
-				{
-					auto section = line.substr(1, closingBracketAt - 1);
-					INIStringUtil::trim(section);
-					parseData.first = section;
-					return PDataType::PDATA_SECTION;
-				}
-			}
-			auto lineNorm = line;
-			INIStringUtil::replace(lineNorm, "\\=", "  ");
-			auto equalsAt = lineNorm.find_first_of('=');
-			if (equalsAt != std::string::npos)
-			{
-				auto key = line.substr(0, equalsAt);
-				INIStringUtil::trim(key);
-				INIStringUtil::replace(key, "\\=", "=");
-				auto value = line.substr(equalsAt + 1);
-				INIStringUtil::trim(value);
-				parseData.first = key;
-				parseData.second = value;
-				return PDataType::PDATA_KEYVALUE;
-			}
-			return PDataType::PDATA_UNKNOWN;
-		}
-	}
-
-	class INIReader
-	{
-	public:
-		using T_LineData = std::vector<std::string>;
-		using T_LineDataPtr = std::shared_ptr<T_LineData>;
-
-		bool isBOM = false;
-
-	private:
-		std::ifstream fileReadStream;
-		T_LineDataPtr lineData;
-
-		T_LineData readFile()
-		{
-			fileReadStream.seekg(0, std::ios::end);
-			const std::size_t fileSize = static_cast<std::size_t>(fileReadStream.tellg());
-			fileReadStream.seekg(0, std::ios::beg);
-			if (fileSize >= 3) {
-				const char header[3] = {
-					static_cast<char>(fileReadStream.get()),
-					static_cast<char>(fileReadStream.get()),
-					static_cast<char>(fileReadStream.get())
-				};
-				isBOM = (
-					header[0] == static_cast<char>(0xEF) &&
-					header[1] == static_cast<char>(0xBB) &&
-					header[2] == static_cast<char>(0xBF)
-				);
-			}
-			else {
-				isBOM = false;
-			}
-			std::string fileContents;
-			fileContents.resize(fileSize);
-			fileReadStream.seekg(isBOM ? 3 : 0, std::ios::beg);
-			fileReadStream.read(&fileContents[0], fileSize);
-			fileReadStream.close();
-			T_LineData output;
-			if (fileSize == 0)
-			{
-				return output;
-			}
-			std::string buffer;
-			buffer.reserve(50);
-			for (std::size_t i = 0; i < fileSize; ++i)
-			{
-				char& c = fileContents[i];
-				if (c == '\n')
-				{
-					output.emplace_back(buffer);
-					buffer.clear();
-					continue;
-				}
-				if (c != '\0' && c != '\r')
-				{
-					buffer += c;
-				}
-			}
-			output.emplace_back(buffer);
-			return output;
-		}
-
-	public:
-		INIReader(std::string const& filename, bool keepLineData = false)
-		{
-			fileReadStream.open(filename, std::ios::in | std::ios::binary);
-			if (keepLineData)
-			{
-				lineData = std::make_shared<T_LineData>();
-			}
-		}
-		~INIReader() { }
-
-		bool operator>>(INIStructure& data)
-		{
-			if (!fileReadStream.is_open())
-			{
-				return false;
-			}
-			T_LineData fileLines = readFile();
-			std::string section;
-			bool inSection = false;
-			INIParser::T_ParseValues parseData;
-			for (auto const& line : fileLines)
-			{
-				auto parseResult = INIParser::parseLine(line, parseData);
-				if (parseResult == INIParser::PDataType::PDATA_SECTION)
-				{
-					inSection = true;
-					data[section = parseData.first];
-				}
-				else if (inSection && parseResult == INIParser::PDataType::PDATA_KEYVALUE)
-				{
-					auto const& key = parseData.first;
-					auto const& value = parseData.second;
-					data[section][key] = value;
-				}
-				if (lineData && parseResult != INIParser::PDataType::PDATA_UNKNOWN)
-				{
-					if (parseResult == INIParser::PDataType::PDATA_KEYVALUE && !inSection)
-					{
-						continue;
-					}
-					lineData->emplace_back(line);
-				}
-			}
-			return true;
-		}
-		T_LineDataPtr getLines()
-		{
-			return lineData;
-		}
-	};
-
-	class INIGenerator
-	{
-	private:
-		std::ofstream fileWriteStream;
-
-	public:
-		bool prettyPrint = false;
-
-		INIGenerator(std::string const& filename)
-		{
-			fileWriteStream.open(filename, std::ios::out | std::ios::binary);
-		}
-		~INIGenerator() { }
-
-		bool operator<<(INIStructure const& data)
-		{
-			if (!fileWriteStream.is_open())
-			{
-				return false;
-			}
-			if (!data.size())
-			{
-				return true;
-			}
-			auto it = data.begin();
-			for (;;)
-			{
-				auto const& section = it->first;
-				auto const& collection = it->second;
-				fileWriteStream
-					<< "["
-					<< section
-					<< "]";
-				if (collection.size())
-				{
-					fileWriteStream << INIStringUtil::endl;
-					auto it2 = collection.begin();
-					for (;;)
-					{
-						auto key = it2->first;
-						INIStringUtil::replace(key, "=", "\\=");
-						auto value = it2->second;
-						INIStringUtil::trim(value);
-						fileWriteStream
-							<< key
-							<< ((prettyPrint) ? " = " : "=")
-							<< value;
-						if (++it2 == collection.end())
-						{
-							break;
-						}
-						fileWriteStream << INIStringUtil::endl;
-					}
-				}
-				if (++it == data.end())
-				{
-					break;
-				}
-				fileWriteStream << INIStringUtil::endl;
-				if (prettyPrint)
-				{
-					fileWriteStream << INIStringUtil::endl;
-				}
-			}
-			return true;
-		}
-	};
-
-	class INIWriter
-	{
-	private:
-		using T_LineData = std::vector<std::string>;
-		using T_LineDataPtr = std::shared_ptr<T_LineData>;
-
-		std::string filename;
-
-		T_LineData getLazyOutput(T_LineDataPtr const& lineData, INIStructure& data, INIStructure& original)
-		{
-			T_LineData output;
-			INIParser::T_ParseValues parseData;
-			std::string sectionCurrent;
-			bool parsingSection = false;
-			bool continueToNextSection = false;
-			bool discardNextEmpty = false;
-			bool writeNewKeys = false;
-			std::size_t lastKeyLine = 0;
-			for (auto line = lineData->begin(); line != lineData->end(); ++line)
-			{
-				if (!writeNewKeys)
-				{
-					auto parseResult = INIParser::parseLine(*line, parseData);
-					if (parseResult == INIParser::PDataType::PDATA_SECTION)
-					{
-						if (parsingSection)
-						{
-							writeNewKeys = true;
-							parsingSection = false;
-							--line;
-							continue;
-						}
-						sectionCurrent = parseData.first;
-						if (data.has(sectionCurrent))
-						{
-							parsingSection = true;
-							continueToNextSection = false;
-							discardNextEmpty = false;
-							output.emplace_back(*line);
-							lastKeyLine = output.size();
-						}
-						else
-						{
-							continueToNextSection = true;
-							discardNextEmpty = true;
-							continue;
-						}
-					}
-					else if (parseResult == INIParser::PDataType::PDATA_KEYVALUE)
-					{
-						if (continueToNextSection)
-						{
-							continue;
-						}
-						if (data.has(sectionCurrent))
-						{
-							auto& collection = data[sectionCurrent];
-							auto const& key = parseData.first;
-							auto const& value = parseData.second;
-							if (collection.has(key))
-							{
-								auto outputValue = collection[key];
-								if (value == outputValue)
-								{
-									output.emplace_back(*line);
-								}
-								else
-								{
-									INIStringUtil::trim(outputValue);
-									auto lineNorm = *line;
-									INIStringUtil::replace(lineNorm, "\\=", "  ");
-									auto equalsAt = lineNorm.find_first_of('=');
-									auto valueAt = lineNorm.find_first_not_of(
-										INIStringUtil::whitespaceDelimiters,
-										equalsAt + 1
-									);
-									std::string outputLine = line->substr(0, valueAt);
-									if (prettyPrint && equalsAt + 1 == valueAt)
-									{
-										outputLine += " ";
-									}
-									outputLine += outputValue;
-									output.emplace_back(outputLine);
-								}
-								lastKeyLine = output.size();
-							}
-						}
-					}
-					else
-					{
-						if (discardNextEmpty && line->empty())
-						{
-							discardNextEmpty = false;
-						}
-						else if (parseResult != INIParser::PDataType::PDATA_UNKNOWN)
-						{
-							output.emplace_back(*line);
-						}
-					}
-				}
-				if (writeNewKeys || std::next(line) == lineData->end())
-				{
-					T_LineData linesToAdd;
-					if (data.has(sectionCurrent) && original.has(sectionCurrent))
-					{
-						auto const& collection = data[sectionCurrent];
-						auto const& collectionOriginal = original[sectionCurrent];
-						for (auto const& it : collection)
-						{
-							auto key = it.first;
-							if (collectionOriginal.has(key))
-							{
-								continue;
-							}
-							auto value = it.second;
-							INIStringUtil::replace(key, "=", "\\=");
-							INIStringUtil::trim(value);
-							linesToAdd.emplace_back(
-								key + ((prettyPrint) ? " = " : "=") + value
-							);
-						}
-					}
-					if (!linesToAdd.empty())
-					{
-						output.insert(
-							output.begin() + lastKeyLine,
-							linesToAdd.begin(),
-							linesToAdd.end()
-						);
-					}
-					if (writeNewKeys)
-					{
-						writeNewKeys = false;
-						--line;
-					}
-				}
-			}
-			for (auto const& it : data)
-			{
-				auto const& section = it.first;
-				if (original.has(section))
-				{
-					continue;
-				}
-				if (prettyPrint && output.size() > 0 && !output.back().empty())
-				{
-					output.emplace_back();
-				}
-				output.emplace_back("[" + section + "]");
-				auto const& collection = it.second;
-				for (auto const& it2 : collection)
-				{
-					auto key = it2.first;
-					auto value = it2.second;
-					INIStringUtil::replace(key, "=", "\\=");
-					INIStringUtil::trim(value);
-					output.emplace_back(
-						key + ((prettyPrint) ? " = " : "=") + value
-					);
-				}
-			}
-			return output;
-		}
-
-	public:
-		bool prettyPrint = false;
-
-		INIWriter(std::string const& filename)
-		: filename(filename)
-		{
-		}
-		~INIWriter() { }
-
-		bool operator<<(INIStructure& data)
-		{
-			struct stat buf;
-			bool fileExists = (stat(filename.c_str(), &buf) == 0);
-			if (!fileExists)
-			{
-				INIGenerator generator(filename);
-				generator.prettyPrint = prettyPrint;
-				return generator << data;
-			}
-			INIStructure originalData;
-			T_LineDataPtr lineData;
-			bool readSuccess = false;
-			bool fileIsBOM = false;
-			{
-				INIReader reader(filename, true);
-				if ((readSuccess = reader >> originalData))
-				{
-					lineData = reader.getLines();
-					fileIsBOM = reader.isBOM;
-				}
-			}
-			if (!readSuccess)
-			{
-				return false;
-			}
-			T_LineData output = getLazyOutput(lineData, data, originalData);
-			std::ofstream fileWriteStream(filename, std::ios::out | std::ios::binary);
-			if (fileWriteStream.is_open())
-			{
-				if (fileIsBOM) {
-					const char utf8_BOM[3] = {
-						static_cast<char>(0xEF),
-						static_cast<char>(0xBB),
-						static_cast<char>(0xBF)
-					};
-					fileWriteStream.write(utf8_BOM, 3);
-				}
-				if (output.size())
-				{
-					auto line = output.begin();
-					for (;;)
-					{
-						fileWriteStream << *line;
-						if (++line == output.end())
-						{
-							break;
-						}
-						fileWriteStream << INIStringUtil::endl;
-					}
-				}
-				return true;
-			}
-			return false;
-		}
-	};
-
-	class INIFile
-	{
-	private:
-		std::string filename;
-
-	public:
-		INIFile(std::string const& filename)
-		: filename(filename)
-		{ }
-
-		~INIFile() { }
-
-		bool read(INIStructure& data) const
-		{
-			if (data.size())
-			{
-				data.clear();
-			}
-			if (filename.empty())
-			{
-				return false;
-			}
-			INIReader reader(filename);
-			return reader >> data;
-		}
-		bool generate(INIStructure const& data, bool pretty = false) const
-		{
-			if (filename.empty())
-			{
-				return false;
-			}
-			INIGenerator generator(filename);
-			generator.prettyPrint = pretty;
-			return generator << data;
-		}
-		bool write(INIStructure& data, bool pretty = false) const
-		{
-			if (filename.empty())
-			{
-				return false;
-			}
-			INIWriter writer(filename);
-			writer.prettyPrint = pretty;
-			return writer << data;
-		}
-	};
-}
-
-#endif // MINI_INI_H_
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/LICENSE	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,21 @@
+The MIT License (MIT)
+
+Copyright (c) 2017 Toru Niina
+
+Permission is hereby granted, free of charge, to any person obtaining a copy
+of this software and associated documentation files (the "Software"), to deal
+in the Software without restriction, including without limitation the rights
+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+copies of the Software, and to permit persons to whom the Software is
+furnished to do so, subject to the following conditions:
+
+The above copyright notice and this permission notice shall be included in
+all copies or substantial portions of the Software.
+
+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+THE SOFTWARE.
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,38 @@
+/*
+ * The MIT License (MIT)
+ *
+ * Copyright (c) 2017 Toru Niina
+ *
+ * Permission is hereby granted, free of charge, to any person obtaining a copy
+ * of this software and associated documentation files (the "Software"), to deal
+ * in the Software without restriction, including without limitation the rights
+ * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ * copies of the Software, and to permit persons to whom the Software is
+ * furnished to do so, subject to the following conditions:
+ *
+ * The above copyright notice and this permission notice shall be included in
+ * all copies or substantial portions of the Software.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ * THE SOFTWARE.
+ */
+
+#ifndef TOML_FOR_MODERN_CPP
+#define TOML_FOR_MODERN_CPP
+
+#define TOML11_VERSION_MAJOR 3
+#define TOML11_VERSION_MINOR 8
+#define TOML11_VERSION_PATCH 1
+
+#include "toml/parser.hpp"
+#include "toml/literal.hpp"
+#include "toml/serializer.hpp"
+#include "toml/get.hpp"
+#include "toml/macros.hpp"
+
+#endif// TOML_FOR_MODERN_CPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/color.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,109 @@
+#ifndef TOML11_COLOR_HPP
+#define TOML11_COLOR_HPP
+#include <cstdint>
+#include <ostream>
+
+#ifdef TOML11_COLORIZE_ERROR_MESSAGE
+#define TOML11_ERROR_MESSAGE_COLORIZED true
+#else
+#define TOML11_ERROR_MESSAGE_COLORIZED false
+#endif
+
+namespace toml
+{
+
+// put ANSI escape sequence to ostream
+namespace color_ansi
+{
+namespace detail
+{
+
+inline int colorize_index()
+{
+    static const int index = std::ios_base::xalloc();
+    return index;
+}
+
+// Control color mode globally
+class color_mode
+{
+  public:
+    inline void enable()
+    {
+        should_color_ = true;
+    }
+    inline void disable()
+    {
+        should_color_ = false;
+    }
+
+    inline bool should_color() const
+    {
+        return should_color_;
+    }
+
+    static color_mode& status()
+    {
+        static color_mode status_;
+        return status_;
+    }
+
+  private:
+    bool should_color_ = false;
+};
+
+} // detail
+
+inline std::ostream& colorize(std::ostream& os)
+{
+    // by default, it is zero.
+    os.iword(detail::colorize_index()) = 1;
+    return os;
+}
+inline std::ostream& nocolorize(std::ostream& os)
+{
+    os.iword(detail::colorize_index()) = 0;
+    return os;
+}
+inline std::ostream& reset  (std::ostream& os)
+{if(os.iword(detail::colorize_index()) == 1) {os << "\033[00m";} return os;}
+inline std::ostream& bold   (std::ostream& os)
+{if(os.iword(detail::colorize_index()) == 1) {os << "\033[01m";} return os;}
+inline std::ostream& grey   (std::ostream& os)
+{if(os.iword(detail::colorize_index()) == 1) {os << "\033[30m";} return os;}
+inline std::ostream& red    (std::ostream& os)
+{if(os.iword(detail::colorize_index()) == 1) {os << "\033[31m";} return os;}
+inline std::ostream& green  (std::ostream& os)
+{if(os.iword(detail::colorize_index()) == 1) {os << "\033[32m";} return os;}
+inline std::ostream& yellow (std::ostream& os)
+{if(os.iword(detail::colorize_index()) == 1) {os << "\033[33m";} return os;}
+inline std::ostream& blue   (std::ostream& os)
+{if(os.iword(detail::colorize_index()) == 1) {os << "\033[34m";} return os;}
+inline std::ostream& magenta(std::ostream& os)
+{if(os.iword(detail::colorize_index()) == 1) {os << "\033[35m";} return os;}
+inline std::ostream& cyan   (std::ostream& os)
+{if(os.iword(detail::colorize_index()) == 1) {os << "\033[36m";} return os;}
+inline std::ostream& white  (std::ostream& os)
+{if(os.iword(detail::colorize_index()) == 1) {os << "\033[37m";} return os;}
+
+inline void enable()
+{
+    return detail::color_mode::status().enable();
+}
+inline void disable()
+{
+    return detail::color_mode::status().disable();
+}
+
+inline bool should_color()
+{
+    return detail::color_mode::status().should_color();
+}
+
+} // color_ansi
+
+// ANSI escape sequence is the only and default colorization method currently
+namespace color = color_ansi;
+
+} // toml
+#endif// TOML11_COLOR_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/combinator.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,306 @@
+//     Copyright Toru Niina 2017.
+// Distributed under the MIT License.
+#ifndef TOML11_COMBINATOR_HPP
+#define TOML11_COMBINATOR_HPP
+#include <cassert>
+#include <cctype>
+#include <cstdio>
+
+#include <array>
+#include <iomanip>
+#include <iterator>
+#include <limits>
+#include <type_traits>
+
+#include "region.hpp"
+#include "result.hpp"
+#include "traits.hpp"
+#include "utility.hpp"
+
+// they scans characters and returns region if it matches to the condition.
+// when they fail, it does not change the location.
+// in lexer.hpp, these are used.
+
+namespace toml
+{
+namespace detail
+{
+
+// to output character as an error message.
+inline std::string show_char(const char c)
+{
+    // It suppresses an error that occurs only in Debug mode of MSVC++ on Windows.
+    // I'm not completely sure but they check the value of char to be in the
+    // range [0, 256) and some of the COMPLETELY VALID utf-8 character sometimes
+    // has negative value (if char has sign). So here it re-interprets c as
+    // unsigned char through pointer. In general, converting pointer to a
+    // pointer that has different type cause UB, but `(signed|unsigned)?char`
+    // are one of the exceptions. Converting pointer only to char and std::byte
+    // (c++17) are valid.
+    if(std::isgraph(*reinterpret_cast<unsigned char const*>(std::addressof(c))))
+    {
+        return std::string(1, c);
+    }
+    else
+    {
+        std::array<char, 5> buf;
+        buf.fill('\0');
+        const auto r = std::snprintf(
+                buf.data(), buf.size(), "0x%02x", static_cast<int>(c) & 0xFF);
+        (void) r; // Unused variable warning
+        assert(r == static_cast<int>(buf.size()) - 1);
+        return std::string(buf.data());
+    }
+}
+
+template<char C>
+struct character
+{
+    static constexpr char target = C;
+
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        if(loc.iter() == loc.end()) {return none();}
+        const auto first = loc.iter();
+
+        const char c = *(loc.iter());
+        if(c != target)
+        {
+            return none();
+        }
+        loc.advance(); // update location
+
+        return ok(region(loc, first, loc.iter()));
+    }
+};
+template<char C>
+constexpr char character<C>::target;
+
+// closed interval [Low, Up]. both Low and Up are included.
+template<char Low, char Up>
+struct in_range
+{
+    // assuming ascii part of UTF-8...
+    static_assert(Low <= Up, "lower bound should be less than upper bound.");
+
+    static constexpr char upper = Up;
+    static constexpr char lower = Low;
+
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        if(loc.iter() == loc.end()) {return none();}
+        const auto first = loc.iter();
+
+        const char c = *(loc.iter());
+        if(c < lower || upper < c)
+        {
+            return none();
+        }
+
+        loc.advance();
+        return ok(region(loc, first, loc.iter()));
+    }
+};
+template<char L, char U> constexpr char in_range<L, U>::upper;
+template<char L, char U> constexpr char in_range<L, U>::lower;
+
+// keep iterator if `Combinator` matches. otherwise, increment `iter` by 1 char.
+// for detecting invalid characters, like control sequences in toml string.
+template<typename Combinator>
+struct exclude
+{
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        if(loc.iter() == loc.end()) {return none();}
+        auto first = loc.iter();
+
+        auto rslt = Combinator::invoke(loc);
+        if(rslt.is_ok())
+        {
+            loc.reset(first);
+            return none();
+        }
+        loc.reset(std::next(first)); // XXX maybe loc.advance() is okay but...
+        return ok(region(loc, first, loc.iter()));
+    }
+};
+
+// increment `iter`, if matches. otherwise, just return empty string.
+template<typename Combinator>
+struct maybe
+{
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        const auto rslt = Combinator::invoke(loc);
+        if(rslt.is_ok())
+        {
+            return rslt;
+        }
+        return ok(region(loc));
+    }
+};
+
+template<typename ... Ts>
+struct sequence;
+
+template<typename Head, typename ... Tail>
+struct sequence<Head, Tail...>
+{
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        const auto first = loc.iter();
+        auto rslt = Head::invoke(loc);
+        if(rslt.is_err())
+        {
+            loc.reset(first);
+            return none();
+        }
+        return sequence<Tail...>::invoke(loc, std::move(rslt.unwrap()), first);
+    }
+
+    // called from the above function only, recursively.
+    template<typename Iterator>
+    static result<region, none_t>
+    invoke(location& loc, region reg, Iterator first)
+    {
+        const auto rslt = Head::invoke(loc);
+        if(rslt.is_err())
+        {
+            loc.reset(first);
+            return none();
+        }
+        reg += rslt.unwrap(); // concat regions
+        return sequence<Tail...>::invoke(loc, std::move(reg), first);
+    }
+};
+
+template<typename Head>
+struct sequence<Head>
+{
+    // would be called from sequence<T ...>::invoke only.
+    template<typename Iterator>
+    static result<region, none_t>
+    invoke(location& loc, region reg, Iterator first)
+    {
+        const auto rslt = Head::invoke(loc);
+        if(rslt.is_err())
+        {
+            loc.reset(first);
+            return none();
+        }
+        reg += rslt.unwrap(); // concat regions
+        return ok(reg);
+    }
+};
+
+template<typename ... Ts>
+struct either;
+
+template<typename Head, typename ... Tail>
+struct either<Head, Tail...>
+{
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        const auto rslt = Head::invoke(loc);
+        if(rslt.is_ok()) {return rslt;}
+        return either<Tail...>::invoke(loc);
+    }
+};
+template<typename Head>
+struct either<Head>
+{
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        return Head::invoke(loc);
+    }
+};
+
+template<typename T, typename N>
+struct repeat;
+
+template<std::size_t N> struct exactly{};
+template<std::size_t N> struct at_least{};
+struct unlimited{};
+
+template<typename T, std::size_t N>
+struct repeat<T, exactly<N>>
+{
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        region retval(loc);
+        const auto first = loc.iter();
+        for(std::size_t i=0; i<N; ++i)
+        {
+            auto rslt = T::invoke(loc);
+            if(rslt.is_err())
+            {
+                loc.reset(first);
+                return none();
+            }
+            retval += rslt.unwrap();
+        }
+        return ok(std::move(retval));
+    }
+};
+
+template<typename T, std::size_t N>
+struct repeat<T, at_least<N>>
+{
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        region retval(loc);
+
+        const auto first = loc.iter();
+        for(std::size_t i=0; i<N; ++i)
+        {
+            auto rslt = T::invoke(loc);
+            if(rslt.is_err())
+            {
+                loc.reset(first);
+                return none();
+            }
+            retval += rslt.unwrap();
+        }
+        while(true)
+        {
+            auto rslt = T::invoke(loc);
+            if(rslt.is_err())
+            {
+                return ok(std::move(retval));
+            }
+            retval += rslt.unwrap();
+        }
+    }
+};
+
+template<typename T>
+struct repeat<T, unlimited>
+{
+    static result<region, none_t>
+    invoke(location& loc)
+    {
+        region retval(loc);
+        while(true)
+        {
+            auto rslt = T::invoke(loc);
+            if(rslt.is_err())
+            {
+                return ok(std::move(retval));
+            }
+            retval += rslt.unwrap();
+        }
+    }
+};
+
+} // detail
+} // toml
+#endif// TOML11_COMBINATOR_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/comments.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,484 @@
+//     Copyright Toru Niina 2019.
+// Distributed under the MIT License.
+#ifndef TOML11_COMMENTS_HPP
+#define TOML11_COMMENTS_HPP
+#include <initializer_list>
+#include <iterator>
+#include <stdexcept>
+#include <string>
+#include <type_traits>
+#include <utility>
+#include <vector>
+
+#ifdef TOML11_PRESERVE_COMMENTS_BY_DEFAULT
+#  define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::preserve_comments
+#else
+#  define TOML11_DEFAULT_COMMENT_STRATEGY ::toml::discard_comments
+#endif
+
+// This file provides mainly two classes, `preserve_comments` and `discard_comments`.
+// Those two are a container that have the same interface as `std::vector<std::string>`
+// but bahaves in the opposite way. `preserve_comments` is just the same as
+// `std::vector<std::string>` and each `std::string` corresponds to a comment line.
+// Conversely, `discard_comments` discards all the strings and ignores everything
+// assigned in it. `discard_comments` is always empty and you will encounter an
+// error whenever you access to the element.
+namespace toml
+{
+struct discard_comments; // forward decl
+
+// use it in the following way
+//
+// const toml::basic_value<toml::preserve_comments> data =
+//     toml::parse<toml::preserve_comments>("example.toml");
+//
+// the interface is almost the same as std::vector<std::string>.
+struct preserve_comments
+{
+    // `container_type` is not provided in discard_comments.
+    // do not use this inner-type in a generic code.
+    using container_type         = std::vector<std::string>;
+
+    using size_type              = container_type::size_type;
+    using difference_type        = container_type::difference_type;
+    using value_type             = container_type::value_type;
+    using reference              = container_type::reference;
+    using const_reference        = container_type::const_reference;
+    using pointer                = container_type::pointer;
+    using const_pointer          = container_type::const_pointer;
+    using iterator               = container_type::iterator;
+    using const_iterator         = container_type::const_iterator;
+    using reverse_iterator       = container_type::reverse_iterator;
+    using const_reverse_iterator = container_type::const_reverse_iterator;
+
+    preserve_comments()  = default;
+    ~preserve_comments() = default;
+    preserve_comments(preserve_comments const&) = default;
+    preserve_comments(preserve_comments &&)     = default;
+    preserve_comments& operator=(preserve_comments const&) = default;
+    preserve_comments& operator=(preserve_comments &&)     = default;
+
+    explicit preserve_comments(const std::vector<std::string>& c): comments(c){}
+    explicit preserve_comments(std::vector<std::string>&& c)
+        : comments(std::move(c))
+    {}
+    preserve_comments& operator=(const std::vector<std::string>& c)
+    {
+        comments = c;
+        return *this;
+    }
+    preserve_comments& operator=(std::vector<std::string>&& c)
+    {
+        comments = std::move(c);
+        return *this;
+    }
+
+    explicit preserve_comments(const discard_comments&) {}
+
+    explicit preserve_comments(size_type n): comments(n) {}
+    preserve_comments(size_type n, const std::string& x): comments(n, x) {}
+    preserve_comments(std::initializer_list<std::string> x): comments(x) {}
+    template<typename InputIterator>
+    preserve_comments(InputIterator first, InputIterator last)
+        : comments(first, last)
+    {}
+
+    template<typename InputIterator>
+    void assign(InputIterator first, InputIterator last) {comments.assign(first, last);}
+    void assign(std::initializer_list<std::string> ini)  {comments.assign(ini);}
+    void assign(size_type n, const std::string& val)     {comments.assign(n, val);}
+
+    // Related to the issue #97.
+    //
+    // It is known that `std::vector::insert` and `std::vector::erase` in
+    // the standard library implementation included in GCC 4.8.5 takes
+    // `std::vector::iterator` instead of `std::vector::const_iterator`.
+    // Because of the const-correctness, we cannot convert a `const_iterator` to
+    // an `iterator`. It causes compilation error in GCC 4.8.5.
+#if defined(__GNUC__) && defined(__GNUC_MINOR__) && defined(__GNUC_PATCHLEVEL__) && !defined(__clang__)
+#  if (__GNUC__ * 10000 + __GNUC_MINOR__ * 100 + __GNUC_PATCHLEVEL__) <= 40805
+#    define TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION
+#  endif
+#endif
+
+#ifdef TOML11_WORKAROUND_GCC_4_8_X_STANDARD_LIBRARY_IMPLEMENTATION
+    iterator insert(iterator p, const std::string& x)
+    {
+        return comments.insert(p, x);
+    }
+    iterator insert(iterator p, std::string&&      x)
+    {
+        return comments.insert(p, std::move(x));
+    }
+    void insert(iterator p, size_type n, const std::string& x)
+    {
+        return comments.insert(p, n, x);
+    }
+    template<typename InputIterator>
+    void insert(iterator p, InputIterator first, InputIterator last)
+    {
+        return comments.insert(p, first, last);
+    }
+    void insert(iterator p, std::initializer_list<std::string> ini)
+    {
+        return comments.insert(p, ini);
+    }
+
+    template<typename ... Ts>
+    iterator emplace(iterator p, Ts&& ... args)
+    {
+        return comments.emplace(p, std::forward<Ts>(args)...);
+    }
+
+    iterator erase(iterator pos) {return comments.erase(pos);}
+    iterator erase(iterator first, iterator last)
+    {
+        return comments.erase(first, last);
+    }
+#else
+    iterator insert(const_iterator p, const std::string& x)
+    {
+        return comments.insert(p, x);
+    }
+    iterator insert(const_iterator p, std::string&&      x)
+    {
+        return comments.insert(p, std::move(x));
+    }
+    iterator insert(const_iterator p, size_type n, const std::string& x)
+    {
+        return comments.insert(p, n, x);
+    }
+    template<typename InputIterator>
+    iterator insert(const_iterator p, InputIterator first, InputIterator last)
+    {
+        return comments.insert(p, first, last);
+    }
+    iterator insert(const_iterator p, std::initializer_list<std::string> ini)
+    {
+        return comments.insert(p, ini);
+    }
+
+    template<typename ... Ts>
+    iterator emplace(const_iterator p, Ts&& ... args)
+    {
+        return comments.emplace(p, std::forward<Ts>(args)...);
+    }
+
+    iterator erase(const_iterator pos) {return comments.erase(pos);}
+    iterator erase(const_iterator first, const_iterator last)
+    {
+        return comments.erase(first, last);
+    }
+#endif
+
+    void swap(preserve_comments& other) {comments.swap(other.comments);}
+
+    void push_back(const std::string& v) {comments.push_back(v);}
+    void push_back(std::string&&      v) {comments.push_back(std::move(v));}
+    void pop_back()                      {comments.pop_back();}
+
+    template<typename ... Ts>
+    void emplace_back(Ts&& ... args) {comments.emplace_back(std::forward<Ts>(args)...);}
+
+    void clear() {comments.clear();}
+
+    size_type size()     const noexcept {return comments.size();}
+    size_type max_size() const noexcept {return comments.max_size();}
+    size_type capacity() const noexcept {return comments.capacity();}
+    bool      empty()    const noexcept {return comments.empty();}
+
+    void reserve(size_type n)                      {comments.reserve(n);}
+    void resize(size_type n)                       {comments.resize(n);}
+    void resize(size_type n, const std::string& c) {comments.resize(n, c);}
+    void shrink_to_fit()                           {comments.shrink_to_fit();}
+
+    reference       operator[](const size_type n)       noexcept {return comments[n];}
+    const_reference operator[](const size_type n) const noexcept {return comments[n];}
+    reference       at(const size_type n)       {return comments.at(n);}
+    const_reference at(const size_type n) const {return comments.at(n);}
+    reference       front()       noexcept {return comments.front();}
+    const_reference front() const noexcept {return comments.front();}
+    reference       back()        noexcept {return comments.back();}
+    const_reference back()  const noexcept {return comments.back();}
+
+    pointer         data()        noexcept {return comments.data();}
+    const_pointer   data()  const noexcept {return comments.data();}
+
+    iterator       begin()        noexcept {return comments.begin();}
+    iterator       end()          noexcept {return comments.end();}
+    const_iterator begin()  const noexcept {return comments.begin();}
+    const_iterator end()    const noexcept {return comments.end();}
+    const_iterator cbegin() const noexcept {return comments.cbegin();}
+    const_iterator cend()   const noexcept {return comments.cend();}
+
+    reverse_iterator       rbegin()        noexcept {return comments.rbegin();}
+    reverse_iterator       rend()          noexcept {return comments.rend();}
+    const_reverse_iterator rbegin()  const noexcept {return comments.rbegin();}
+    const_reverse_iterator rend()    const noexcept {return comments.rend();}
+    const_reverse_iterator crbegin() const noexcept {return comments.crbegin();}
+    const_reverse_iterator crend()   const noexcept {return comments.crend();}
+
+    friend bool operator==(const preserve_comments&, const preserve_comments&);
+    friend bool operator!=(const preserve_comments&, const preserve_comments&);
+    friend bool operator< (const preserve_comments&, const preserve_comments&);
+    friend bool operator<=(const preserve_comments&, const preserve_comments&);
+    friend bool operator> (const preserve_comments&, const preserve_comments&);
+    friend bool operator>=(const preserve_comments&, const preserve_comments&);
+
+    friend void swap(preserve_comments&, std::vector<std::string>&);
+    friend void swap(std::vector<std::string>&, preserve_comments&);
+
+  private:
+
+    container_type comments;
+};
+
+inline bool operator==(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments == rhs.comments;}
+inline bool operator!=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments != rhs.comments;}
+inline bool operator< (const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments <  rhs.comments;}
+inline bool operator<=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments <= rhs.comments;}
+inline bool operator> (const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments >  rhs.comments;}
+inline bool operator>=(const preserve_comments& lhs, const preserve_comments& rhs) {return lhs.comments >= rhs.comments;}
+
+inline void swap(preserve_comments& lhs, preserve_comments& rhs)
+{
+    lhs.swap(rhs);
+    return;
+}
+inline void swap(preserve_comments& lhs, std::vector<std::string>& rhs)
+{
+    lhs.comments.swap(rhs);
+    return;
+}
+inline void swap(std::vector<std::string>& lhs, preserve_comments& rhs)
+{
+    lhs.swap(rhs.comments);
+    return;
+}
+
+template<typename charT, typename traits>
+std::basic_ostream<charT, traits>&
+operator<<(std::basic_ostream<charT, traits>& os, const preserve_comments& com)
+{
+    for(const auto& c : com)
+    {
+        os << '#' << c << '\n';
+    }
+    return os;
+}
+
+namespace detail
+{
+
+// To provide the same interface with `preserve_comments`, `discard_comments`
+// should have an iterator. But it does not contain anything, so we need to
+// add an iterator that points nothing.
+//
+// It always points null, so DO NOT unwrap this iterator. It always crashes
+// your program.
+template<typename T, bool is_const>
+struct empty_iterator
+{
+    using value_type        = T;
+    using reference_type    = typename std::conditional<is_const, T const&, T&>::type;
+    using pointer_type      = typename std::conditional<is_const, T const*, T*>::type;
+    using difference_type   = std::ptrdiff_t;
+    using iterator_category = std::random_access_iterator_tag;
+
+    empty_iterator()  = default;
+    ~empty_iterator() = default;
+    empty_iterator(empty_iterator const&) = default;
+    empty_iterator(empty_iterator &&)     = default;
+    empty_iterator& operator=(empty_iterator const&) = default;
+    empty_iterator& operator=(empty_iterator &&)     = default;
+
+    // DO NOT call these operators.
+    reference_type operator*()  const noexcept {std::terminate();}
+    pointer_type   operator->() const noexcept {return nullptr;}
+    reference_type operator[](difference_type) const noexcept {return this->operator*();}
+
+    // These operators do nothing.
+    empty_iterator& operator++()    noexcept {return *this;}
+    empty_iterator  operator++(int) noexcept {return *this;}
+    empty_iterator& operator--()    noexcept {return *this;}
+    empty_iterator  operator--(int) noexcept {return *this;}
+
+    empty_iterator& operator+=(difference_type) noexcept {return *this;}
+    empty_iterator& operator-=(difference_type) noexcept {return *this;}
+
+    empty_iterator  operator+(difference_type) const noexcept {return *this;}
+    empty_iterator  operator-(difference_type) const noexcept {return *this;}
+};
+
+template<typename T, bool C>
+bool operator==(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return true;}
+template<typename T, bool C>
+bool operator!=(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return false;}
+template<typename T, bool C>
+bool operator< (const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return false;}
+template<typename T, bool C>
+bool operator<=(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return true;}
+template<typename T, bool C>
+bool operator> (const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return false;}
+template<typename T, bool C>
+bool operator>=(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return true;}
+
+template<typename T, bool C>
+typename empty_iterator<T, C>::difference_type
+operator-(const empty_iterator<T, C>&, const empty_iterator<T, C>&) noexcept {return 0;}
+
+template<typename T, bool C>
+empty_iterator<T, C>
+operator+(typename empty_iterator<T, C>::difference_type, const empty_iterator<T, C>& rhs) noexcept {return rhs;}
+template<typename T, bool C>
+empty_iterator<T, C>
+operator+(const empty_iterator<T, C>& lhs, typename empty_iterator<T, C>::difference_type) noexcept {return lhs;}
+
+} // detail
+
+// The default comment type. It discards all the comments. It requires only one
+// byte to contain, so the memory footprint is smaller than preserve_comments.
+//
+// It just ignores `push_back`, `insert`, `erase`, and any other modifications.
+// IT always returns size() == 0, the iterator taken by `begin()` is always the
+// same as that of `end()`, and accessing through `operator[]` or iterators
+// always causes a segmentation fault. DO NOT access to the element of this.
+//
+// Why this is chose as the default type is because the last version (2.x.y)
+// does not contain any comments in a value. To minimize the impact on the
+// efficiency, this is chosen as a default.
+//
+// To reduce the memory footprint, later we can try empty base optimization (EBO).
+struct discard_comments
+{
+    using size_type              = std::size_t;
+    using difference_type        = std::ptrdiff_t;
+    using value_type             = std::string;
+    using reference              = std::string&;
+    using const_reference        = std::string const&;
+    using pointer                = std::string*;
+    using const_pointer          = std::string const*;
+    using iterator               = detail::empty_iterator<std::string, false>;
+    using const_iterator         = detail::empty_iterator<std::string, true>;
+    using reverse_iterator       = detail::empty_iterator<std::string, false>;
+    using const_reverse_iterator = detail::empty_iterator<std::string, true>;
+
+    discard_comments() = default;
+    ~discard_comments() = default;
+    discard_comments(discard_comments const&) = default;
+    discard_comments(discard_comments &&)     = default;
+    discard_comments& operator=(discard_comments const&) = default;
+    discard_comments& operator=(discard_comments &&)     = default;
+
+    explicit discard_comments(const std::vector<std::string>&) noexcept {}
+    explicit discard_comments(std::vector<std::string>&&)      noexcept {}
+    discard_comments& operator=(const std::vector<std::string>&) noexcept {return *this;}
+    discard_comments& operator=(std::vector<std::string>&&)      noexcept {return *this;}
+
+    explicit discard_comments(const preserve_comments&)        noexcept {}
+
+    explicit discard_comments(size_type) noexcept {}
+    discard_comments(size_type, const std::string&) noexcept {}
+    discard_comments(std::initializer_list<std::string>) noexcept {}
+    template<typename InputIterator>
+    discard_comments(InputIterator, InputIterator) noexcept {}
+
+    template<typename InputIterator>
+    void assign(InputIterator, InputIterator)       noexcept {}
+    void assign(std::initializer_list<std::string>) noexcept {}
+    void assign(size_type, const std::string&)      noexcept {}
+
+    iterator insert(const_iterator, const std::string&)                 {return iterator{};}
+    iterator insert(const_iterator, std::string&&)                      {return iterator{};}
+    iterator insert(const_iterator, size_type, const std::string&)      {return iterator{};}
+    template<typename InputIterator>
+    iterator insert(const_iterator, InputIterator, InputIterator)       {return iterator{};}
+    iterator insert(const_iterator, std::initializer_list<std::string>) {return iterator{};}
+
+    template<typename ... Ts>
+    iterator emplace(const_iterator, Ts&& ...)     {return iterator{};}
+    iterator erase(const_iterator)                 {return iterator{};}
+    iterator erase(const_iterator, const_iterator) {return iterator{};}
+
+    void swap(discard_comments&) {return;}
+
+    void push_back(const std::string&) {return;}
+    void push_back(std::string&&     ) {return;}
+    void pop_back()                    {return;}
+
+    template<typename ... Ts>
+    void emplace_back(Ts&& ...) {return;}
+
+    void clear() {return;}
+
+    size_type size()     const noexcept {return 0;}
+    size_type max_size() const noexcept {return 0;}
+    size_type capacity() const noexcept {return 0;}
+    bool      empty()    const noexcept {return true;}
+
+    void reserve(size_type)                    {return;}
+    void resize(size_type)                     {return;}
+    void resize(size_type, const std::string&) {return;}
+    void shrink_to_fit()                       {return;}
+
+    // DO NOT access to the element of this container. This container is always
+    // empty, so accessing through operator[], front/back, data causes address
+    // error.
+
+    reference       operator[](const size_type)       noexcept {never_call("toml::discard_comment::operator[]");}
+    const_reference operator[](const size_type) const noexcept {never_call("toml::discard_comment::operator[]");}
+    reference       at(const size_type)       {throw std::out_of_range("toml::discard_comment is always empty.");}
+    const_reference at(const size_type) const {throw std::out_of_range("toml::discard_comment is always empty.");}
+    reference       front()       noexcept {never_call("toml::discard_comment::front");}
+    const_reference front() const noexcept {never_call("toml::discard_comment::front");}
+    reference       back()        noexcept {never_call("toml::discard_comment::back");}
+    const_reference back()  const noexcept {never_call("toml::discard_comment::back");}
+
+    pointer         data()        noexcept {return nullptr;}
+    const_pointer   data()  const noexcept {return nullptr;}
+
+    iterator       begin()        noexcept {return iterator{};}
+    iterator       end()          noexcept {return iterator{};}
+    const_iterator begin()  const noexcept {return const_iterator{};}
+    const_iterator end()    const noexcept {return const_iterator{};}
+    const_iterator cbegin() const noexcept {return const_iterator{};}
+    const_iterator cend()   const noexcept {return const_iterator{};}
+
+    reverse_iterator       rbegin()        noexcept {return iterator{};}
+    reverse_iterator       rend()          noexcept {return iterator{};}
+    const_reverse_iterator rbegin()  const noexcept {return const_iterator{};}
+    const_reverse_iterator rend()    const noexcept {return const_iterator{};}
+    const_reverse_iterator crbegin() const noexcept {return const_iterator{};}
+    const_reverse_iterator crend()   const noexcept {return const_iterator{};}
+
+  private:
+
+    [[noreturn]] static void never_call(const char *const this_function)
+    {
+#ifdef __has_builtin
+#  if __has_builtin(__builtin_unreachable)
+        __builtin_unreachable();
+#  endif
+#endif
+        throw std::logic_error{this_function};
+    }
+};
+
+inline bool operator==(const discard_comments&, const discard_comments&) noexcept {return true;}
+inline bool operator!=(const discard_comments&, const discard_comments&) noexcept {return false;}
+inline bool operator< (const discard_comments&, const discard_comments&) noexcept {return false;}
+inline bool operator<=(const discard_comments&, const discard_comments&) noexcept {return true;}
+inline bool operator> (const discard_comments&, const discard_comments&) noexcept {return false;}
+inline bool operator>=(const discard_comments&, const discard_comments&) noexcept {return true;}
+
+inline void swap(const discard_comments&, const discard_comments&) noexcept {return;}
+
+template<typename charT, typename traits>
+std::basic_ostream<charT, traits>&
+operator<<(std::basic_ostream<charT, traits>& os, const discard_comments&)
+{
+    return os;
+}
+
+} // toml11
+#endif// TOML11_COMMENTS_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/datetime.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,631 @@
+//     Copyright Toru Niina 2017.
+// Distributed under the MIT License.
+#ifndef TOML11_DATETIME_HPP
+#define TOML11_DATETIME_HPP
+#include <cstdint>
+#include <cstdlib>
+#include <ctime>
+
+#include <array>
+#include <chrono>
+#include <iomanip>
+#include <ostream>
+#include <tuple>
+
+namespace toml
+{
+
+// To avoid non-threadsafe std::localtime. In C11 (not C++11!), localtime_s is
+// provided in the absolutely same purpose, but C++11 is actually not compatible
+// with C11. We need to dispatch the function depending on the OS.
+namespace detail
+{
+// TODO: find more sophisticated way to handle this
+#if defined(_MSC_VER)
+inline std::tm localtime_s(const std::time_t* src)
+{
+    std::tm dst;
+    const auto result = ::localtime_s(&dst, src);
+    if (result) { throw std::runtime_error("localtime_s failed."); }
+    return dst;
+}
+inline std::tm gmtime_s(const std::time_t* src)
+{
+    std::tm dst;
+    const auto result = ::gmtime_s(&dst, src);
+    if (result) { throw std::runtime_error("gmtime_s failed."); }
+    return dst;
+}
+#elif (defined(_POSIX_C_SOURCE) && _POSIX_C_SOURCE >= 1) || defined(_XOPEN_SOURCE) || defined(_BSD_SOURCE) || defined(_SVID_SOURCE) || defined(_POSIX_SOURCE)
+inline std::tm localtime_s(const std::time_t* src)
+{
+    std::tm dst;
+    const auto result = ::localtime_r(src, &dst);
+    if (!result) { throw std::runtime_error("localtime_r failed."); }
+    return dst;
+}
+inline std::tm gmtime_s(const std::time_t* src)
+{
+    std::tm dst;
+    const auto result = ::gmtime_r(src, &dst);
+    if (!result) { throw std::runtime_error("gmtime_r failed."); }
+    return dst;
+}
+#else // fallback. not threadsafe
+inline std::tm localtime_s(const std::time_t* src)
+{
+    const auto result = std::localtime(src);
+    if (!result) { throw std::runtime_error("localtime failed."); }
+    return *result;
+}
+inline std::tm gmtime_s(const std::time_t* src)
+{
+    const auto result = std::gmtime(src);
+    if (!result) { throw std::runtime_error("gmtime failed."); }
+    return *result;
+}
+#endif
+} // detail
+
+enum class month_t : std::uint8_t
+{
+    Jan =  0,
+    Feb =  1,
+    Mar =  2,
+    Apr =  3,
+    May =  4,
+    Jun =  5,
+    Jul =  6,
+    Aug =  7,
+    Sep =  8,
+    Oct =  9,
+    Nov = 10,
+    Dec = 11
+};
+
+struct local_date
+{
+    std::int16_t year{};   // A.D. (like, 2018)
+    std::uint8_t month{};  // [0, 11]
+    std::uint8_t day{};    // [1, 31]
+
+    local_date(int y, month_t m, int d)
+        : year (static_cast<std::int16_t>(y)),
+          month(static_cast<std::uint8_t>(m)),
+          day  (static_cast<std::uint8_t>(d))
+    {}
+
+    explicit local_date(const std::tm& t)
+        : year (static_cast<std::int16_t>(t.tm_year + 1900)),
+          month(static_cast<std::uint8_t>(t.tm_mon)),
+          day  (static_cast<std::uint8_t>(t.tm_mday))
+    {}
+
+    explicit local_date(const std::chrono::system_clock::time_point& tp)
+    {
+        const auto t    = std::chrono::system_clock::to_time_t(tp);
+        const auto time = detail::localtime_s(&t);
+        *this = local_date(time);
+    }
+
+    explicit local_date(const std::time_t t)
+        : local_date(std::chrono::system_clock::from_time_t(t))
+    {}
+
+    operator std::chrono::system_clock::time_point() const
+    {
+        // std::mktime returns date as local time zone. no conversion needed
+        std::tm t;
+        t.tm_sec   = 0;
+        t.tm_min   = 0;
+        t.tm_hour  = 0;
+        t.tm_mday  = static_cast<int>(this->day);
+        t.tm_mon   = static_cast<int>(this->month);
+        t.tm_year  = static_cast<int>(this->year) - 1900;
+        t.tm_wday  = 0; // the value will be ignored
+        t.tm_yday  = 0; // the value will be ignored
+        t.tm_isdst = -1;
+        return std::chrono::system_clock::from_time_t(std::mktime(&t));
+    }
+
+    operator std::time_t() const
+    {
+        return std::chrono::system_clock::to_time_t(
+                std::chrono::system_clock::time_point(*this));
+    }
+
+    local_date() = default;
+    ~local_date() = default;
+    local_date(local_date const&) = default;
+    local_date(local_date&&)      = default;
+    local_date& operator=(local_date const&) = default;
+    local_date& operator=(local_date&&)      = default;
+};
+
+inline bool operator==(const local_date& lhs, const local_date& rhs)
+{
+    return std::make_tuple(lhs.year, lhs.month, lhs.day) ==
+           std::make_tuple(rhs.year, rhs.month, rhs.day);
+}
+inline bool operator!=(const local_date& lhs, const local_date& rhs)
+{
+    return !(lhs == rhs);
+}
+inline bool operator< (const local_date& lhs, const local_date& rhs)
+{
+    return std::make_tuple(lhs.year, lhs.month, lhs.day) <
+           std::make_tuple(rhs.year, rhs.month, rhs.day);
+}
+inline bool operator<=(const local_date& lhs, const local_date& rhs)
+{
+    return (lhs < rhs) || (lhs == rhs);
+}
+inline bool operator> (const local_date& lhs, const local_date& rhs)
+{
+    return !(lhs <= rhs);
+}
+inline bool operator>=(const local_date& lhs, const local_date& rhs)
+{
+    return !(lhs < rhs);
+}
+
+template<typename charT, typename traits>
+std::basic_ostream<charT, traits>&
+operator<<(std::basic_ostream<charT, traits>& os, const local_date& date)
+{
+    os << std::setfill('0') << std::setw(4) << static_cast<int>(date.year )     << '-';
+    os << std::setfill('0') << std::setw(2) << static_cast<int>(date.month) + 1 << '-';
+    os << std::setfill('0') << std::setw(2) << static_cast<int>(date.day  )    ;
+    return os;
+}
+
+struct local_time
+{
+    std::uint8_t  hour{};        // [0, 23]
+    std::uint8_t  minute{};      // [0, 59]
+    std::uint8_t  second{};      // [0, 60]
+    std::uint16_t millisecond{}; // [0, 999]
+    std::uint16_t microsecond{}; // [0, 999]
+    std::uint16_t nanosecond{};  // [0, 999]
+
+    local_time(int h, int m, int s,
+               int ms = 0, int us = 0, int ns = 0)
+        : hour  (static_cast<std::uint8_t>(h)),
+          minute(static_cast<std::uint8_t>(m)),
+          second(static_cast<std::uint8_t>(s)),
+          millisecond(static_cast<std::uint16_t>(ms)),
+          microsecond(static_cast<std::uint16_t>(us)),
+          nanosecond (static_cast<std::uint16_t>(ns))
+    {}
+
+    explicit local_time(const std::tm& t)
+        : hour  (static_cast<std::uint8_t>(t.tm_hour)),
+          minute(static_cast<std::uint8_t>(t.tm_min)),
+          second(static_cast<std::uint8_t>(t.tm_sec)),
+          millisecond(0), microsecond(0), nanosecond(0)
+    {}
+
+    template<typename Rep, typename Period>
+    explicit local_time(const std::chrono::duration<Rep, Period>& t)
+    {
+        const auto h = std::chrono::duration_cast<std::chrono::hours>(t);
+        this->hour = static_cast<std::uint8_t>(h.count());
+        const auto t2 = t - h;
+        const auto m = std::chrono::duration_cast<std::chrono::minutes>(t2);
+        this->minute = static_cast<std::uint8_t>(m.count());
+        const auto t3 = t2 - m;
+        const auto s = std::chrono::duration_cast<std::chrono::seconds>(t3);
+        this->second = static_cast<std::uint8_t>(s.count());
+        const auto t4 = t3 - s;
+        const auto ms = std::chrono::duration_cast<std::chrono::milliseconds>(t4);
+        this->millisecond = static_cast<std::uint16_t>(ms.count());
+        const auto t5 = t4 - ms;
+        const auto us = std::chrono::duration_cast<std::chrono::microseconds>(t5);
+        this->microsecond = static_cast<std::uint16_t>(us.count());
+        const auto t6 = t5 - us;
+        const auto ns = std::chrono::duration_cast<std::chrono::nanoseconds>(t6);
+        this->nanosecond = static_cast<std::uint16_t>(ns.count());
+    }
+
+    operator std::chrono::nanoseconds() const
+    {
+        return std::chrono::nanoseconds (this->nanosecond)  +
+               std::chrono::microseconds(this->microsecond) +
+               std::chrono::milliseconds(this->millisecond) +
+               std::chrono::seconds(this->second) +
+               std::chrono::minutes(this->minute) +
+               std::chrono::hours(this->hour);
+    }
+
+    local_time() = default;
+    ~local_time() = default;
+    local_time(local_time const&) = default;
+    local_time(local_time&&)      = default;
+    local_time& operator=(local_time const&) = default;
+    local_time& operator=(local_time&&)      = default;
+};
+
+inline bool operator==(const local_time& lhs, const local_time& rhs)
+{
+    return std::make_tuple(lhs.hour, lhs.minute, lhs.second, lhs.millisecond, lhs.microsecond, lhs.nanosecond) ==
+           std::make_tuple(rhs.hour, rhs.minute, rhs.second, rhs.millisecond, rhs.microsecond, rhs.nanosecond);
+}
+inline bool operator!=(const local_time& lhs, const local_time& rhs)
+{
+    return !(lhs == rhs);
+}
+inline bool operator< (const local_time& lhs, const local_time& rhs)
+{
+    return std::make_tuple(lhs.hour, lhs.minute, lhs.second, lhs.millisecond, lhs.microsecond, lhs.nanosecond) <
+           std::make_tuple(rhs.hour, rhs.minute, rhs.second, rhs.millisecond, rhs.microsecond, rhs.nanosecond);
+}
+inline bool operator<=(const local_time& lhs, const local_time& rhs)
+{
+    return (lhs < rhs) || (lhs == rhs);
+}
+inline bool operator> (const local_time& lhs, const local_time& rhs)
+{
+    return !(lhs <= rhs);
+}
+inline bool operator>=(const local_time& lhs, const local_time& rhs)
+{
+    return !(lhs < rhs);
+}
+
+template<typename charT, typename traits>
+std::basic_ostream<charT, traits>&
+operator<<(std::basic_ostream<charT, traits>& os, const local_time& time)
+{
+    os << std::setfill('0') << std::setw(2) << static_cast<int>(time.hour  ) << ':';
+    os << std::setfill('0') << std::setw(2) << static_cast<int>(time.minute) << ':';
+    os << std::setfill('0') << std::setw(2) << static_cast<int>(time.second);
+    if(time.millisecond != 0 || time.microsecond != 0 || time.nanosecond != 0)
+    {
+        os << '.';
+        os << std::setfill('0') << std::setw(3) << static_cast<int>(time.millisecond);
+        if(time.microsecond != 0 || time.nanosecond != 0)
+        {
+            os << std::setfill('0') << std::setw(3) << static_cast<int>(time.microsecond);
+            if(time.nanosecond != 0)
+            {
+                os << std::setfill('0') << std::setw(3) << static_cast<int>(time.nanosecond);
+            }
+        }
+    }
+    return os;
+}
+
+struct time_offset
+{
+    std::int8_t hour{};   // [-12, 12]
+    std::int8_t minute{}; // [-59, 59]
+
+    time_offset(int h, int m)
+        : hour  (static_cast<std::int8_t>(h)),
+          minute(static_cast<std::int8_t>(m))
+    {}
+
+    operator std::chrono::minutes() const
+    {
+        return std::chrono::minutes(this->minute) +
+               std::chrono::hours(this->hour);
+    }
+
+    time_offset() = default;
+    ~time_offset() = default;
+    time_offset(time_offset const&) = default;
+    time_offset(time_offset&&)      = default;
+    time_offset& operator=(time_offset const&) = default;
+    time_offset& operator=(time_offset&&)      = default;
+};
+
+inline bool operator==(const time_offset& lhs, const time_offset& rhs)
+{
+    return std::make_tuple(lhs.hour, lhs.minute) ==
+           std::make_tuple(rhs.hour, rhs.minute);
+}
+inline bool operator!=(const time_offset& lhs, const time_offset& rhs)
+{
+    return !(lhs == rhs);
+}
+inline bool operator< (const time_offset& lhs, const time_offset& rhs)
+{
+    return std::make_tuple(lhs.hour, lhs.minute) <
+           std::make_tuple(rhs.hour, rhs.minute);
+}
+inline bool operator<=(const time_offset& lhs, const time_offset& rhs)
+{
+    return (lhs < rhs) || (lhs == rhs);
+}
+inline bool operator> (const time_offset& lhs, const time_offset& rhs)
+{
+    return !(lhs <= rhs);
+}
+inline bool operator>=(const time_offset& lhs, const time_offset& rhs)
+{
+    return !(lhs < rhs);
+}
+
+template<typename charT, typename traits>
+std::basic_ostream<charT, traits>&
+operator<<(std::basic_ostream<charT, traits>& os, const time_offset& offset)
+{
+    if(offset.hour == 0 && offset.minute == 0)
+    {
+        os << 'Z';
+        return os;
+    }
+    int minute = static_cast<int>(offset.hour) * 60 + offset.minute;
+    if(minute < 0){os << '-'; minute = std::abs(minute);} else {os << '+';}
+    os << std::setfill('0') << std::setw(2) << minute / 60 << ':';
+    os << std::setfill('0') << std::setw(2) << minute % 60;
+    return os;
+}
+
+struct local_datetime
+{
+    local_date date{};
+    local_time time{};
+
+    local_datetime(local_date d, local_time t): date(d), time(t) {}
+
+    explicit local_datetime(const std::tm& t): date(t), time(t){}
+
+    explicit local_datetime(const std::chrono::system_clock::time_point& tp)
+    {
+        const auto t = std::chrono::system_clock::to_time_t(tp);
+        std::tm ltime = detail::localtime_s(&t);
+
+        this->date = local_date(ltime);
+        this->time = local_time(ltime);
+
+        // std::tm lacks subsecond information, so diff between tp and tm
+        // can be used to get millisecond & microsecond information.
+        const auto t_diff = tp -
+            std::chrono::system_clock::from_time_t(std::mktime(&ltime));
+        this->time.millisecond = static_cast<std::uint16_t>(
+          std::chrono::duration_cast<std::chrono::milliseconds>(t_diff).count());
+        this->time.microsecond = static_cast<std::uint16_t>(
+          std::chrono::duration_cast<std::chrono::microseconds>(t_diff).count());
+        this->time.nanosecond = static_cast<std::uint16_t>(
+          std::chrono::duration_cast<std::chrono::nanoseconds >(t_diff).count());
+    }
+
+    explicit local_datetime(const std::time_t t)
+        : local_datetime(std::chrono::system_clock::from_time_t(t))
+    {}
+
+    operator std::chrono::system_clock::time_point() const
+    {
+        using internal_duration =
+            typename std::chrono::system_clock::time_point::duration;
+
+        // Normally DST begins at A.M. 3 or 4. If we re-use conversion operator
+        // of local_date and local_time independently, the conversion fails if
+        // it is the day when DST begins or ends. Since local_date considers the
+        // time is 00:00 A.M. and local_time does not consider DST because it
+        // does not have any date information. We need to consider both date and
+        // time information at the same time to convert it correctly.
+
+        std::tm t;
+        t.tm_sec   = static_cast<int>(this->time.second);
+        t.tm_min   = static_cast<int>(this->time.minute);
+        t.tm_hour  = static_cast<int>(this->time.hour);
+        t.tm_mday  = static_cast<int>(this->date.day);
+        t.tm_mon   = static_cast<int>(this->date.month);
+        t.tm_year  = static_cast<int>(this->date.year) - 1900;
+        t.tm_wday  = 0; // the value will be ignored
+        t.tm_yday  = 0; // the value will be ignored
+        t.tm_isdst = -1;
+
+        // std::mktime returns date as local time zone. no conversion needed
+        auto dt = std::chrono::system_clock::from_time_t(std::mktime(&t));
+        dt += std::chrono::duration_cast<internal_duration>(
+                std::chrono::milliseconds(this->time.millisecond) +
+                std::chrono::microseconds(this->time.microsecond) +
+                std::chrono::nanoseconds (this->time.nanosecond));
+        return dt;
+    }
+
+    operator std::time_t() const
+    {
+        return std::chrono::system_clock::to_time_t(
+                std::chrono::system_clock::time_point(*this));
+    }
+
+    local_datetime() = default;
+    ~local_datetime() = default;
+    local_datetime(local_datetime const&) = default;
+    local_datetime(local_datetime&&)      = default;
+    local_datetime& operator=(local_datetime const&) = default;
+    local_datetime& operator=(local_datetime&&)      = default;
+};
+
+inline bool operator==(const local_datetime& lhs, const local_datetime& rhs)
+{
+    return std::make_tuple(lhs.date, lhs.time) ==
+           std::make_tuple(rhs.date, rhs.time);
+}
+inline bool operator!=(const local_datetime& lhs, const local_datetime& rhs)
+{
+    return !(lhs == rhs);
+}
+inline bool operator< (const local_datetime& lhs, const local_datetime& rhs)
+{
+    return std::make_tuple(lhs.date, lhs.time) <
+           std::make_tuple(rhs.date, rhs.time);
+}
+inline bool operator<=(const local_datetime& lhs, const local_datetime& rhs)
+{
+    return (lhs < rhs) || (lhs == rhs);
+}
+inline bool operator> (const local_datetime& lhs, const local_datetime& rhs)
+{
+    return !(lhs <= rhs);
+}
+inline bool operator>=(const local_datetime& lhs, const local_datetime& rhs)
+{
+    return !(lhs < rhs);
+}
+
+template<typename charT, typename traits>
+std::basic_ostream<charT, traits>&
+operator<<(std::basic_ostream<charT, traits>& os, const local_datetime& dt)
+{
+    os << dt.date << 'T' << dt.time;
+    return os;
+}
+
+struct offset_datetime
+{
+    local_date  date{};
+    local_time  time{};
+    time_offset offset{};
+
+    offset_datetime(local_date d, local_time t, time_offset o)
+        : date(d), time(t), offset(o)
+    {}
+    offset_datetime(const local_datetime& dt, time_offset o)
+        : date(dt.date), time(dt.time), offset(o)
+    {}
+    explicit offset_datetime(const local_datetime& ld)
+        : date(ld.date), time(ld.time), offset(get_local_offset(nullptr))
+          // use the current local timezone offset
+    {}
+    explicit offset_datetime(const std::chrono::system_clock::time_point& tp)
+        : offset(0, 0) // use gmtime
+    {
+        const auto timet = std::chrono::system_clock::to_time_t(tp);
+        const auto tm    = detail::gmtime_s(&timet);
+        this->date = local_date(tm);
+        this->time = local_time(tm);
+    }
+    explicit offset_datetime(const std::time_t& t)
+        : offset(0, 0) // use gmtime
+    {
+        const auto tm    = detail::gmtime_s(&t);
+        this->date = local_date(tm);
+        this->time = local_time(tm);
+    }
+    explicit offset_datetime(const std::tm& t)
+        : offset(0, 0) // assume gmtime
+    {
+        this->date = local_date(t);
+        this->time = local_time(t);
+    }
+
+    operator std::chrono::system_clock::time_point() const
+    {
+        // get date-time
+        using internal_duration =
+            typename std::chrono::system_clock::time_point::duration;
+
+        // first, convert it to local date-time information in the same way as
+        // local_datetime does. later we will use time_t to adjust time offset.
+        std::tm t;
+        t.tm_sec   = static_cast<int>(this->time.second);
+        t.tm_min   = static_cast<int>(this->time.minute);
+        t.tm_hour  = static_cast<int>(this->time.hour);
+        t.tm_mday  = static_cast<int>(this->date.day);
+        t.tm_mon   = static_cast<int>(this->date.month);
+        t.tm_year  = static_cast<int>(this->date.year) - 1900;
+        t.tm_wday  = 0; // the value will be ignored
+        t.tm_yday  = 0; // the value will be ignored
+        t.tm_isdst = -1;
+        const std::time_t tp_loc = std::mktime(std::addressof(t));
+
+        auto tp = std::chrono::system_clock::from_time_t(tp_loc);
+        tp += std::chrono::duration_cast<internal_duration>(
+                std::chrono::milliseconds(this->time.millisecond) +
+                std::chrono::microseconds(this->time.microsecond) +
+                std::chrono::nanoseconds (this->time.nanosecond));
+
+        // Since mktime uses local time zone, it should be corrected.
+        // `12:00:00+09:00` means `03:00:00Z`. So mktime returns `03:00:00Z` if
+        // we are in `+09:00` timezone. To represent `12:00:00Z` there, we need
+        // to add `+09:00` to `03:00:00Z`.
+        //    Here, it uses the time_t converted from date-time info to handle
+        // daylight saving time.
+        const auto ofs = get_local_offset(std::addressof(tp_loc));
+        tp += std::chrono::hours  (ofs.hour);
+        tp += std::chrono::minutes(ofs.minute);
+
+        // We got `12:00:00Z` by correcting local timezone applied by mktime.
+        // Then we will apply the offset. Let's say `12:00:00-08:00` is given.
+        // And now, we have `12:00:00Z`. `12:00:00-08:00` means `20:00:00Z`.
+        // So we need to subtract the offset.
+        tp -= std::chrono::minutes(this->offset);
+        return tp;
+    }
+
+    operator std::time_t() const
+    {
+        return std::chrono::system_clock::to_time_t(
+                std::chrono::system_clock::time_point(*this));
+    }
+
+    offset_datetime() = default;
+    ~offset_datetime() = default;
+    offset_datetime(offset_datetime const&) = default;
+    offset_datetime(offset_datetime&&)      = default;
+    offset_datetime& operator=(offset_datetime const&) = default;
+    offset_datetime& operator=(offset_datetime&&)      = default;
+
+  private:
+
+    static time_offset get_local_offset(const std::time_t* tp)
+    {
+        // get local timezone with the same date-time information as mktime
+        const auto t = detail::localtime_s(tp);
+
+        std::array<char, 6> buf;
+        const auto result = std::strftime(buf.data(), 6, "%z", &t); // +hhmm\0
+        if(result != 5)
+        {
+            throw std::runtime_error("toml::offset_datetime: cannot obtain "
+                                     "timezone information of current env");
+        }
+        const int ofs = std::atoi(buf.data());
+        const int ofs_h = ofs / 100;
+        const int ofs_m = ofs - (ofs_h * 100);
+        return time_offset(ofs_h, ofs_m);
+    }
+};
+
+inline bool operator==(const offset_datetime& lhs, const offset_datetime& rhs)
+{
+    return std::make_tuple(lhs.date, lhs.time, lhs.offset) ==
+           std::make_tuple(rhs.date, rhs.time, rhs.offset);
+}
+inline bool operator!=(const offset_datetime& lhs, const offset_datetime& rhs)
+{
+    return !(lhs == rhs);
+}
+inline bool operator< (const offset_datetime& lhs, const offset_datetime& rhs)
+{
+    return std::make_tuple(lhs.date, lhs.time, lhs.offset) <
+           std::make_tuple(rhs.date, rhs.time, rhs.offset);
+}
+inline bool operator<=(const offset_datetime& lhs, const offset_datetime& rhs)
+{
+    return (lhs < rhs) || (lhs == rhs);
+}
+inline bool operator> (const offset_datetime& lhs, const offset_datetime& rhs)
+{
+    return !(lhs <= rhs);
+}
+inline bool operator>=(const offset_datetime& lhs, const offset_datetime& rhs)
+{
+    return !(lhs < rhs);
+}
+
+template<typename charT, typename traits>
+std::basic_ostream<charT, traits>&
+operator<<(std::basic_ostream<charT, traits>& os, const offset_datetime& dt)
+{
+    os << dt.date << 'T' << dt.time << dt.offset;
+    return os;
+}
+
+}//toml
+#endif// TOML11_DATETIME
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/exception.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,83 @@
+//     Copyright Toru Niina 2017.
+// Distributed under the MIT License.
+#ifndef TOML11_EXCEPTION_HPP
+#define TOML11_EXCEPTION_HPP
+
+#include <array>
+#include <string>
+#include <stdexcept>
+
+#include <cstring>
+
+#include "source_location.hpp"
+
+namespace toml
+{
+
+struct file_io_error : public std::runtime_error
+{
+  public:
+    file_io_error(int errnum, const std::string& msg, const std::string& fname)
+        : std::runtime_error(msg + " \"" + fname + "\": errno = " + std::to_string(errnum)),
+          errno_(errnum)
+    {}
+
+    int get_errno() const noexcept {return errno_;}
+
+  private:
+    int errno_;
+};
+
+struct exception : public std::exception
+{
+  public:
+    explicit exception(const source_location& loc): loc_(loc) {}
+    virtual ~exception() noexcept override = default;
+    virtual const char* what() const noexcept override {return "";}
+    virtual source_location const& location() const noexcept {return loc_;}
+
+  protected:
+    source_location loc_;
+};
+
+struct syntax_error : public toml::exception
+{
+  public:
+    explicit syntax_error(const std::string& what_arg, const source_location& loc)
+        : exception(loc), what_(what_arg)
+    {}
+    virtual ~syntax_error() noexcept override = default;
+    virtual const char* what() const noexcept override {return what_.c_str();}
+
+  protected:
+    std::string what_;
+};
+
+struct type_error : public toml::exception
+{
+  public:
+    explicit type_error(const std::string& what_arg, const source_location& loc)
+        : exception(loc), what_(what_arg)
+    {}
+    virtual ~type_error() noexcept override = default;
+    virtual const char* what() const noexcept override {return what_.c_str();}
+
+  protected:
+    std::string what_;
+};
+
+struct internal_error : public toml::exception
+{
+  public:
+    explicit internal_error(const std::string& what_arg, const source_location& loc)
+        : exception(loc), what_(what_arg)
+    {}
+    virtual ~internal_error() noexcept override = default;
+    virtual const char* what() const noexcept override {return what_.c_str();}
+
+  protected:
+    std::string what_;
+};
+
+} // toml
+#endif // TOML_EXCEPTION
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/from.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,19 @@
+//     Copyright Toru Niina 2019.
+// Distributed under the MIT License.
+#ifndef TOML11_FROM_HPP
+#define TOML11_FROM_HPP
+
+namespace toml
+{
+
+template<typename T>
+struct from;
+// {
+//     static T from_toml(const toml::value& v)
+//     {
+//         // User-defined conversions ...
+//     }
+// };
+
+} // toml
+#endif // TOML11_FROM_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/get.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,1154 @@
+//     Copyright Toru Niina 2017.
+// Distributed under the MIT License.
+#ifndef TOML11_GET_HPP
+#define TOML11_GET_HPP
+#include <algorithm>
+
+#include "from.hpp"
+#include "result.hpp"
+#include "value.hpp"
+
+namespace toml
+{
+
+// ============================================================================
+// exact toml::* type
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T> &
+get(basic_value<C, M, V>& v)
+{
+    return v.template cast<detail::type_to_enum<T, basic_value<C, M, V>>::value>();
+}
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T> const&
+get(const basic_value<C, M, V>& v)
+{
+    return v.template cast<detail::type_to_enum<T, basic_value<C, M, V>>::value>();
+}
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T>
+get(basic_value<C, M, V>&& v)
+{
+    return T(std::move(v).template cast<detail::type_to_enum<T, basic_value<C, M, V>>::value>());
+}
+
+// ============================================================================
+// T == toml::value; identity transformation.
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+inline detail::enable_if_t<std::is_same<T, basic_value<C, M, V>>::value, T>&
+get(basic_value<C, M, V>& v)
+{
+    return v;
+}
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+inline detail::enable_if_t<std::is_same<T, basic_value<C, M, V>>::value, T> const&
+get(const basic_value<C, M, V>& v)
+{
+    return v;
+}
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+inline detail::enable_if_t<std::is_same<T, basic_value<C, M, V>>::value, T>
+get(basic_value<C, M, V>&& v)
+{
+    return basic_value<C, M, V>(std::move(v));
+}
+
+// ============================================================================
+// T == toml::basic_value<C2, M2, V2>; basic_value -> basic_value
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+inline detail::enable_if_t<detail::conjunction<detail::is_basic_value<T>,
+    detail::negation<std::is_same<T, basic_value<C, M, V>>>
+    >::value, T>
+get(const basic_value<C, M, V>& v)
+{
+    return T(v);
+}
+
+// ============================================================================
+// integer convertible from toml::Integer
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+inline detail::enable_if_t<detail::conjunction<
+    std::is_integral<T>,                            // T is integral
+    detail::negation<std::is_same<T, bool>>,        // but not bool
+    detail::negation<                               // but not toml::integer
+        detail::is_exact_toml_type<T, basic_value<C, M, V>>>
+    >::value, T>
+get(const basic_value<C, M, V>& v)
+{
+    return static_cast<T>(v.as_integer());
+}
+
+// ============================================================================
+// floating point convertible from toml::Float
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+inline detail::enable_if_t<detail::conjunction<
+    std::is_floating_point<T>,                      // T is floating_point
+    detail::negation<                               // but not toml::floating
+        detail::is_exact_toml_type<T, basic_value<C, M, V>>>
+    >::value, T>
+get(const basic_value<C, M, V>& v)
+{
+    return static_cast<T>(v.as_floating());
+}
+
+// ============================================================================
+// std::string; toml uses its own toml::string, but it should be convertible to
+// std::string seamlessly
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+inline detail::enable_if_t<std::is_same<T, std::string>::value, std::string>&
+get(basic_value<C, M, V>& v)
+{
+    return v.as_string().str;
+}
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+inline detail::enable_if_t<std::is_same<T, std::string>::value, std::string> const&
+get(const basic_value<C, M, V>& v)
+{
+    return v.as_string().str;
+}
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+inline detail::enable_if_t<std::is_same<T, std::string>::value, std::string>
+get(basic_value<C, M, V>&& v)
+{
+    return std::string(std::move(v.as_string().str));
+}
+
+// ============================================================================
+// std::string_view
+
+#if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+inline detail::enable_if_t<std::is_same<T, std::string_view>::value, std::string_view>
+get(const basic_value<C, M, V>& v)
+{
+    return std::string_view(v.as_string().str);
+}
+#endif
+
+// ============================================================================
+// std::chrono::duration from toml::local_time.
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+inline detail::enable_if_t<detail::is_chrono_duration<T>::value, T>
+get(const basic_value<C, M, V>& v)
+{
+    return std::chrono::duration_cast<T>(
+            std::chrono::nanoseconds(v.as_local_time()));
+}
+
+// ============================================================================
+// std::chrono::system_clock::time_point from toml::datetime variants
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+inline detail::enable_if_t<
+    std::is_same<std::chrono::system_clock::time_point, T>::value, T>
+get(const basic_value<C, M, V>& v)
+{
+    switch(v.type())
+    {
+        case value_t::local_date:
+        {
+            return std::chrono::system_clock::time_point(v.as_local_date());
+        }
+        case value_t::local_datetime:
+        {
+            return std::chrono::system_clock::time_point(v.as_local_datetime());
+        }
+        case value_t::offset_datetime:
+        {
+            return std::chrono::system_clock::time_point(v.as_offset_datetime());
+        }
+        default:
+        {
+            throw type_error(detail::format_underline("toml::value: "
+                "bad_cast to std::chrono::system_clock::time_point", {
+                    {v.location(), concat_to_string("the actual type is ", v.type())}
+                }), v.location());
+        }
+    }
+}
+
+// ============================================================================
+// forward declaration to use this recursively. ignore this and go ahead.
+
+// array-like type with push_back(value) method
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::conjunction<
+    detail::is_container<T>,         // T is a container
+    detail::has_push_back_method<T>, // T::push_back(value) works
+    detail::negation<                // but not toml::array
+        detail::is_exact_toml_type<T, basic_value<C, M, V>>>
+    >::value, T>
+get(const basic_value<C, M, V>&);
+
+// array-like type without push_back(value) method
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::conjunction<
+    detail::is_container<T>,                           // T is a container
+    detail::negation<detail::has_push_back_method<T>>, // w/o push_back(...)
+    detail::negation<detail::has_specialized_from<T>>, // T does not have special conversion
+    detail::negation<                                  // not toml::array
+        detail::is_exact_toml_type<T, basic_value<C, M, V>>>
+    >::value, T>
+get(const basic_value<C, M, V>&);
+
+// std::pair<T1, T2>
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::is_std_pair<T>::value, T>
+get(const basic_value<C, M, V>&);
+
+// std::tuple<T1, T2, ...>
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::is_std_tuple<T>::value, T>
+get(const basic_value<C, M, V>&);
+
+// map-like classes
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::conjunction<
+    detail::is_map<T>, // T is map
+    detail::negation<  // but not toml::table
+        detail::is_exact_toml_type<T, basic_value<C, M, V>>>
+    >::value, T>
+get(const basic_value<C, M, V>&);
+
+// T.from_toml(v)
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::conjunction<
+    detail::negation<                         // not a toml::* type
+        detail::is_exact_toml_type<T, basic_value<C, M, V>>>,
+    detail::has_from_toml_method<T, C, M, V>, // but has from_toml(toml::value)
+    std::is_default_constructible<T>          // and default constructible
+    >::value, T>
+get(const basic_value<C, M, V>&);
+
+// toml::from<T>::from_toml(v)
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::has_specialized_from<T>::value, T>
+get(const basic_value<C, M, V>&);
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::has_specialized_from<T>::value, T>
+get(basic_value<C, M, V>&);
+
+// T(const toml::value&) and T is not toml::basic_value,
+// and it does not have `from<T>` nor `from_toml`.
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::conjunction<
+    detail::negation<detail::is_basic_value<T>>,
+    std::is_constructible<T, const basic_value<C, M, V>&>,
+    detail::negation<detail::has_from_toml_method<T, C, M, V>>,
+    detail::negation<detail::has_specialized_from<T>>
+    >::value, T>
+get(const basic_value<C, M, V>&);
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::conjunction<
+    detail::negation<detail::is_basic_value<T>>,
+    std::is_constructible<T, basic_value<C, M, V>&>,
+    detail::negation<detail::has_from_toml_method<T, C, M, V>>,
+    detail::negation<detail::has_specialized_from<T>>
+    >::value, T>
+get(basic_value<C, M, V>&);
+
+// ============================================================================
+// array-like types; most likely STL container, like std::vector, etc.
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::conjunction<
+    detail::is_container<T>,         // T is a container
+    detail::has_push_back_method<T>, // container.push_back(elem) works
+    detail::negation<                // but not toml::array
+        detail::is_exact_toml_type<T, basic_value<C, M, V>>>
+    >::value, T>
+get(const basic_value<C, M, V>& v)
+{
+    using value_type = typename T::value_type;
+    const auto& ary = v.as_array();
+
+    T container;
+    try_reserve(container, ary.size());
+
+    for(const auto& elem : ary)
+    {
+        container.push_back(get<value_type>(elem));
+    }
+    return container;
+}
+
+// ============================================================================
+// std::forward_list does not have push_back, insert, or emplace.
+// It has insert_after, emplace_after, push_front.
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::is_std_forward_list<T>::value, T>
+get(const basic_value<C, M, V>& v)
+{
+    using value_type = typename T::value_type;
+    T container;
+    for(const auto& elem : v.as_array())
+    {
+        container.push_front(get<value_type>(elem));
+    }
+    container.reverse();
+    return container;
+}
+
+// ============================================================================
+// array-like types, without push_back(). most likely [std|boost]::array.
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::conjunction<
+    detail::is_container<T>,                           // T is a container
+    detail::negation<detail::has_push_back_method<T>>, // w/o push_back
+    detail::negation<detail::has_specialized_from<T>>, // T does not have special conversion
+    detail::negation<                                  // T is not toml::array
+        detail::is_exact_toml_type<T, basic_value<C, M, V>>>
+    >::value, T>
+get(const basic_value<C, M, V>& v)
+{
+    using value_type = typename T::value_type;
+    const auto& ar = v.as_array();
+
+    T container;
+    if(ar.size() != container.size())
+    {
+        throw std::out_of_range(detail::format_underline(concat_to_string(
+            "toml::get: specified container size is ", container.size(),
+            " but there are ", ar.size(), " elements in toml array."), {
+                {v.location(), "here"}
+            }));
+    }
+    for(std::size_t i=0; i<ar.size(); ++i)
+    {
+        container[i] = ::toml::get<value_type>(ar[i]);
+    }
+    return container;
+}
+
+// ============================================================================
+// std::pair.
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::is_std_pair<T>::value, T>
+get(const basic_value<C, M, V>& v)
+{
+    using first_type  = typename T::first_type;
+    using second_type = typename T::second_type;
+
+    const auto& ar = v.as_array();
+    if(ar.size() != 2)
+    {
+        throw std::out_of_range(detail::format_underline(concat_to_string(
+            "toml::get: specified std::pair but there are ", ar.size(),
+            " elements in toml array."), {{v.location(), "here"}}));
+    }
+    return std::make_pair(::toml::get<first_type >(ar.at(0)),
+                          ::toml::get<second_type>(ar.at(1)));
+}
+
+// ============================================================================
+// std::tuple.
+
+namespace detail
+{
+template<typename T, typename Array, std::size_t ... I>
+T get_tuple_impl(const Array& a, index_sequence<I...>)
+{
+    return std::make_tuple(
+        ::toml::get<typename std::tuple_element<I, T>::type>(a.at(I))...);
+}
+} // detail
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::is_std_tuple<T>::value, T>
+get(const basic_value<C, M, V>& v)
+{
+    const auto& ar = v.as_array();
+    if(ar.size() != std::tuple_size<T>::value)
+    {
+        throw std::out_of_range(detail::format_underline(concat_to_string(
+            "toml::get: specified std::tuple with ",
+            std::tuple_size<T>::value, " elements, but there are ", ar.size(),
+            " elements in toml array."), {{v.location(), "here"}}));
+    }
+    return detail::get_tuple_impl<T>(ar,
+            detail::make_index_sequence<std::tuple_size<T>::value>{});
+}
+
+// ============================================================================
+// map-like types; most likely STL map, like std::map or std::unordered_map.
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::conjunction<
+    detail::is_map<T>, // T is map
+    detail::negation<  // but not toml::array
+        detail::is_exact_toml_type<T, basic_value<C, M, V>>>
+    >::value, T>
+get(const basic_value<C, M, V>& v)
+{
+    using key_type    = typename T::key_type;
+    using mapped_type = typename T::mapped_type;
+    static_assert(std::is_convertible<std::string, key_type>::value,
+                  "toml::get only supports map type of which key_type is "
+                  "convertible from std::string.");
+    T map;
+    for(const auto& kv : v.as_table())
+    {
+        map.emplace(key_type(kv.first), get<mapped_type>(kv.second));
+    }
+    return map;
+}
+
+// ============================================================================
+// user-defined, but compatible types.
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::conjunction<
+    detail::negation<                         // not a toml::* type
+        detail::is_exact_toml_type<T, basic_value<C, M, V>>>,
+    detail::has_from_toml_method<T, C, M, V>, // but has from_toml(toml::value) memfn
+    std::is_default_constructible<T>          // and default constructible
+    >::value, T>
+get(const basic_value<C, M, V>& v)
+{
+    T ud;
+    ud.from_toml(v);
+    return ud;
+}
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::has_specialized_from<T>::value, T>
+get(const basic_value<C, M, V>& v)
+{
+    return ::toml::from<T>::from_toml(v);
+}
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::has_specialized_from<T>::value, T>
+get(basic_value<C, M, V>& v)
+{
+    return ::toml::from<T>::from_toml(v);
+}
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::conjunction<
+    detail::negation<detail::is_basic_value<T>>,                // T is not a toml::value
+    std::is_constructible<T, const basic_value<C, M, V>&>,      // T is constructible from toml::value
+    detail::negation<detail::has_from_toml_method<T, C, M, V>>, // and T does not have T.from_toml(v);
+    detail::negation<detail::has_specialized_from<T>>           // and T does not have toml::from<T>{};
+    >::value, T>
+get(const basic_value<C, M, V>& v)
+{
+    return T(v);
+}
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::conjunction<
+    detail::negation<detail::is_basic_value<T>>,                // T is not a toml::value
+    std::is_constructible<T, basic_value<C, M, V>&>,      // T is constructible from toml::value
+    detail::negation<detail::has_from_toml_method<T, C, M, V>>, // and T does not have T.from_toml(v);
+    detail::negation<detail::has_specialized_from<T>>           // and T does not have toml::from<T>{};
+    >::value, T>
+get(basic_value<C, M, V>& v)
+{
+    return T(v);
+}
+
+// ============================================================================
+// find
+
+// ----------------------------------------------------------------------------
+// these overloads do not require to set T. and returns value itself.
+template<typename C,
+         template<typename ...> class M, template<typename ...> class V>
+basic_value<C, M, V> const& find(const basic_value<C, M, V>& v, const key& ky)
+{
+    const auto& tab = v.as_table();
+    if(tab.count(ky) == 0)
+    {
+        detail::throw_key_not_found_error(v, ky);
+    }
+    return tab.at(ky);
+}
+template<typename C,
+         template<typename ...> class M, template<typename ...> class V>
+basic_value<C, M, V>& find(basic_value<C, M, V>& v, const key& ky)
+{
+    auto& tab = v.as_table();
+    if(tab.count(ky) == 0)
+    {
+        detail::throw_key_not_found_error(v, ky);
+    }
+    return tab.at(ky);
+}
+template<typename C,
+         template<typename ...> class M, template<typename ...> class V>
+basic_value<C, M, V> find(basic_value<C, M, V>&& v, const key& ky)
+{
+    typename basic_value<C, M, V>::table_type tab = std::move(v).as_table();
+    if(tab.count(ky) == 0)
+    {
+        detail::throw_key_not_found_error(v, ky);
+    }
+    return basic_value<C, M, V>(std::move(tab.at(ky)));
+}
+
+// ----------------------------------------------------------------------------
+// find(value, idx)
+template<typename C,
+         template<typename ...> class M, template<typename ...> class V>
+basic_value<C, M, V> const&
+find(const basic_value<C, M, V>& v, const std::size_t idx)
+{
+    const auto& ary = v.as_array();
+    if(ary.size() <= idx)
+    {
+        throw std::out_of_range(detail::format_underline(concat_to_string(
+            "index ", idx, " is out of range"), {{v.location(), "in this array"}}));
+    }
+    return ary.at(idx);
+}
+template<typename C,
+         template<typename ...> class M, template<typename ...> class V>
+basic_value<C, M, V>& find(basic_value<C, M, V>& v, const std::size_t idx)
+{
+    auto& ary = v.as_array();
+    if(ary.size() <= idx)
+    {
+        throw std::out_of_range(detail::format_underline(concat_to_string(
+            "index ", idx, " is out of range"), {{v.location(), "in this array"}}));
+    }
+    return ary.at(idx);
+}
+template<typename C,
+         template<typename ...> class M, template<typename ...> class V>
+basic_value<C, M, V> find(basic_value<C, M, V>&& v, const std::size_t idx)
+{
+    auto& ary = v.as_array();
+    if(ary.size() <= idx)
+    {
+        throw std::out_of_range(detail::format_underline(concat_to_string(
+            "index ", idx, " is out of range"), {{v.location(), "in this array"}}));
+    }
+    return basic_value<C, M, V>(std::move(ary.at(idx)));
+}
+
+// ----------------------------------------------------------------------------
+// find<T>(value, key);
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+decltype(::toml::get<T>(std::declval<basic_value<C, M, V> const&>()))
+find(const basic_value<C, M, V>& v, const key& ky)
+{
+    const auto& tab = v.as_table();
+    if(tab.count(ky) == 0)
+    {
+        detail::throw_key_not_found_error(v, ky);
+    }
+    return ::toml::get<T>(tab.at(ky));
+}
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&>()))
+find(basic_value<C, M, V>& v, const key& ky)
+{
+    auto& tab = v.as_table();
+    if(tab.count(ky) == 0)
+    {
+        detail::throw_key_not_found_error(v, ky);
+    }
+    return ::toml::get<T>(tab.at(ky));
+}
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&&>()))
+find(basic_value<C, M, V>&& v, const key& ky)
+{
+    typename basic_value<C, M, V>::table_type tab = std::move(v).as_table();
+    if(tab.count(ky) == 0)
+    {
+        detail::throw_key_not_found_error(v, ky);
+    }
+    return ::toml::get<T>(std::move(tab.at(ky)));
+}
+
+// ----------------------------------------------------------------------------
+// find<T>(value, idx)
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+decltype(::toml::get<T>(std::declval<basic_value<C, M, V> const&>()))
+find(const basic_value<C, M, V>& v, const std::size_t idx)
+{
+    const auto& ary = v.as_array();
+    if(ary.size() <= idx)
+    {
+        throw std::out_of_range(detail::format_underline(concat_to_string(
+            "index ", idx, " is out of range"), {{v.location(), "in this array"}}));
+    }
+    return ::toml::get<T>(ary.at(idx));
+}
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&>()))
+find(basic_value<C, M, V>& v, const std::size_t idx)
+{
+    auto& ary = v.as_array();
+    if(ary.size() <= idx)
+    {
+        throw std::out_of_range(detail::format_underline(concat_to_string(
+            "index ", idx, " is out of range"), {{v.location(), "in this array"}}));
+    }
+    return ::toml::get<T>(ary.at(idx));
+}
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&&>()))
+find(basic_value<C, M, V>&& v, const std::size_t idx)
+{
+    typename basic_value<C, M, V>::array_type ary = std::move(v).as_array();
+    if(ary.size() <= idx)
+    {
+        throw std::out_of_range(detail::format_underline(concat_to_string(
+            "index ", idx, " is out of range"), {{v.location(), "in this array"}}));
+    }
+    return ::toml::get<T>(std::move(ary.at(idx)));
+}
+
+// --------------------------------------------------------------------------
+// toml::find(toml::value, toml::key, Ts&& ... keys)
+
+namespace detail
+{
+// It suppresses warnings by -Wsign-conversion. Let's say we have the following
+// code.
+// ```cpp
+// const auto x = toml::find<std::string>(data, "array", 0);
+// ```
+// Here, the type of literal number `0` is `int`. `int` is a signed integer.
+// `toml::find` takes `std::size_t` as an index. So it causes implicit sign
+// conversion and `-Wsign-conversion` warns about it. Using `0u` instead of `0`
+// suppresses the warning, but it makes user code messy.
+//     To suppress this warning, we need to be aware of type conversion caused
+// by `toml::find(v, key1, key2, ... keys)`. But the thing is that the types of
+// keys can be any combination of {string-like, size_t-like}. Of course we can't
+// write down all the combinations. Thus we need to use some function that
+// recognize the type of argument and cast it into `std::string` or
+// `std::size_t` depending on the context.
+//     `key_cast` does the job. It has 2 overloads. One is invoked when the
+// argument type is an integer and cast the argument into `std::size_t`. The
+// other is invoked when the argument type is not an integer, possibly one of
+// std::string, const char[N] or const char*, and construct std::string from
+// the argument.
+//     `toml::find(v, k1, k2, ... ks)` uses `key_cast` before passing `ks` to
+// `toml::find(v, k)` to suppress -Wsign-conversion.
+
+template<typename T>
+enable_if_t<conjunction<std::is_integral<remove_cvref_t<T>>,
+            negation<std::is_same<remove_cvref_t<T>, bool>>>::value, std::size_t>
+key_cast(T&& v) noexcept
+{
+    return std::size_t(v);
+}
+template<typename T>
+enable_if_t<negation<conjunction<std::is_integral<remove_cvref_t<T>>,
+            negation<std::is_same<remove_cvref_t<T>, bool>>>>::value, std::string>
+key_cast(T&& v) noexcept
+{
+    return std::string(std::forward<T>(v));
+}
+} // detail
+
+template<typename C,
+         template<typename ...> class M, template<typename ...> class V,
+         typename Key1, typename Key2, typename ... Keys>
+const basic_value<C, M, V>&
+find(const basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
+{
+    return ::toml::find(::toml::find(v, detail::key_cast(k1)),
+            detail::key_cast(k2), std::forward<Keys>(keys)...);
+}
+template<typename C,
+         template<typename ...> class M, template<typename ...> class V,
+         typename Key1, typename Key2, typename ... Keys>
+basic_value<C, M, V>&
+find(basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
+{
+    return ::toml::find(::toml::find(v, detail::key_cast(k1)),
+            detail::key_cast(k2), std::forward<Keys>(keys)...);
+}
+template<typename C,
+         template<typename ...> class M, template<typename ...> class V,
+         typename Key1, typename Key2, typename ... Keys>
+basic_value<C, M, V>
+find(basic_value<C, M, V>&& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
+{
+    return ::toml::find(::toml::find(std::move(v), std::forward<Key1>(k1)),
+            detail::key_cast(k2), std::forward<Keys>(keys)...);
+}
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V,
+         typename Key1, typename Key2, typename ... Keys>
+decltype(::toml::get<T>(std::declval<const basic_value<C, M, V>&>()))
+find(const basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
+{
+    return ::toml::find<T>(::toml::find(v, detail::key_cast(k1)),
+            detail::key_cast(k2), std::forward<Keys>(keys)...);
+}
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V,
+         typename Key1, typename Key2, typename ... Keys>
+decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&>()))
+find(basic_value<C, M, V>& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
+{
+    return ::toml::find<T>(::toml::find(v, detail::key_cast(k1)),
+            detail::key_cast(k2), std::forward<Keys>(keys)...);
+}
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V,
+         typename Key1, typename Key2, typename ... Keys>
+decltype(::toml::get<T>(std::declval<basic_value<C, M, V>&&>()))
+find(basic_value<C, M, V>&& v, Key1&& k1, Key2&& k2, Keys&& ... keys)
+{
+    return ::toml::find<T>(::toml::find(std::move(v), detail::key_cast(k1)),
+            detail::key_cast(k2), std::forward<Keys>(keys)...);
+}
+
+// ============================================================================
+// get_or(value, fallback)
+
+template<typename C,
+         template<typename ...> class M, template<typename ...> class V>
+basic_value<C, M, V> const&
+get_or(const basic_value<C, M, V>& v, const basic_value<C, M, V>&)
+{
+    return v;
+}
+template<typename C,
+         template<typename ...> class M, template<typename ...> class V>
+basic_value<C, M, V>&
+get_or(basic_value<C, M, V>& v, basic_value<C, M, V>&)
+{
+    return v;
+}
+template<typename C,
+         template<typename ...> class M, template<typename ...> class V>
+basic_value<C, M, V>
+get_or(basic_value<C, M, V>&& v, basic_value<C, M, V>&&)
+{
+    return v;
+}
+
+// ----------------------------------------------------------------------------
+// specialization for the exact toml types (return type becomes lvalue ref)
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<
+    detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T> const&
+get_or(const basic_value<C, M, V>& v, const T& opt)
+{
+    try
+    {
+        return get<detail::remove_cvref_t<T>>(v);
+    }
+    catch(...)
+    {
+        return opt;
+    }
+}
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<
+    detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T>&
+get_or(basic_value<C, M, V>& v, T& opt)
+{
+    try
+    {
+        return get<detail::remove_cvref_t<T>>(v);
+    }
+    catch(...)
+    {
+        return opt;
+    }
+}
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::is_exact_toml_type<detail::remove_cvref_t<T>,
+    basic_value<C, M, V>>::value, detail::remove_cvref_t<T>>
+get_or(basic_value<C, M, V>&& v, T&& opt)
+{
+    try
+    {
+        return get<detail::remove_cvref_t<T>>(std::move(v));
+    }
+    catch(...)
+    {
+        return detail::remove_cvref_t<T>(std::forward<T>(opt));
+    }
+}
+
+// ----------------------------------------------------------------------------
+// specialization for std::string (return type becomes lvalue ref)
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<std::is_same<detail::remove_cvref_t<T>, std::string>::value,
+    std::string> const&
+get_or(const basic_value<C, M, V>& v, const T& opt)
+{
+    try
+    {
+        return v.as_string().str;
+    }
+    catch(...)
+    {
+        return opt;
+    }
+}
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<std::is_same<T, std::string>::value, std::string>&
+get_or(basic_value<C, M, V>& v, T& opt)
+{
+    try
+    {
+        return v.as_string().str;
+    }
+    catch(...)
+    {
+        return opt;
+    }
+}
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<
+    std::is_same<detail::remove_cvref_t<T>, std::string>::value, std::string>
+get_or(basic_value<C, M, V>&& v, T&& opt)
+{
+    try
+    {
+        return std::move(v.as_string().str);
+    }
+    catch(...)
+    {
+        return std::string(std::forward<T>(opt));
+    }
+}
+
+// ----------------------------------------------------------------------------
+// specialization for string literal
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::is_string_literal<
+    typename std::remove_reference<T>::type>::value, std::string>
+get_or(const basic_value<C, M, V>& v, T&& opt)
+{
+    try
+    {
+        return std::move(v.as_string().str);
+    }
+    catch(...)
+    {
+        return std::string(std::forward<T>(opt));
+    }
+}
+
+// ----------------------------------------------------------------------------
+// others (require type conversion and return type cannot be lvalue reference)
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::conjunction<
+    detail::negation<detail::is_exact_toml_type<detail::remove_cvref_t<T>,
+        basic_value<C, M, V>>>,
+    detail::negation<std::is_same<std::string, detail::remove_cvref_t<T>>>,
+    detail::negation<detail::is_string_literal<
+        typename std::remove_reference<T>::type>>
+    >::value, detail::remove_cvref_t<T>>
+get_or(const basic_value<C, M, V>& v, T&& opt)
+{
+    try
+    {
+        return get<detail::remove_cvref_t<T>>(v);
+    }
+    catch(...)
+    {
+        return detail::remove_cvref_t<T>(std::forward<T>(opt));
+    }
+}
+
+// ===========================================================================
+// find_or(value, key, fallback)
+
+template<typename C,
+         template<typename ...> class M, template<typename ...> class V>
+basic_value<C, M, V> const&
+find_or(const basic_value<C, M, V>& v, const key& ky,
+        const basic_value<C, M, V>& opt)
+{
+    if(!v.is_table()) {return opt;}
+    const auto& tab = v.as_table();
+    if(tab.count(ky) == 0) {return opt;}
+    return tab.at(ky);
+}
+
+template<typename C,
+         template<typename ...> class M, template<typename ...> class V>
+basic_value<C, M, V>&
+find_or(basic_value<C, M, V>& v, const toml::key& ky, basic_value<C, M, V>& opt)
+{
+    if(!v.is_table()) {return opt;}
+    auto& tab = v.as_table();
+    if(tab.count(ky) == 0) {return opt;}
+    return tab.at(ky);
+}
+
+template<typename C,
+         template<typename ...> class M, template<typename ...> class V>
+basic_value<C, M, V>
+find_or(basic_value<C, M, V>&& v, const toml::key& ky, basic_value<C, M, V>&& opt)
+{
+    if(!v.is_table()) {return opt;}
+    auto tab = std::move(v).as_table();
+    if(tab.count(ky) == 0) {return opt;}
+    return basic_value<C, M, V>(std::move(tab.at(ky)));
+}
+
+// ---------------------------------------------------------------------------
+// exact types (return type can be a reference)
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<
+    detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T> const&
+find_or(const basic_value<C, M, V>& v, const key& ky, const T& opt)
+{
+    if(!v.is_table()) {return opt;}
+    const auto& tab = v.as_table();
+    if(tab.count(ky) == 0) {return opt;}
+    return get_or(tab.at(ky), opt);
+}
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<
+    detail::is_exact_toml_type<T, basic_value<C, M, V>>::value, T>&
+find_or(basic_value<C, M, V>& v, const toml::key& ky, T& opt)
+{
+    if(!v.is_table()) {return opt;}
+    auto& tab = v.as_table();
+    if(tab.count(ky) == 0) {return opt;}
+    return get_or(tab.at(ky), opt);
+}
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<
+    detail::is_exact_toml_type<T, basic_value<C, M, V>>::value,
+    detail::remove_cvref_t<T>>
+find_or(basic_value<C, M, V>&& v, const toml::key& ky, T&& opt)
+{
+    if(!v.is_table()) {return std::forward<T>(opt);}
+    auto tab = std::move(v).as_table();
+    if(tab.count(ky) == 0) {return std::forward<T>(opt);}
+    return get_or(std::move(tab.at(ky)), std::forward<T>(opt));
+}
+
+// ---------------------------------------------------------------------------
+// std::string (return type can be a reference)
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<std::is_same<T, std::string>::value, std::string> const&
+find_or(const basic_value<C, M, V>& v, const key& ky, const T& opt)
+{
+    if(!v.is_table()) {return opt;}
+    const auto& tab = v.as_table();
+    if(tab.count(ky) == 0) {return opt;}
+    return get_or(tab.at(ky), opt);
+}
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<std::is_same<T, std::string>::value, std::string>&
+find_or(basic_value<C, M, V>& v, const toml::key& ky, T& opt)
+{
+    if(!v.is_table()) {return opt;}
+    auto& tab = v.as_table();
+    if(tab.count(ky) == 0) {return opt;}
+    return get_or(tab.at(ky), opt);
+}
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<std::is_same<T, std::string>::value, std::string>
+find_or(basic_value<C, M, V>&& v, const toml::key& ky, T&& opt)
+{
+    if(!v.is_table()) {return std::forward<T>(opt);}
+    auto tab = std::move(v).as_table();
+    if(tab.count(ky) == 0) {return std::forward<T>(opt);}
+    return get_or(std::move(tab.at(ky)), std::forward<T>(opt));
+}
+
+// ---------------------------------------------------------------------------
+// string literal (deduced as std::string)
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<
+    detail::is_string_literal<typename std::remove_reference<T>::type>::value,
+    std::string>
+find_or(const basic_value<C, M, V>& v, const toml::key& ky, T&& opt)
+{
+    if(!v.is_table()) {return std::string(opt);}
+    const auto& tab = v.as_table();
+    if(tab.count(ky) == 0) {return std::string(opt);}
+    return get_or(tab.at(ky), std::forward<T>(opt));
+}
+
+// ---------------------------------------------------------------------------
+// others (require type conversion and return type cannot be lvalue reference)
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+detail::enable_if_t<detail::conjunction<
+    // T is not an exact toml type
+    detail::negation<detail::is_exact_toml_type<
+        detail::remove_cvref_t<T>, basic_value<C, M, V>>>,
+    // T is not std::string
+    detail::negation<std::is_same<std::string, detail::remove_cvref_t<T>>>,
+    // T is not a string literal
+    detail::negation<detail::is_string_literal<
+        typename std::remove_reference<T>::type>>
+    >::value, detail::remove_cvref_t<T>>
+find_or(const basic_value<C, M, V>& v, const toml::key& ky, T&& opt)
+{
+    if(!v.is_table()) {return std::forward<T>(opt);}
+    const auto& tab = v.as_table();
+    if(tab.count(ky) == 0) {return std::forward<T>(opt);}
+    return get_or(tab.at(ky), std::forward<T>(opt));
+}
+
+// ---------------------------------------------------------------------------
+// recursive find-or with type deduction (find_or(value, keys, opt))
+
+template<typename Value, typename ... Ks,
+         typename detail::enable_if_t<(sizeof...(Ks) > 1), std::nullptr_t> = nullptr>
+         // here we need to add SFINAE in the template parameter to avoid
+         // infinite recursion in type deduction on gcc
+auto find_or(Value&& v, const toml::key& ky, Ks&& ... keys)
+    -> decltype(find_or(std::forward<Value>(v), ky, detail::last_one(std::forward<Ks>(keys)...)))
+{
+    if(!v.is_table())
+    {
+        return detail::last_one(std::forward<Ks>(keys)...);
+    }
+    auto&& tab = std::forward<Value>(v).as_table();
+    if(tab.count(ky) == 0)
+    {
+        return detail::last_one(std::forward<Ks>(keys)...);
+    }
+    return find_or(std::forward<decltype(tab)>(tab).at(ky), std::forward<Ks>(keys)...);
+}
+
+// ---------------------------------------------------------------------------
+// recursive find_or with explicit type specialization, find_or<int>(value, keys...)
+
+template<typename T, typename Value, typename ... Ks,
+         typename detail::enable_if_t<(sizeof...(Ks) > 1), std::nullptr_t> = nullptr>
+         // here we need to add SFINAE in the template parameter to avoid
+         // infinite recursion in type deduction on gcc
+auto find_or(Value&& v, const toml::key& ky, Ks&& ... keys)
+    -> decltype(find_or<T>(std::forward<Value>(v), ky, detail::last_one(std::forward<Ks>(keys)...)))
+{
+    if(!v.is_table())
+    {
+        return detail::last_one(std::forward<Ks>(keys)...);
+    }
+    auto&& tab = std::forward<Value>(v).as_table();
+    if(tab.count(ky) == 0)
+    {
+        return detail::last_one(std::forward<Ks>(keys)...);
+    }
+    return find_or(std::forward<decltype(tab)>(tab).at(ky), std::forward<Ks>(keys)...);
+}
+
+// ============================================================================
+// expect
+
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+result<T, std::string> expect(const basic_value<C, M, V>& v) noexcept
+{
+    try
+    {
+        return ok(get<T>(v));
+    }
+    catch(const std::exception& e)
+    {
+        return err(e.what());
+    }
+}
+template<typename T, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+result<T, std::string>
+expect(const basic_value<C, M, V>& v, const toml::key& k) noexcept
+{
+    try
+    {
+        return ok(find<T>(v, k));
+    }
+    catch(const std::exception& e)
+    {
+        return err(e.what());
+    }
+}
+
+} // toml
+#endif// TOML11_GET
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/into.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,19 @@
+//     Copyright Toru Niina 2019.
+// Distributed under the MIT License.
+#ifndef TOML11_INTO_HPP
+#define TOML11_INTO_HPP
+
+namespace toml
+{
+
+template<typename T>
+struct into;
+// {
+//     static toml::value into_toml(const T& user_defined_type)
+//     {
+//         // User-defined conversions ...
+//     }
+// };
+
+} // toml
+#endif // TOML11_INTO_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/lexer.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,294 @@
+//     Copyright Toru Niina 2017.
+// Distributed under the MIT License.
+#ifndef TOML11_LEXER_HPP
+#define TOML11_LEXER_HPP
+#include <istream>
+#include <sstream>
+#include <stdexcept>
+
+#include "combinator.hpp"
+
+namespace toml
+{
+namespace detail
+{
+
+// these scans contents from current location in a container of char
+// and extract a region that matches their own pattern.
+// to see the implementation of each component, see combinator.hpp.
+
+using lex_wschar  = either<character<' '>, character<'\t'>>;
+using lex_ws      = repeat<lex_wschar, at_least<1>>;
+using lex_newline = either<character<'\n'>,
+                           sequence<character<'\r'>, character<'\n'>>>;
+using lex_lower   = in_range<'a', 'z'>;
+using lex_upper   = in_range<'A', 'Z'>;
+using lex_alpha   = either<lex_lower, lex_upper>;
+using lex_digit   = in_range<'0', '9'>;
+using lex_nonzero = in_range<'1', '9'>;
+using lex_oct_dig = in_range<'0', '7'>;
+using lex_bin_dig = in_range<'0', '1'>;
+using lex_hex_dig = either<lex_digit, in_range<'A', 'F'>, in_range<'a', 'f'>>;
+
+using lex_hex_prefix = sequence<character<'0'>, character<'x'>>;
+using lex_oct_prefix = sequence<character<'0'>, character<'o'>>;
+using lex_bin_prefix = sequence<character<'0'>, character<'b'>>;
+using lex_underscore = character<'_'>;
+using lex_plus       = character<'+'>;
+using lex_minus      = character<'-'>;
+using lex_sign       = either<lex_plus, lex_minus>;
+
+// digit | nonzero 1*(digit | _ digit)
+using lex_unsigned_dec_int = either<sequence<lex_nonzero, repeat<
+    either<lex_digit, sequence<lex_underscore, lex_digit>>, at_least<1>>>,
+    lex_digit>;
+// (+|-)? unsigned_dec_int
+using lex_dec_int = sequence<maybe<lex_sign>, lex_unsigned_dec_int>;
+
+// hex_prefix hex_dig *(hex_dig | _ hex_dig)
+using lex_hex_int = sequence<lex_hex_prefix, sequence<lex_hex_dig, repeat<
+    either<lex_hex_dig, sequence<lex_underscore, lex_hex_dig>>, unlimited>>>;
+// oct_prefix oct_dig *(oct_dig | _ oct_dig)
+using lex_oct_int = sequence<lex_oct_prefix, sequence<lex_oct_dig, repeat<
+    either<lex_oct_dig, sequence<lex_underscore, lex_oct_dig>>, unlimited>>>;
+// bin_prefix bin_dig *(bin_dig | _ bin_dig)
+using lex_bin_int = sequence<lex_bin_prefix, sequence<lex_bin_dig, repeat<
+    either<lex_bin_dig, sequence<lex_underscore, lex_bin_dig>>, unlimited>>>;
+
+// (dec_int | hex_int | oct_int | bin_int)
+using lex_integer = either<lex_bin_int, lex_oct_int, lex_hex_int, lex_dec_int>;
+
+// ===========================================================================
+
+using lex_inf = sequence<character<'i'>, character<'n'>, character<'f'>>;
+using lex_nan = sequence<character<'n'>, character<'a'>, character<'n'>>;
+using lex_special_float = sequence<maybe<lex_sign>, either<lex_inf, lex_nan>>;
+
+using lex_zero_prefixable_int = sequence<lex_digit, repeat<either<lex_digit,
+    sequence<lex_underscore, lex_digit>>, unlimited>>;
+
+using lex_fractional_part = sequence<character<'.'>, lex_zero_prefixable_int>;
+
+using lex_exponent_part   = sequence<either<character<'e'>, character<'E'>>,
+        maybe<lex_sign>, lex_zero_prefixable_int>;
+
+using lex_float = either<lex_special_float,
+      sequence<lex_dec_int, either<lex_exponent_part,
+      sequence<lex_fractional_part, maybe<lex_exponent_part>>>>>;
+
+// ===========================================================================
+
+using lex_true = sequence<character<'t'>, character<'r'>,
+                          character<'u'>, character<'e'>>;
+using lex_false = sequence<character<'f'>, character<'a'>, character<'l'>,
+                           character<'s'>, character<'e'>>;
+using lex_boolean = either<lex_true, lex_false>;
+
+// ===========================================================================
+
+using lex_date_fullyear = repeat<lex_digit, exactly<4>>;
+using lex_date_month    = repeat<lex_digit, exactly<2>>;
+using lex_date_mday     = repeat<lex_digit, exactly<2>>;
+using lex_time_delim    = either<character<'T'>, character<'t'>, character<' '>>;
+using lex_time_hour     = repeat<lex_digit, exactly<2>>;
+using lex_time_minute   = repeat<lex_digit, exactly<2>>;
+using lex_time_second   = repeat<lex_digit, exactly<2>>;
+using lex_time_secfrac  = sequence<character<'.'>,
+                                   repeat<lex_digit, at_least<1>>>;
+
+using lex_time_numoffset = sequence<either<character<'+'>, character<'-'>>,
+                                    sequence<lex_time_hour, character<':'>,
+                                             lex_time_minute>>;
+using lex_time_offset = either<character<'Z'>, character<'z'>,
+                               lex_time_numoffset>;
+
+using lex_partial_time = sequence<lex_time_hour,   character<':'>,
+                                  lex_time_minute, character<':'>,
+                                  lex_time_second, maybe<lex_time_secfrac>>;
+using lex_full_date    = sequence<lex_date_fullyear, character<'-'>,
+                                  lex_date_month,    character<'-'>,
+                                  lex_date_mday>;
+using lex_full_time    = sequence<lex_partial_time, lex_time_offset>;
+
+using lex_offset_date_time = sequence<lex_full_date, lex_time_delim, lex_full_time>;
+using lex_local_date_time  = sequence<lex_full_date, lex_time_delim, lex_partial_time>;
+using lex_local_date       = lex_full_date;
+using lex_local_time       = lex_partial_time;
+
+// ===========================================================================
+
+using lex_quotation_mark  = character<'"'>;
+using lex_basic_unescaped = exclude<either<in_range<0x00, 0x08>, // 0x09 (tab) is allowed
+                                           in_range<0x0A, 0x1F>,
+                                           character<0x22>, character<0x5C>,
+                                           character<0x7F>>>;
+
+using lex_escape          = character<'\\'>;
+using lex_escape_unicode_short = sequence<character<'u'>,
+                                          repeat<lex_hex_dig, exactly<4>>>;
+using lex_escape_unicode_long  = sequence<character<'U'>,
+                                          repeat<lex_hex_dig, exactly<8>>>;
+using lex_escape_seq_char = either<character<'"'>, character<'\\'>,
+                                   character<'b'>, character<'f'>,
+                                   character<'n'>, character<'r'>,
+                                   character<'t'>,
+#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
+                                   character<'e'>, // ESC (0x1B)
+#endif
+                                   lex_escape_unicode_short,
+                                   lex_escape_unicode_long
+                                   >;
+using lex_escaped      = sequence<lex_escape, lex_escape_seq_char>;
+using lex_basic_char   = either<lex_basic_unescaped, lex_escaped>;
+using lex_basic_string = sequence<lex_quotation_mark,
+                                  repeat<lex_basic_char, unlimited>,
+                                  lex_quotation_mark>;
+
+// After toml post-v0.5.0, it is explicitly clarified how quotes in ml-strings
+// are allowed to be used.
+// After this, the following strings are *explicitly* allowed.
+// - One or two `"`s in a multi-line basic string is allowed wherever it is.
+// - Three consecutive `"`s in a multi-line basic string is considered as a delimiter.
+// - One or two `"`s can appear just before or after the delimiter.
+// ```toml
+// str4 = """Here are two quotation marks: "". Simple enough."""
+// str5 = """Here are three quotation marks: ""\"."""
+// str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\"."""
+// str7 = """"This," she said, "is just a pointless statement.""""
+// ```
+// In the current implementation (v3.3.0), it is difficult to parse `str7` in
+// the above example. It is difficult to recognize `"` at the end of string body
+// collectly. It will be misunderstood as a `"""` delimiter and an additional,
+// invalid `"`. Like this:
+// ```console
+//   what():  [error] toml::parse_table: invalid line format
+//  --> hoge.toml
+//     |
+//  13 | str7 = """"This," she said, "is just a pointless statement.""""
+//     |                                                               ^- expected newline, but got '"'.
+// ```
+// As a quick workaround for this problem, `lex_ml_basic_string_delim` was
+// split into two, `lex_ml_basic_string_open` and `lex_ml_basic_string_close`.
+// `lex_ml_basic_string_open` allows only `"""`. `_close` allows 3-5 `"`s.
+// In parse_ml_basic_string() function, the trailing `"`s will be attached to
+// the string body.
+//
+using lex_ml_basic_string_delim = repeat<lex_quotation_mark, exactly<3>>;
+using lex_ml_basic_string_open  = lex_ml_basic_string_delim;
+using lex_ml_basic_string_close = sequence<
+        repeat<lex_quotation_mark, exactly<3>>,
+        maybe<lex_quotation_mark>, maybe<lex_quotation_mark>
+    >;
+
+using lex_ml_basic_unescaped    = exclude<either<in_range<0x00, 0x08>, // 0x09 is tab
+                                                 in_range<0x0A, 0x1F>,
+                                                 character<0x5C>, // backslash
+                                                 character<0x7F>, // DEL
+                                                 lex_ml_basic_string_delim>>;
+
+using lex_ml_basic_escaped_newline = sequence<
+        lex_escape, maybe<lex_ws>, lex_newline,
+        repeat<either<lex_ws, lex_newline>, unlimited>>;
+
+using lex_ml_basic_char = either<lex_ml_basic_unescaped, lex_escaped>;
+using lex_ml_basic_body = repeat<either<lex_ml_basic_char, lex_newline,
+                                        lex_ml_basic_escaped_newline>,
+                                 unlimited>;
+using lex_ml_basic_string = sequence<lex_ml_basic_string_open,
+                                     lex_ml_basic_body,
+                                     lex_ml_basic_string_close>;
+
+using lex_literal_char = exclude<either<in_range<0x00, 0x08>, in_range<0x0A, 0x1F>,
+                                        character<0x7F>, character<0x27>>>;
+using lex_apostrophe = character<'\''>;
+using lex_literal_string = sequence<lex_apostrophe,
+                                    repeat<lex_literal_char, unlimited>,
+                                    lex_apostrophe>;
+
+// the same reason as above.
+using lex_ml_literal_string_delim = repeat<lex_apostrophe, exactly<3>>;
+using lex_ml_literal_string_open  = lex_ml_literal_string_delim;
+using lex_ml_literal_string_close = sequence<
+        repeat<lex_apostrophe, exactly<3>>,
+        maybe<lex_apostrophe>, maybe<lex_apostrophe>
+    >;
+
+using lex_ml_literal_char = exclude<either<in_range<0x00, 0x08>,
+                                           in_range<0x0A, 0x1F>,
+                                           character<0x7F>,
+                                           lex_ml_literal_string_delim>>;
+using lex_ml_literal_body = repeat<either<lex_ml_literal_char, lex_newline>,
+                                   unlimited>;
+using lex_ml_literal_string = sequence<lex_ml_literal_string_open,
+                                       lex_ml_literal_body,
+                                       lex_ml_literal_string_close>;
+
+using lex_string = either<lex_ml_basic_string,   lex_basic_string,
+                          lex_ml_literal_string, lex_literal_string>;
+
+// ===========================================================================
+using lex_dot_sep = sequence<maybe<lex_ws>, character<'.'>, maybe<lex_ws>>;
+
+using lex_unquoted_key = repeat<either<lex_alpha, lex_digit,
+                                       character<'-'>, character<'_'>>,
+                                at_least<1>>;
+using lex_quoted_key = either<lex_basic_string, lex_literal_string>;
+using lex_simple_key = either<lex_unquoted_key, lex_quoted_key>;
+using lex_dotted_key = sequence<lex_simple_key,
+                                repeat<sequence<lex_dot_sep, lex_simple_key>,
+                                       at_least<1>
+                                       >
+                                >;
+using lex_key = either<lex_dotted_key, lex_simple_key>;
+
+using lex_keyval_sep = sequence<maybe<lex_ws>,
+                                character<'='>,
+                                maybe<lex_ws>>;
+
+using lex_std_table_open  = character<'['>;
+using lex_std_table_close = character<']'>;
+using lex_std_table       = sequence<lex_std_table_open,
+                                     maybe<lex_ws>,
+                                     lex_key,
+                                     maybe<lex_ws>,
+                                     lex_std_table_close>;
+
+using lex_array_table_open  = sequence<lex_std_table_open,  lex_std_table_open>;
+using lex_array_table_close = sequence<lex_std_table_close, lex_std_table_close>;
+using lex_array_table       = sequence<lex_array_table_open,
+                                       maybe<lex_ws>,
+                                       lex_key,
+                                       maybe<lex_ws>,
+                                       lex_array_table_close>;
+
+using lex_utf8_1byte = in_range<0x00, 0x7F>;
+using lex_utf8_2byte = sequence<
+        in_range<'\xC2', '\xDF'>,
+        in_range<'\x80', '\xBF'>
+    >;
+using lex_utf8_3byte = sequence<either<
+        sequence<character<'\xE0'>, in_range<'\xA0', '\xBF'>>,
+        sequence<in_range<'\xE1', '\xEC'>, in_range<'\x80', '\xBF'>>,
+        sequence<character<'\xED'>, in_range<'\x80', '\x9F'>>,
+        sequence<in_range<'\xEE', '\xEF'>, in_range<'\x80', '\xBF'>>
+    >, in_range<'\x80', '\xBF'>>;
+using lex_utf8_4byte = sequence<either<
+        sequence<character<'\xF0'>, in_range<'\x90', '\xBF'>>,
+        sequence<in_range<'\xF1', '\xF3'>, in_range<'\x80', '\xBF'>>,
+        sequence<character<'\xF4'>, in_range<'\x80', '\x8F'>>
+    >, in_range<'\x80', '\xBF'>, in_range<'\x80', '\xBF'>>;
+using lex_utf8_code = either<
+        lex_utf8_1byte,
+        lex_utf8_2byte,
+        lex_utf8_3byte,
+        lex_utf8_4byte
+    >;
+
+using lex_comment_start_symbol = character<'#'>;
+using lex_non_eol_ascii = either<character<0x09>, in_range<0x20, 0x7E>>;
+using lex_comment = sequence<lex_comment_start_symbol, repeat<either<
+    lex_non_eol_ascii, lex_utf8_2byte, lex_utf8_3byte, lex_utf8_4byte>, unlimited>>;
+
+} // detail
+} // toml
+#endif // TOML_LEXER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/literal.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,113 @@
+//     Copyright Toru Niina 2019.
+// Distributed under the MIT License.
+#ifndef TOML11_LITERAL_HPP
+#define TOML11_LITERAL_HPP
+#include "parser.hpp"
+
+namespace toml
+{
+inline namespace literals
+{
+inline namespace toml_literals
+{
+
+// implementation
+inline ::toml::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
+literal_internal_impl(::toml::detail::location loc)
+{
+    using value_type = ::toml::basic_value<
+        TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>;
+    // if there are some comments or empty lines, skip them.
+    using skip_line = ::toml::detail::repeat<toml::detail::sequence<
+            ::toml::detail::maybe<::toml::detail::lex_ws>,
+            ::toml::detail::maybe<::toml::detail::lex_comment>,
+            ::toml::detail::lex_newline
+        >, ::toml::detail::at_least<1>>;
+    skip_line::invoke(loc);
+
+    // if there are some whitespaces before a value, skip them.
+    using skip_ws = ::toml::detail::repeat<
+        ::toml::detail::lex_ws, ::toml::detail::at_least<1>>;
+    skip_ws::invoke(loc);
+
+    // to distinguish arrays and tables, first check it is a table or not.
+    //
+    // "[1,2,3]"_toml;   // this is an array
+    // "[table]"_toml;   // a table that has an empty table named "table" inside.
+    // "[[1,2,3]]"_toml; // this is an array of arrays
+    // "[[table]]"_toml; // this is a table that has an array of tables inside.
+    //
+    // "[[1]]"_toml;     // this can be both... (currently it becomes a table)
+    // "1 = [{}]"_toml;  // this is a table that has an array of table named 1.
+    // "[[1,]]"_toml;    // this is an array of arrays.
+    // "[[1],]"_toml;    // this also.
+
+    const auto the_front = loc.iter();
+
+    const bool is_table_key = ::toml::detail::lex_std_table::invoke(loc);
+    loc.reset(the_front);
+
+    const bool is_aots_key  = ::toml::detail::lex_array_table::invoke(loc);
+    loc.reset(the_front);
+
+    // If it is neither a table-key or a array-of-table-key, it may be a value.
+    if(!is_table_key && !is_aots_key)
+    {
+        if(auto data = ::toml::detail::parse_value<value_type>(loc, 0))
+        {
+            return data.unwrap();
+        }
+    }
+
+    // Note that still it can be a table, because the literal might be something
+    // like the following.
+    // ```cpp
+    // R"( // c++11 raw string literals
+    //   key = "value"
+    //   int = 42
+    // )"_toml;
+    // ```
+    // It is a valid toml file.
+    // It should be parsed as if we parse a file with this content.
+
+    if(auto data = ::toml::detail::parse_toml_file<value_type>(loc))
+    {
+        return data.unwrap();
+    }
+    else // none of them.
+    {
+        throw ::toml::syntax_error(data.unwrap_err(), source_location(loc));
+    }
+
+}
+
+inline ::toml::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
+operator"" _toml(const char* str, std::size_t len)
+{
+    ::toml::detail::location loc(
+            std::string("TOML literal encoded in a C++ code"),
+            std::vector<char>(str, str + len));
+    // literal length does not include the null character at the end.
+    return literal_internal_impl(std::move(loc));
+}
+
+// value of __cplusplus in C++2a/20 mode is not fixed yet along compilers.
+// So here we use the feature test macro for `char8_t` itself.
+#if defined(__cpp_char8_t) && __cpp_char8_t >= 201811L
+// value of u8"" literal has been changed from char to char8_t and char8_t is
+// NOT compatible to char
+inline ::toml::basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>
+operator"" _toml(const char8_t* str, std::size_t len)
+{
+    ::toml::detail::location loc(
+            std::string("TOML literal encoded in a C++ code"),
+            std::vector<char>(reinterpret_cast<const char*>(str),
+                              reinterpret_cast<const char*>(str) + len));
+    return literal_internal_impl(std::move(loc));
+}
+#endif
+
+} // toml_literals
+} // literals
+} // toml
+#endif//TOML11_LITERAL_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/macros.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,121 @@
+#ifndef TOML11_MACROS_HPP
+#define TOML11_MACROS_HPP
+
+#define TOML11_STRINGIZE_AUX(x) #x
+#define TOML11_STRINGIZE(x)     TOML11_STRINGIZE_AUX(x)
+
+#define TOML11_CONCATENATE_AUX(x, y) x##y
+#define TOML11_CONCATENATE(x, y)     TOML11_CONCATENATE_AUX(x, y)
+
+// ============================================================================
+// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE
+
+#ifndef TOML11_WITHOUT_DEFINE_NON_INTRUSIVE
+
+// ----------------------------------------------------------------------------
+// TOML11_ARGS_SIZE
+
+#define TOML11_INDEX_RSEQ() \
+    32, 31, 30, 29, 28, 27, 26, 25, 24, 23, 22, 21, 20, 19, 18, 17, \
+    16, 15, 14, 13, 12, 11, 10,  9,  8,  7,  6,  5,  4,  3,  2,  1, 0
+#define TOML11_ARGS_SIZE_IMPL(\
+    ARG1,  ARG2,  ARG3,  ARG4,  ARG5,  ARG6,  ARG7,  ARG8,  ARG9,  ARG10, \
+    ARG11, ARG12, ARG13, ARG14, ARG15, ARG16, ARG17, ARG18, ARG19, ARG20, \
+    ARG21, ARG22, ARG23, ARG24, ARG25, ARG26, ARG27, ARG28, ARG29, ARG30, \
+    ARG31, ARG32, N, ...) N
+#define TOML11_ARGS_SIZE_AUX(...) TOML11_ARGS_SIZE_IMPL(__VA_ARGS__)
+#define TOML11_ARGS_SIZE(...) TOML11_ARGS_SIZE_AUX(__VA_ARGS__, TOML11_INDEX_RSEQ())
+
+// ----------------------------------------------------------------------------
+// TOML11_FOR_EACH_VA_ARGS
+
+#define TOML11_FOR_EACH_VA_ARGS_AUX_1( FUNCTOR, ARG1     ) FUNCTOR(ARG1)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_2( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_1( FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_3( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_2( FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_4( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_3( FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_5( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_4( FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_6( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_5( FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_7( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_6( FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_8( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_7( FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_9( FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_8( FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_10(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_9( FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_11(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_10(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_12(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_11(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_13(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_12(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_14(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_13(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_15(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_14(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_16(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_15(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_17(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_16(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_18(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_17(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_19(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_18(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_20(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_19(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_21(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_20(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_22(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_21(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_23(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_22(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_24(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_23(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_25(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_24(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_26(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_25(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_27(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_26(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_28(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_27(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_29(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_28(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_30(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_29(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_31(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_30(FUNCTOR, __VA_ARGS__)
+#define TOML11_FOR_EACH_VA_ARGS_AUX_32(FUNCTOR, ARG1, ...) FUNCTOR(ARG1) TOML11_FOR_EACH_VA_ARGS_AUX_31(FUNCTOR, __VA_ARGS__)
+
+#define TOML11_FOR_EACH_VA_ARGS(FUNCTOR, ...)\
+    TOML11_CONCATENATE(TOML11_FOR_EACH_VA_ARGS_AUX_, TOML11_ARGS_SIZE(__VA_ARGS__))(FUNCTOR, __VA_ARGS__)
+
+// ----------------------------------------------------------------------------
+// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE
+
+// use it in the following way.
+// ```cpp
+// namespace foo
+// {
+// struct Foo
+// {
+//     std::string s;
+//     double      d;
+//     int         i;
+// };
+// } // foo
+//
+// TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(foo::Foo, s, d, i)
+// ```
+// And then you can use `toml::find<foo::Foo>(file, "foo");`
+//
+#define TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE(VAR_NAME)\
+    obj.VAR_NAME = toml::find<decltype(obj.VAR_NAME)>(v, TOML11_STRINGIZE(VAR_NAME));
+
+#define TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE(VAR_NAME)\
+    v[TOML11_STRINGIZE(VAR_NAME)] = obj.VAR_NAME;
+
+#define TOML11_DEFINE_CONVERSION_NON_INTRUSIVE(NAME, ...)\
+    namespace toml {                                                                     \
+    template<>                                                                           \
+    struct from<NAME>                                                                    \
+    {                                                                                    \
+        template<typename C, template<typename ...> class T,                             \
+                 template<typename ...> class A>                                         \
+        static NAME from_toml(const basic_value<C, T, A>& v)                             \
+        {                                                                                \
+            NAME obj;                                                                    \
+            TOML11_FOR_EACH_VA_ARGS(TOML11_FIND_MEMBER_VARIABLE_FROM_VALUE, __VA_ARGS__) \
+            return obj;                                                                  \
+        }                                                                                \
+    };                                                                                   \
+    template<>                                                                           \
+    struct into<NAME>                                                                    \
+    {                                                                                    \
+        static value into_toml(const NAME& obj)                                          \
+        {                                                                                \
+            ::toml::value v = ::toml::table{};                                           \
+            TOML11_FOR_EACH_VA_ARGS(TOML11_ASSIGN_MEMBER_VARIABLE_TO_VALUE, __VA_ARGS__) \
+            return v;                                                                    \
+        }                                                                                \
+    };                                                                                   \
+    } /* toml */
+
+#endif// TOML11_WITHOUT_DEFINE_NON_INTRUSIVE
+
+#endif// TOML11_MACROS_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/parser.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,2611 @@
+//     Copyright Toru Niina 2017.
+// Distributed under the MIT License.
+#ifndef TOML11_PARSER_HPP
+#define TOML11_PARSER_HPP
+#include <cstring>
+#include <fstream>
+#include <sstream>
+
+#include "combinator.hpp"
+#include "lexer.hpp"
+#include "macros.hpp"
+#include "region.hpp"
+#include "result.hpp"
+#include "types.hpp"
+#include "value.hpp"
+
+#ifndef TOML11_DISABLE_STD_FILESYSTEM
+#ifdef __cpp_lib_filesystem
+#if __has_include(<filesystem>)
+#define TOML11_HAS_STD_FILESYSTEM
+#include <filesystem>
+#endif // has_include(<string_view>)
+#endif // __cpp_lib_filesystem
+#endif // TOML11_DISABLE_STD_FILESYSTEM
+
+// the previous commit works with 500+ recursions. so it may be too small.
+// but in most cases, i think we don't need such a deep recursion of
+// arrays or inline-tables.
+#define TOML11_VALUE_RECURSION_LIMIT 64
+
+namespace toml
+{
+namespace detail
+{
+
+inline result<std::pair<boolean, region>, std::string>
+parse_boolean(location& loc)
+{
+    const auto first = loc.iter();
+    if(const auto token = lex_boolean::invoke(loc))
+    {
+        const auto reg = token.unwrap();
+        if     (reg.str() == "true")  {return ok(std::make_pair(true,  reg));}
+        else if(reg.str() == "false") {return ok(std::make_pair(false, reg));}
+        else // internal error.
+        {
+            throw internal_error(format_underline(
+                "toml::parse_boolean: internal error",
+                {{source_location(reg), "invalid token"}}),
+                source_location(reg));
+        }
+    }
+    loc.reset(first); //rollback
+    return err(format_underline("toml::parse_boolean: ",
+               {{source_location(loc), "the next token is not a boolean"}}));
+}
+
+inline result<std::pair<integer, region>, std::string>
+parse_binary_integer(location& loc)
+{
+    const auto first = loc.iter();
+    if(const auto token = lex_bin_int::invoke(loc))
+    {
+        auto str = token.unwrap().str();
+        assert(str.size() > 2); // minimum -> 0b1
+        assert(str.at(0) == '0' && str.at(1) == 'b');
+
+        // skip all the zeros and `_` locating at the MSB
+        str.erase(str.begin(), std::find_if(
+                str.begin() + 2, // to skip prefix `0b`
+                str.end(),
+                [](const char c) { return c == '1'; })
+            );
+        assert(str.empty() || str.front() == '1');
+
+        // since toml11 uses int64_t, 64bit (unsigned) input cannot be read.
+        const auto max_length = 63 + std::count(str.begin(), str.end(), '_');
+        if(static_cast<std::string::size_type>(max_length) < str.size())
+        {
+            loc.reset(first);
+            return err(format_underline("toml::parse_binary_integer: "
+                "only signed 64bit integer is available",
+               {{source_location(loc), "too large input (> int64_t)"}}));
+        }
+
+        integer retval(0), base(1);
+        for(auto i(str.rbegin()), e(str.rend()); i!=e; ++i)
+        {
+            assert(base != 0); // means overflow, checked in the above code
+            if(*i == '1')
+            {
+                retval += base;
+                if( (std::numeric_limits<integer>::max)() / 2 < base )
+                {
+                    base = 0;
+                }
+                base *= 2;
+            }
+            else if(*i == '0')
+            {
+                if( (std::numeric_limits<integer>::max)() / 2 < base )
+                {
+                    base = 0;
+                }
+                base *= 2;
+            }
+            else if(*i == '_')
+            {
+                // do nothing.
+            }
+            else // should be detected by lex_bin_int. [[unlikely]]
+            {
+                throw internal_error(format_underline(
+                    "toml::parse_binary_integer: internal error",
+                    {{source_location(token.unwrap()), "invalid token"}}),
+                    source_location(loc));
+            }
+        }
+        return ok(std::make_pair(retval, token.unwrap()));
+    }
+    loc.reset(first);
+    return err(format_underline("toml::parse_binary_integer:",
+               {{source_location(loc), "the next token is not an integer"}}));
+}
+
+inline result<std::pair<integer, region>, std::string>
+parse_octal_integer(location& loc)
+{
+    const auto first = loc.iter();
+    if(const auto token = lex_oct_int::invoke(loc))
+    {
+        auto str = token.unwrap().str();
+        str.erase(std::remove(str.begin(), str.end(), '_'), str.end());
+        str.erase(str.begin()); str.erase(str.begin()); // remove `0o` prefix
+
+        std::istringstream iss(str);
+        integer retval(0);
+        iss >> std::oct >> retval;
+        if(iss.fail())
+        {
+            // `istream` sets `failbit` if internally-called `std::num_get::get`
+            // fails.
+            // `std::num_get::get` calls `std::strtoll` if the argument type is
+            // signed.
+            // `std::strtoll` fails if
+            //  - the value is out_of_range or
+            //  - no conversion is possible.
+            // since we already checked that the string is valid octal integer,
+            // so the error reason is out_of_range.
+            loc.reset(first);
+            return err(format_underline("toml::parse_octal_integer:",
+                       {{source_location(loc), "out of range"}}));
+        }
+        return ok(std::make_pair(retval, token.unwrap()));
+    }
+    loc.reset(first);
+    return err(format_underline("toml::parse_octal_integer:",
+               {{source_location(loc), "the next token is not an integer"}}));
+}
+
+inline result<std::pair<integer, region>, std::string>
+parse_hexadecimal_integer(location& loc)
+{
+    const auto first = loc.iter();
+    if(const auto token = lex_hex_int::invoke(loc))
+    {
+        auto str = token.unwrap().str();
+        str.erase(std::remove(str.begin(), str.end(), '_'), str.end());
+        str.erase(str.begin()); str.erase(str.begin()); // remove `0x` prefix
+
+        std::istringstream iss(str);
+        integer retval(0);
+        iss >> std::hex >> retval;
+        if(iss.fail())
+        {
+            // see parse_octal_integer for detail of this error message.
+            loc.reset(first);
+            return err(format_underline("toml::parse_hexadecimal_integer:",
+                       {{source_location(loc), "out of range"}}));
+        }
+        return ok(std::make_pair(retval, token.unwrap()));
+    }
+    loc.reset(first);
+    return err(format_underline("toml::parse_hexadecimal_integer",
+               {{source_location(loc), "the next token is not an integer"}}));
+}
+
+inline result<std::pair<integer, region>, std::string>
+parse_integer(location& loc)
+{
+    const auto first = loc.iter();
+    if(first != loc.end() && *first == '0')
+    {
+        const auto second = std::next(first);
+        if(second == loc.end()) // the token is just zero.
+        {
+            loc.advance();
+            return ok(std::make_pair(0, region(loc, first, second)));
+        }
+
+        if(*second == 'b') {return parse_binary_integer     (loc);} // 0b1100
+        if(*second == 'o') {return parse_octal_integer      (loc);} // 0o775
+        if(*second == 'x') {return parse_hexadecimal_integer(loc);} // 0xC0FFEE
+
+        if(std::isdigit(*second))
+        {
+            return err(format_underline("toml::parse_integer: "
+                "leading zero in an Integer is not allowed.",
+                {{source_location(loc), "leading zero"}}));
+        }
+        else if(std::isalpha(*second))
+        {
+             return err(format_underline("toml::parse_integer: "
+                "unknown integer prefix appeared.",
+                {{source_location(loc), "none of 0x, 0o, 0b"}}));
+        }
+    }
+
+    if(const auto token = lex_dec_int::invoke(loc))
+    {
+        auto str = token.unwrap().str();
+        str.erase(std::remove(str.begin(), str.end(), '_'), str.end());
+
+        std::istringstream iss(str);
+        integer retval(0);
+        iss >> retval;
+        if(iss.fail())
+        {
+            // see parse_octal_integer for detail of this error message.
+            loc.reset(first);
+            return err(format_underline("toml::parse_integer:",
+                       {{source_location(loc), "out of range"}}));
+        }
+        return ok(std::make_pair(retval, token.unwrap()));
+    }
+    loc.reset(first);
+    return err(format_underline("toml::parse_integer: ",
+               {{source_location(loc), "the next token is not an integer"}}));
+}
+
+inline result<std::pair<floating, region>, std::string>
+parse_floating(location& loc)
+{
+    const auto first = loc.iter();
+    if(const auto token = lex_float::invoke(loc))
+    {
+        auto str = token.unwrap().str();
+        if(str == "inf" || str == "+inf")
+        {
+            if(std::numeric_limits<floating>::has_infinity)
+            {
+                return ok(std::make_pair(
+                    std::numeric_limits<floating>::infinity(), token.unwrap()));
+            }
+            else
+            {
+                throw std::domain_error("toml::parse_floating: inf value found"
+                    " but the current environment does not support inf. Please"
+                    " make sure that the floating-point implementation conforms"
+                    " IEEE 754/ISO 60559 international standard.");
+            }
+        }
+        else if(str == "-inf")
+        {
+            if(std::numeric_limits<floating>::has_infinity)
+            {
+                return ok(std::make_pair(
+                    -std::numeric_limits<floating>::infinity(), token.unwrap()));
+            }
+            else
+            {
+                throw std::domain_error("toml::parse_floating: inf value found"
+                    " but the current environment does not support inf. Please"
+                    " make sure that the floating-point implementation conforms"
+                    " IEEE 754/ISO 60559 international standard.");
+            }
+        }
+        else if(str == "nan" || str == "+nan")
+        {
+            if(std::numeric_limits<floating>::has_quiet_NaN)
+            {
+                return ok(std::make_pair(
+                    std::numeric_limits<floating>::quiet_NaN(), token.unwrap()));
+            }
+            else if(std::numeric_limits<floating>::has_signaling_NaN)
+            {
+                return ok(std::make_pair(
+                    std::numeric_limits<floating>::signaling_NaN(), token.unwrap()));
+            }
+            else
+            {
+                throw std::domain_error("toml::parse_floating: NaN value found"
+                    " but the current environment does not support NaN. Please"
+                    " make sure that the floating-point implementation conforms"
+                    " IEEE 754/ISO 60559 international standard.");
+            }
+        }
+        else if(str == "-nan")
+        {
+            if(std::numeric_limits<floating>::has_quiet_NaN)
+            {
+                return ok(std::make_pair(
+                    -std::numeric_limits<floating>::quiet_NaN(), token.unwrap()));
+            }
+            else if(std::numeric_limits<floating>::has_signaling_NaN)
+            {
+                return ok(std::make_pair(
+                    -std::numeric_limits<floating>::signaling_NaN(), token.unwrap()));
+            }
+            else
+            {
+                throw std::domain_error("toml::parse_floating: NaN value found"
+                    " but the current environment does not support NaN. Please"
+                    " make sure that the floating-point implementation conforms"
+                    " IEEE 754/ISO 60559 international standard.");
+            }
+        }
+        str.erase(std::remove(str.begin(), str.end(), '_'), str.end());
+        std::istringstream iss(str);
+        floating v(0.0);
+        iss >> v;
+        if(iss.fail())
+        {
+            // see parse_octal_integer for detail of this error message.
+            loc.reset(first);
+            return err(format_underline("toml::parse_floating:",
+                       {{source_location(loc), "out of range"}}));
+        }
+        return ok(std::make_pair(v, token.unwrap()));
+    }
+    loc.reset(first);
+    return err(format_underline("toml::parse_floating: ",
+               {{source_location(loc), "the next token is not a float"}}));
+}
+
+inline std::string read_utf8_codepoint(const region& reg, const location& loc)
+{
+    const auto str = reg.str().substr(1);
+    std::uint_least32_t codepoint;
+    std::istringstream iss(str);
+    iss >> std::hex >> codepoint;
+
+    const auto to_char = [](const std::uint_least32_t i) noexcept -> char {
+        const auto uc = static_cast<unsigned char>(i);
+        return *reinterpret_cast<const char*>(std::addressof(uc));
+    };
+
+    std::string character;
+    if(codepoint < 0x80) // U+0000 ... U+0079 ; just an ASCII.
+    {
+        character += static_cast<char>(codepoint);
+    }
+    else if(codepoint < 0x800) //U+0080 ... U+07FF
+    {
+        // 110yyyyx 10xxxxxx; 0x3f == 0b0011'1111
+        character += to_char(0xC0| codepoint >> 6);
+        character += to_char(0x80|(codepoint & 0x3F));
+    }
+    else if(codepoint < 0x10000) // U+0800...U+FFFF
+    {
+        if(0xD800 <= codepoint && codepoint <= 0xDFFF)
+        {
+            throw syntax_error(format_underline(
+                "toml::read_utf8_codepoint: codepoints in the range "
+                "[0xD800, 0xDFFF] are not valid UTF-8.", {{
+                    source_location(loc), "not a valid UTF-8 codepoint"
+                }}), source_location(loc));
+        }
+        assert(codepoint < 0xD800 || 0xDFFF < codepoint);
+        // 1110yyyy 10yxxxxx 10xxxxxx
+        character += to_char(0xE0| codepoint >> 12);
+        character += to_char(0x80|(codepoint >> 6 & 0x3F));
+        character += to_char(0x80|(codepoint      & 0x3F));
+    }
+    else if(codepoint < 0x110000) // U+010000 ... U+10FFFF
+    {
+        // 11110yyy 10yyxxxx 10xxxxxx 10xxxxxx
+        character += to_char(0xF0| codepoint >> 18);
+        character += to_char(0x80|(codepoint >> 12 & 0x3F));
+        character += to_char(0x80|(codepoint >> 6  & 0x3F));
+        character += to_char(0x80|(codepoint       & 0x3F));
+    }
+    else // out of UTF-8 region
+    {
+        throw syntax_error(format_underline("toml::read_utf8_codepoint:"
+            " input codepoint is too large.",
+            {{source_location(loc), "should be in [0x00..0x10FFFF]"}}),
+            source_location(loc));
+    }
+    return character;
+}
+
+inline result<std::string, std::string> parse_escape_sequence(location& loc)
+{
+    const auto first = loc.iter();
+    if(first == loc.end() || *first != '\\')
+    {
+        return err(format_underline("toml::parse_escape_sequence: ", {{
+            source_location(loc), "the next token is not a backslash \"\\\""}}));
+    }
+    loc.advance();
+    switch(*loc.iter())
+    {
+        case '\\':{loc.advance(); return ok(std::string("\\"));}
+        case '"' :{loc.advance(); return ok(std::string("\""));}
+        case 'b' :{loc.advance(); return ok(std::string("\b"));}
+        case 't' :{loc.advance(); return ok(std::string("\t"));}
+        case 'n' :{loc.advance(); return ok(std::string("\n"));}
+        case 'f' :{loc.advance(); return ok(std::string("\f"));}
+        case 'r' :{loc.advance(); return ok(std::string("\r"));}
+#ifdef TOML11_USE_UNRELEASED_TOML_FEATURES
+        case 'e' :{loc.advance(); return ok(std::string("\x1b"));} // ESC
+#endif
+        case 'u' :
+        {
+            if(const auto token = lex_escape_unicode_short::invoke(loc))
+            {
+                return ok(read_utf8_codepoint(token.unwrap(), loc));
+            }
+            else
+            {
+                return err(format_underline("parse_escape_sequence: "
+                           "invalid token found in UTF-8 codepoint uXXXX.",
+                           {{source_location(loc), "here"}}));
+            }
+        }
+        case 'U':
+        {
+            if(const auto token = lex_escape_unicode_long::invoke(loc))
+            {
+                return ok(read_utf8_codepoint(token.unwrap(), loc));
+            }
+            else
+            {
+                return err(format_underline("parse_escape_sequence: "
+                           "invalid token found in UTF-8 codepoint Uxxxxxxxx",
+                           {{source_location(loc), "here"}}));
+            }
+        }
+    }
+
+    const auto msg = format_underline("parse_escape_sequence: "
+           "unknown escape sequence appeared.", {{source_location(loc),
+           "escape sequence is one of \\, \", b, t, n, f, r, uxxxx, Uxxxxxxxx"}},
+           /* Hints = */{"if you want to write backslash as just one backslash, "
+           "use literal string like: regex    = '<\\i\\c*\\s*>'"});
+    loc.reset(first);
+    return err(msg);
+}
+
+inline std::ptrdiff_t check_utf8_validity(const std::string& reg)
+{
+    location loc("tmp", reg);
+    const auto u8 = repeat<lex_utf8_code, unlimited>::invoke(loc);
+    if(!u8 || loc.iter() != loc.end())
+    {
+        const auto error_location = std::distance(loc.begin(), loc.iter());
+        assert(0 <= error_location);
+        return error_location;
+    }
+    return -1;
+}
+
+inline result<std::pair<toml::string, region>, std::string>
+parse_ml_basic_string(location& loc)
+{
+    const auto first = loc.iter();
+    if(const auto token = lex_ml_basic_string::invoke(loc))
+    {
+        auto inner_loc = loc;
+        inner_loc.reset(first);
+
+        std::string retval;
+        retval.reserve(token.unwrap().size());
+
+        auto delim = lex_ml_basic_string_open::invoke(inner_loc);
+        if(!delim)
+        {
+            throw internal_error(format_underline(
+                "parse_ml_basic_string: invalid token",
+                {{source_location(inner_loc), "should be \"\"\""}}),
+                source_location(inner_loc));
+        }
+        // immediate newline is ignored (if exists)
+        /* discard return value */ lex_newline::invoke(inner_loc);
+
+        delim = none();
+        while(!delim)
+        {
+            using lex_unescaped_seq = repeat<
+                either<lex_ml_basic_unescaped, lex_newline>, unlimited>;
+            if(auto unescaped = lex_unescaped_seq::invoke(inner_loc))
+            {
+                retval += unescaped.unwrap().str();
+            }
+            if(auto escaped = parse_escape_sequence(inner_loc))
+            {
+                retval += escaped.unwrap();
+            }
+            if(auto esc_nl = lex_ml_basic_escaped_newline::invoke(inner_loc))
+            {
+                // ignore newline after escape until next non-ws char
+            }
+            if(inner_loc.iter() == inner_loc.end())
+            {
+                throw internal_error(format_underline(
+                    "parse_ml_basic_string: unexpected end of region",
+                    {{source_location(inner_loc), "not sufficient token"}}),
+                    source_location(inner_loc));
+            }
+            delim = lex_ml_basic_string_close::invoke(inner_loc);
+        }
+        // `lex_ml_basic_string_close` allows 3 to 5 `"`s to allow 1 or 2 `"`s
+        // at just before the delimiter. Here, we need to attach `"`s at the
+        // end of the string body, if it exists.
+        // For detail, see the definition of `lex_ml_basic_string_close`.
+        assert(std::all_of(delim.unwrap().first(), delim.unwrap().last(),
+                           [](const char c) noexcept {return c == '\"';}));
+        switch(delim.unwrap().size())
+        {
+            case 3: {break;}
+            case 4: {retval += "\"";  break;}
+            case 5: {retval += "\"\""; break;}
+            default:
+            {
+                throw internal_error(format_underline(
+                    "parse_ml_basic_string: closing delimiter has invalid length",
+                    {{source_location(inner_loc), "end of this"}}),
+                    source_location(inner_loc));
+            }
+        }
+
+        const auto err_loc = check_utf8_validity(token.unwrap().str());
+        if(err_loc == -1)
+        {
+            return ok(std::make_pair(toml::string(retval), token.unwrap()));
+        }
+        else
+        {
+            inner_loc.reset(first);
+            inner_loc.advance(err_loc);
+            throw syntax_error(format_underline(
+                "parse_ml_basic_string: invalid utf8 sequence found",
+                {{source_location(inner_loc), "here"}}),
+                source_location(inner_loc));
+        }
+    }
+    else
+    {
+        loc.reset(first);
+        return err(format_underline("toml::parse_ml_basic_string: "
+                   "the next token is not a valid multiline string",
+                   {{source_location(loc), "here"}}));
+    }
+}
+
+inline result<std::pair<toml::string, region>, std::string>
+parse_basic_string(location& loc)
+{
+    const auto first = loc.iter();
+    if(const auto token = lex_basic_string::invoke(loc))
+    {
+        auto inner_loc = loc;
+        inner_loc.reset(first);
+
+        auto quot = lex_quotation_mark::invoke(inner_loc);
+        if(!quot)
+        {
+            throw internal_error(format_underline("parse_basic_string: "
+                "invalid token", {{source_location(inner_loc), "should be \""}}),
+                source_location(inner_loc));
+        }
+
+        std::string retval;
+        retval.reserve(token.unwrap().size());
+
+        quot = none();
+        while(!quot)
+        {
+            using lex_unescaped_seq = repeat<lex_basic_unescaped, unlimited>;
+            if(auto unescaped = lex_unescaped_seq::invoke(inner_loc))
+            {
+                retval += unescaped.unwrap().str();
+            }
+            if(auto escaped = parse_escape_sequence(inner_loc))
+            {
+                retval += escaped.unwrap();
+            }
+            if(inner_loc.iter() == inner_loc.end())
+            {
+                throw internal_error(format_underline(
+                    "parse_basic_string: unexpected end of region",
+                    {{source_location(inner_loc), "not sufficient token"}}),
+                    source_location(inner_loc));
+            }
+            quot = lex_quotation_mark::invoke(inner_loc);
+        }
+
+        const auto err_loc = check_utf8_validity(token.unwrap().str());
+        if(err_loc == -1)
+        {
+            return ok(std::make_pair(toml::string(retval), token.unwrap()));
+        }
+        else
+        {
+            inner_loc.reset(first);
+            inner_loc.advance(err_loc);
+            throw syntax_error(format_underline(
+                "parse_basic_string: invalid utf8 sequence found",
+                {{source_location(inner_loc), "here"}}),
+                source_location(inner_loc));
+        }
+    }
+    else
+    {
+        loc.reset(first); // rollback
+        return err(format_underline("toml::parse_basic_string: "
+                   "the next token is not a valid string",
+                   {{source_location(loc), "here"}}));
+    }
+}
+
+inline result<std::pair<toml::string, region>, std::string>
+parse_ml_literal_string(location& loc)
+{
+    const auto first = loc.iter();
+    if(const auto token = lex_ml_literal_string::invoke(loc))
+    {
+        auto inner_loc = loc;
+        inner_loc.reset(first);
+
+        const auto open = lex_ml_literal_string_open::invoke(inner_loc);
+        if(!open)
+        {
+            throw internal_error(format_underline(
+                "parse_ml_literal_string: invalid token",
+                {{source_location(inner_loc), "should be '''"}}),
+                source_location(inner_loc));
+        }
+        // immediate newline is ignored (if exists)
+        /* discard return value */ lex_newline::invoke(inner_loc);
+
+        const auto body = lex_ml_literal_body::invoke(inner_loc);
+
+        const auto close = lex_ml_literal_string_close::invoke(inner_loc);
+        if(!close)
+        {
+            throw internal_error(format_underline(
+                "parse_ml_literal_string: invalid token",
+                {{source_location(inner_loc), "should be '''"}}),
+                source_location(inner_loc));
+        }
+        // `lex_ml_literal_string_close` allows 3 to 5 `'`s to allow 1 or 2 `'`s
+        // at just before the delimiter. Here, we need to attach `'`s at the
+        // end of the string body, if it exists.
+        // For detail, see the definition of `lex_ml_basic_string_close`.
+
+        std::string retval = body.unwrap().str();
+        assert(std::all_of(close.unwrap().first(), close.unwrap().last(),
+                           [](const char c) noexcept {return c == '\'';}));
+        switch(close.unwrap().size())
+        {
+            case 3: {break;}
+            case 4: {retval += "'";  break;}
+            case 5: {retval += "''"; break;}
+            default:
+            {
+                throw internal_error(format_underline(
+                    "parse_ml_literal_string: closing delimiter has invalid length",
+                    {{source_location(inner_loc), "end of this"}}),
+                    source_location(inner_loc));
+            }
+        }
+
+        const auto err_loc = check_utf8_validity(token.unwrap().str());
+        if(err_loc == -1)
+        {
+            return ok(std::make_pair(toml::string(retval, toml::string_t::literal),
+                                     token.unwrap()));
+        }
+        else
+        {
+            inner_loc.reset(first);
+            inner_loc.advance(err_loc);
+            throw syntax_error(format_underline(
+                "parse_ml_literal_string: invalid utf8 sequence found",
+                {{source_location(inner_loc), "here"}}),
+                source_location(inner_loc));
+        }
+    }
+    else
+    {
+        loc.reset(first); // rollback
+        return err(format_underline("toml::parse_ml_literal_string: "
+                   "the next token is not a valid multiline literal string",
+                   {{source_location(loc), "here"}}));
+    }
+}
+
+inline result<std::pair<toml::string, region>, std::string>
+parse_literal_string(location& loc)
+{
+    const auto first = loc.iter();
+    if(const auto token = lex_literal_string::invoke(loc))
+    {
+        auto inner_loc = loc;
+        inner_loc.reset(first);
+
+        const auto open = lex_apostrophe::invoke(inner_loc);
+        if(!open)
+        {
+            throw internal_error(format_underline(
+                "parse_literal_string: invalid token",
+                {{source_location(inner_loc), "should be '"}}),
+                source_location(inner_loc));
+        }
+
+        const auto body = repeat<lex_literal_char, unlimited>::invoke(inner_loc);
+
+        const auto close = lex_apostrophe::invoke(inner_loc);
+        if(!close)
+        {
+            throw internal_error(format_underline(
+                "parse_literal_string: invalid token",
+                {{source_location(inner_loc), "should be '"}}),
+                source_location(inner_loc));
+        }
+
+        const auto err_loc = check_utf8_validity(token.unwrap().str());
+        if(err_loc == -1)
+        {
+            return ok(std::make_pair(
+                      toml::string(body.unwrap().str(), toml::string_t::literal),
+                      token.unwrap()));
+        }
+        else
+        {
+            inner_loc.reset(first);
+            inner_loc.advance(err_loc);
+            throw syntax_error(format_underline(
+                "parse_literal_string: invalid utf8 sequence found",
+                {{source_location(inner_loc), "here"}}),
+                source_location(inner_loc));
+        }
+    }
+    else
+    {
+        loc.reset(first); // rollback
+        return err(format_underline("toml::parse_literal_string: "
+                   "the next token is not a valid literal string",
+                   {{source_location(loc), "here"}}));
+    }
+}
+
+inline result<std::pair<toml::string, region>, std::string>
+parse_string(location& loc)
+{
+    if(loc.iter() != loc.end() && *(loc.iter()) == '"')
+    {
+        if(loc.iter() + 1 != loc.end() && *(loc.iter() + 1) == '"' &&
+           loc.iter() + 2 != loc.end() && *(loc.iter() + 2) == '"')
+        {
+            return parse_ml_basic_string(loc);
+        }
+        else
+        {
+            return parse_basic_string(loc);
+        }
+    }
+    else if(loc.iter() != loc.end() && *(loc.iter()) == '\'')
+    {
+        if(loc.iter() + 1 != loc.end() && *(loc.iter() + 1) == '\'' &&
+           loc.iter() + 2 != loc.end() && *(loc.iter() + 2) == '\'')
+        {
+            return parse_ml_literal_string(loc);
+        }
+        else
+        {
+            return parse_literal_string(loc);
+        }
+    }
+    return err(format_underline("toml::parse_string: ",
+                {{source_location(loc), "the next token is not a string"}}));
+}
+
+inline result<std::pair<local_date, region>, std::string>
+parse_local_date(location& loc)
+{
+    const auto first = loc.iter();
+    if(const auto token = lex_local_date::invoke(loc))
+    {
+        location inner_loc(loc.name(), token.unwrap().str());
+
+        const auto y = lex_date_fullyear::invoke(inner_loc);
+        if(!y || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-')
+        {
+            throw internal_error(format_underline(
+                "toml::parse_local_date: invalid year format",
+                {{source_location(inner_loc), "should be `-`"}}),
+                source_location(inner_loc));
+        }
+        inner_loc.advance();
+        const auto m = lex_date_month::invoke(inner_loc);
+        if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != '-')
+        {
+            throw internal_error(format_underline(
+                "toml::parse_local_date: invalid month format",
+                {{source_location(inner_loc), "should be `-`"}}),
+                source_location(inner_loc));
+        }
+        inner_loc.advance();
+        const auto d = lex_date_mday::invoke(inner_loc);
+        if(!d)
+        {
+            throw internal_error(format_underline(
+                "toml::parse_local_date: invalid day format",
+                {{source_location(inner_loc), "here"}}),
+                source_location(inner_loc));
+        }
+
+        const auto year  = static_cast<std::int16_t>(from_string<int>(y.unwrap().str(), 0));
+        const auto month = static_cast<std::int8_t >(from_string<int>(m.unwrap().str(), 0));
+        const auto day   = static_cast<std::int8_t >(from_string<int>(d.unwrap().str(), 0));
+
+        // We briefly check whether the input date is valid or not. But here, we
+        // only check if the RFC3339 compliance.
+        //     Actually there are several special date that does not exist,
+        // because of historical reasons, such as 1582/10/5-1582/10/14 (only in
+        // several countries). But here, we do not care about such a complicated
+        // rule. It makes the code complicated and there is only low probability
+        // that such a specific date is needed in practice. If someone need to
+        // validate date accurately, that means that the one need a specialized
+        // library for their purpose in a different layer.
+        {
+            const bool is_leap = (year % 4 == 0) && ((year % 100 != 0) || (year % 400 == 0));
+            const auto max_day = (month == 2) ? (is_leap ? 29 : 28) :
+                ((month == 4 || month == 6 || month == 9 || month == 11) ? 30 : 31);
+
+            if((month < 1 || 12 < month) || (day < 1 || max_day < day))
+            {
+                throw syntax_error(format_underline("toml::parse_date: "
+                    "invalid date: it does not conform RFC3339.", {{
+                    source_location(loc), "month should be 01-12, day should be"
+                    " 01-28,29,30,31, depending on month/year."
+                    }}), source_location(inner_loc));
+            }
+        }
+        return ok(std::make_pair(local_date(year, static_cast<month_t>(month - 1), day),
+                                 token.unwrap()));
+    }
+    else
+    {
+        loc.reset(first);
+        return err(format_underline("toml::parse_local_date: ",
+            {{source_location(loc), "the next token is not a local_date"}}));
+    }
+}
+
+inline result<std::pair<local_time, region>, std::string>
+parse_local_time(location& loc)
+{
+    const auto first = loc.iter();
+    if(const auto token = lex_local_time::invoke(loc))
+    {
+        location inner_loc(loc.name(), token.unwrap().str());
+
+        const auto h = lex_time_hour::invoke(inner_loc);
+        if(!h || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':')
+        {
+            throw internal_error(format_underline(
+                "toml::parse_local_time: invalid year format",
+                {{source_location(inner_loc), "should be `:`"}}),
+                source_location(inner_loc));
+        }
+        inner_loc.advance();
+        const auto m = lex_time_minute::invoke(inner_loc);
+        if(!m || inner_loc.iter() == inner_loc.end() || *inner_loc.iter() != ':')
+        {
+            throw internal_error(format_underline(
+                "toml::parse_local_time: invalid month format",
+                {{source_location(inner_loc), "should be `:`"}}),
+                source_location(inner_loc));
+        }
+        inner_loc.advance();
+        const auto s = lex_time_second::invoke(inner_loc);
+        if(!s)
+        {
+            throw internal_error(format_underline(
+                "toml::parse_local_time: invalid second format",
+                {{source_location(inner_loc), "here"}}),
+                source_location(inner_loc));
+        }
+
+        const int hour   = from_string<int>(h.unwrap().str(), 0);
+        const int minute = from_string<int>(m.unwrap().str(), 0);
+        const int second = from_string<int>(s.unwrap().str(), 0);
+
+        if((hour   < 0 || 23 < hour) || (minute < 0 || 59 < minute) ||
+           (second < 0 || 60 < second)) // it may be leap second
+        {
+            throw syntax_error(format_underline("toml::parse_local_time: "
+                "invalid time: it does not conform RFC3339.", {{
+                source_location(loc), "hour should be 00-23, minute should be"
+                " 00-59, second should be 00-60 (depending on the leap"
+                " second rules.)"}}), source_location(inner_loc));
+        }
+
+        local_time time(hour, minute, second, 0, 0);
+
+        const auto before_secfrac = inner_loc.iter();
+        if(const auto secfrac = lex_time_secfrac::invoke(inner_loc))
+        {
+            auto sf = secfrac.unwrap().str();
+            sf.erase(sf.begin()); // sf.front() == '.'
+            switch(sf.size() % 3)
+            {
+                case 2:  sf += '0';  break;
+                case 1:  sf += "00"; break;
+                case 0:  break;
+                default: break;
+            }
+            if(sf.size() >= 9)
+            {
+                time.millisecond = from_string<std::uint16_t>(sf.substr(0, 3), 0u);
+                time.microsecond = from_string<std::uint16_t>(sf.substr(3, 3), 0u);
+                time.nanosecond  = from_string<std::uint16_t>(sf.substr(6, 3), 0u);
+            }
+            else if(sf.size() >= 6)
+            {
+                time.millisecond = from_string<std::uint16_t>(sf.substr(0, 3), 0u);
+                time.microsecond = from_string<std::uint16_t>(sf.substr(3, 3), 0u);
+            }
+            else if(sf.size() >= 3)
+            {
+                time.millisecond = from_string<std::uint16_t>(sf, 0u);
+                time.microsecond = 0u;
+            }
+        }
+        else
+        {
+            if(before_secfrac != inner_loc.iter())
+            {
+                throw internal_error(format_underline(
+                    "toml::parse_local_time: invalid subsecond format",
+                    {{source_location(inner_loc), "here"}}),
+                source_location(inner_loc));
+            }
+        }
+        return ok(std::make_pair(time, token.unwrap()));
+    }
+    else
+    {
+        loc.reset(first);
+        return err(format_underline("toml::parse_local_time: ",
+            {{source_location(loc), "the next token is not a local_time"}}));
+    }
+}
+
+inline result<std::pair<local_datetime, region>, std::string>
+parse_local_datetime(location& loc)
+{
+    const auto first = loc.iter();
+    if(const auto token = lex_local_date_time::invoke(loc))
+    {
+        location inner_loc(loc.name(), token.unwrap().str());
+        const auto date = parse_local_date(inner_loc);
+        if(!date || inner_loc.iter() == inner_loc.end())
+        {
+            throw internal_error(format_underline(
+                "toml::parse_local_datetime: invalid datetime format",
+                {{source_location(inner_loc), "date, not datetime"}}),
+                source_location(inner_loc));
+        }
+        const char delim = *(inner_loc.iter());
+        if(delim != 'T' && delim != 't' && delim != ' ')
+        {
+            throw internal_error(format_underline(
+                "toml::parse_local_datetime: invalid datetime format",
+                {{source_location(inner_loc), "should be `T` or ` ` (space)"}}),
+                source_location(inner_loc));
+        }
+        inner_loc.advance();
+        const auto time = parse_local_time(inner_loc);
+        if(!time)
+        {
+            throw internal_error(format_underline(
+                "toml::parse_local_datetime: invalid datetime format",
+                {{source_location(inner_loc), "invalid time format"}}),
+                source_location(inner_loc));
+        }
+        return ok(std::make_pair(
+            local_datetime(date.unwrap().first, time.unwrap().first),
+            token.unwrap()));
+    }
+    else
+    {
+        loc.reset(first);
+        return err(format_underline("toml::parse_local_datetime: ",
+            {{source_location(loc), "the next token is not a local_datetime"}}));
+    }
+}
+
+inline result<std::pair<offset_datetime, region>, std::string>
+parse_offset_datetime(location& loc)
+{
+    const auto first = loc.iter();
+    if(const auto token = lex_offset_date_time::invoke(loc))
+    {
+        location inner_loc(loc.name(), token.unwrap().str());
+        const auto datetime = parse_local_datetime(inner_loc);
+        if(!datetime || inner_loc.iter() == inner_loc.end())
+        {
+            throw internal_error(format_underline(
+                "toml::parse_offset_datetime: invalid datetime format",
+                {{source_location(inner_loc), "date, not datetime"}}),
+                source_location(inner_loc));
+        }
+        time_offset offset(0, 0);
+        if(const auto ofs = lex_time_numoffset::invoke(inner_loc))
+        {
+            const auto str = ofs.unwrap().str();
+
+            const auto hour   = from_string<int>(str.substr(1,2), 0);
+            const auto minute = from_string<int>(str.substr(4,2), 0);
+
+            if((hour < 0 || 23 < hour) || (minute < 0 || 59 < minute))
+            {
+                throw syntax_error(format_underline("toml::parse_offset_datetime: "
+                    "invalid offset: it does not conform RFC3339.", {{
+                    source_location(loc), "month should be 01-12, day should be"
+                    " 01-28,29,30,31, depending on month/year."
+                    }}), source_location(inner_loc));
+            }
+
+            if(str.front() == '+')
+            {
+                offset = time_offset(hour, minute);
+            }
+            else
+            {
+                offset = time_offset(-hour, -minute);
+            }
+        }
+        else if(*inner_loc.iter() != 'Z' && *inner_loc.iter() != 'z')
+        {
+            throw internal_error(format_underline(
+                "toml::parse_offset_datetime: invalid datetime format",
+                {{source_location(inner_loc), "should be `Z` or `+HH:MM`"}}),
+                source_location(inner_loc));
+        }
+        return ok(std::make_pair(offset_datetime(datetime.unwrap().first, offset),
+                                 token.unwrap()));
+    }
+    else
+    {
+        loc.reset(first);
+        return err(format_underline("toml::parse_offset_datetime: ",
+            {{source_location(loc), "the next token is not a offset_datetime"}}));
+    }
+}
+
+inline result<std::pair<key, region>, std::string>
+parse_simple_key(location& loc)
+{
+    if(const auto bstr = parse_basic_string(loc))
+    {
+        return ok(std::make_pair(bstr.unwrap().first.str, bstr.unwrap().second));
+    }
+    if(const auto lstr = parse_literal_string(loc))
+    {
+        return ok(std::make_pair(lstr.unwrap().first.str, lstr.unwrap().second));
+    }
+    if(const auto bare = lex_unquoted_key::invoke(loc))
+    {
+        const auto reg = bare.unwrap();
+        return ok(std::make_pair(reg.str(), reg));
+    }
+    return err(format_underline("toml::parse_simple_key: ",
+            {{source_location(loc), "the next token is not a simple key"}}));
+}
+
+// dotted key become vector of keys
+inline result<std::pair<std::vector<key>, region>, std::string>
+parse_key(location& loc)
+{
+    const auto first = loc.iter();
+    // dotted key -> `foo.bar.baz` where several single keys are chained by
+    // dots. Whitespaces between keys and dots are allowed.
+    if(const auto token = lex_dotted_key::invoke(loc))
+    {
+        const auto reg = token.unwrap();
+        location inner_loc(loc.name(), reg.str());
+        std::vector<key> keys;
+
+        while(inner_loc.iter() != inner_loc.end())
+        {
+            lex_ws::invoke(inner_loc);
+            if(const auto k = parse_simple_key(inner_loc))
+            {
+                keys.push_back(k.unwrap().first);
+            }
+            else
+            {
+                throw internal_error(format_underline(
+                    "toml::parse_key: dotted key contains invalid key",
+                    {{source_location(inner_loc), k.unwrap_err()}}),
+                    source_location(inner_loc));
+            }
+
+            lex_ws::invoke(inner_loc);
+            if(inner_loc.iter() == inner_loc.end())
+            {
+                break;
+            }
+            else if(*inner_loc.iter() == '.')
+            {
+                inner_loc.advance(); // to skip `.`
+            }
+            else
+            {
+                throw internal_error(format_underline("toml::parse_key: "
+                    "dotted key contains invalid key ",
+                    {{source_location(inner_loc), "should be `.`"}}),
+                    source_location(inner_loc));
+            }
+        }
+        return ok(std::make_pair(keys, reg));
+    }
+    loc.reset(first);
+
+    // simple_key: a single (basic_string|literal_string|bare key)
+    if(const auto smpl = parse_simple_key(loc))
+    {
+        return ok(std::make_pair(std::vector<key>(1, smpl.unwrap().first),
+                                 smpl.unwrap().second));
+    }
+    return err(format_underline("toml::parse_key: an invalid key appeared.",
+                {{source_location(loc), "is not a valid key"}}, {
+                "bare keys  : non-empty strings composed only of [A-Za-z0-9_-].",
+                "quoted keys: same as \"basic strings\" or 'literal strings'.",
+                "dotted keys: sequence of bare or quoted keys joined with a dot."
+                }));
+}
+
+// forward-decl to implement parse_array and parse_table
+template<typename Value>
+result<Value, std::string> parse_value(location&, const std::size_t n_rec);
+
+template<typename Value>
+result<std::pair<typename Value::array_type, region>, std::string>
+parse_array(location& loc, const std::size_t n_rec)
+{
+    using value_type = Value;
+    using array_type = typename value_type::array_type;
+
+    if(n_rec > TOML11_VALUE_RECURSION_LIMIT)
+    {
+        // parse_array does not have any way to handle recursive error currently...
+        throw syntax_error(std::string("toml::parse_array: recursion limit ("
+                TOML11_STRINGIZE(TOML11_VALUE_RECURSION_LIMIT) ") exceeded"),
+                source_location(loc));
+    }
+
+    const auto first = loc.iter();
+    if(loc.iter() == loc.end())
+    {
+        return err("toml::parse_array: input is empty");
+    }
+    if(*loc.iter() != '[')
+    {
+        return err("toml::parse_array: token is not an array");
+    }
+    loc.advance();
+
+    using lex_ws_comment_newline = repeat<
+        either<lex_wschar, lex_newline, lex_comment>, unlimited>;
+
+    array_type retval;
+    while(loc.iter() != loc.end())
+    {
+        lex_ws_comment_newline::invoke(loc); // skip
+
+        if(loc.iter() != loc.end() && *loc.iter() == ']')
+        {
+            loc.advance(); // skip ']'
+            return ok(std::make_pair(retval,
+                      region(loc, first, loc.iter())));
+        }
+
+        if(auto val = parse_value<value_type>(loc, n_rec+1))
+        {
+            // After TOML v1.0.0-rc.1, array becomes to be able to have values
+            // with different types. So here we will omit this by default.
+            //
+            // But some of the test-suite checks if the parser accepts a hetero-
+            // geneous arrays, so we keep this for a while.
+#ifdef TOML11_DISALLOW_HETEROGENEOUS_ARRAYS
+            if(!retval.empty() && retval.front().type() != val.as_ok().type())
+            {
+                auto array_start_loc = loc;
+                array_start_loc.reset(first);
+
+                throw syntax_error(format_underline("toml::parse_array: "
+                    "type of elements should be the same each other.", {
+                        {source_location(array_start_loc), "array starts here"},
+                        {
+                            retval.front().location(),
+                            "value has type " + stringize(retval.front().type())
+                        },
+                        {
+                            val.unwrap().location(),
+                            "value has different type, " + stringize(val.unwrap().type())
+                        }
+                    }), source_location(loc));
+            }
+#endif
+            retval.push_back(std::move(val.unwrap()));
+        }
+        else
+        {
+            auto array_start_loc = loc;
+            array_start_loc.reset(first);
+
+            throw syntax_error(format_underline("toml::parse_array: "
+                "value having invalid format appeared in an array", {
+                    {source_location(array_start_loc), "array starts here"},
+                    {source_location(loc), "it is not a valid value."}
+                }), source_location(loc));
+        }
+
+        using lex_array_separator = sequence<maybe<lex_ws_comment_newline>, character<','>>;
+        const auto sp = lex_array_separator::invoke(loc);
+        if(!sp)
+        {
+            lex_ws_comment_newline::invoke(loc);
+            if(loc.iter() != loc.end() && *loc.iter() == ']')
+            {
+                loc.advance(); // skip ']'
+                return ok(std::make_pair(retval,
+                          region(loc, first, loc.iter())));
+            }
+            else
+            {
+                auto array_start_loc = loc;
+                array_start_loc.reset(first);
+
+                throw syntax_error(format_underline("toml::parse_array:"
+                    " missing array separator `,` after a value", {
+                        {source_location(array_start_loc), "array starts here"},
+                        {source_location(loc),             "should be `,`"}
+                    }), source_location(loc));
+            }
+        }
+    }
+    loc.reset(first);
+    throw syntax_error(format_underline("toml::parse_array: "
+            "array did not closed by `]`",
+            {{source_location(loc), "should be closed"}}),
+            source_location(loc));
+}
+
+template<typename Value>
+result<std::pair<std::pair<std::vector<key>, region>, Value>, std::string>
+parse_key_value_pair(location& loc, const std::size_t n_rec)
+{
+    using value_type = Value;
+
+    const auto first = loc.iter();
+    auto key_reg = parse_key(loc);
+    if(!key_reg)
+    {
+        std::string msg = std::move(key_reg.unwrap_err());
+        // if the next token is keyvalue-separator, it means that there are no
+        // key. then we need to show error as "empty key is not allowed".
+        if(const auto keyval_sep = lex_keyval_sep::invoke(loc))
+        {
+            loc.reset(first);
+            msg = format_underline("toml::parse_key_value_pair: "
+                "empty key is not allowed.",
+                {{source_location(loc), "key expected before '='"}});
+        }
+        return err(std::move(msg));
+    }
+
+    const auto kvsp = lex_keyval_sep::invoke(loc);
+    if(!kvsp)
+    {
+        std::string msg;
+        // if the line contains '=' after the invalid sequence, possibly the
+        // error is in the key (like, invalid character in bare key).
+        const auto line_end = std::find(loc.iter(), loc.end(), '\n');
+        if(std::find(loc.iter(), line_end, '=') != line_end)
+        {
+            msg = format_underline("toml::parse_key_value_pair: "
+                "invalid format for key",
+                {{source_location(loc), "invalid character in key"}},
+                {"Did you forget '.' to separate dotted-key?",
+                "Allowed characters for bare key are [0-9a-zA-Z_-]."});
+        }
+        else // if not, the error is lack of key-value separator.
+        {
+            msg = format_underline("toml::parse_key_value_pair: "
+                "missing key-value separator `=`",
+                {{source_location(loc), "should be `=`"}});
+        }
+        loc.reset(first);
+        return err(std::move(msg));
+    }
+
+    const auto after_kvsp = loc.iter(); // err msg
+    auto val = parse_value<value_type>(loc, n_rec);
+    if(!val)
+    {
+        std::string msg;
+        loc.reset(after_kvsp);
+        // check there is something not a comment/whitespace after `=`
+        if(sequence<maybe<lex_ws>, maybe<lex_comment>, lex_newline>::invoke(loc))
+        {
+            loc.reset(after_kvsp);
+            msg = format_underline("toml::parse_key_value_pair: "
+                    "missing value after key-value separator '='",
+                    {{source_location(loc), "expected value, but got nothing"}});
+        }
+        else // there is something not a comment/whitespace, so invalid format.
+        {
+            msg = std::move(val.unwrap_err());
+        }
+        loc.reset(first);
+        return err(msg);
+    }
+    return ok(std::make_pair(std::move(key_reg.unwrap()),
+                             std::move(val.unwrap())));
+}
+
+// for error messages.
+template<typename InputIterator>
+std::string format_dotted_keys(InputIterator first, const InputIterator last)
+{
+    static_assert(std::is_same<key,
+        typename std::iterator_traits<InputIterator>::value_type>::value,"");
+
+    std::string retval(*first++);
+    for(; first != last; ++first)
+    {
+        retval += '.';
+        retval += *first;
+    }
+    return retval;
+}
+
+// forward decl for is_valid_forward_table_definition
+result<std::pair<std::vector<key>, region>, std::string>
+parse_table_key(location& loc);
+result<std::pair<std::vector<key>, region>, std::string>
+parse_array_table_key(location& loc);
+template<typename Value>
+result<std::pair<typename Value::table_type, region>, std::string>
+parse_inline_table(location& loc, const std::size_t n_rec);
+
+// The following toml file is allowed.
+// ```toml
+// [a.b.c]     # here, table `a` has element `b`.
+// foo = "bar"
+// [a]         # merge a = {baz = "qux"} to a = {b = {...}}
+// baz = "qux"
+// ```
+// But the following is not allowed.
+// ```toml
+// [a]
+// b.c.foo = "bar"
+// [a]             # error! the same table [a] defined!
+// baz = "qux"
+// ```
+// The following is neither allowed.
+// ```toml
+// a = { b.c.foo = "bar"}
+// [a]             # error! the same table [a] defined!
+// baz = "qux"
+// ```
+// Here, it parses region of `tab->at(k)` as a table key and check the depth
+// of the key. If the key region points deeper node, it would be allowed.
+// Otherwise, the key points the same node. It would be rejected.
+template<typename Value, typename Iterator>
+bool is_valid_forward_table_definition(const Value& fwd, const Value& inserting,
+        Iterator key_first, Iterator key_curr, Iterator key_last)
+{
+    // ------------------------------------------------------------------------
+    // check type of the value to be inserted/merged
+
+    std::string inserting_reg = "";
+    if(const auto ptr = detail::get_region(inserting))
+    {
+        inserting_reg = ptr->str();
+    }
+    location inserting_def("internal", std::move(inserting_reg));
+    if(const auto inlinetable = parse_inline_table<Value>(inserting_def, 0))
+    {
+        // check if we are overwriting existing table.
+        // ```toml
+        // # NG
+        // a.b = 42
+        // a = {d = 3.14}
+        // ```
+        // Inserting an inline table to a existing super-table is not allowed in
+        // any case. If we found it, we can reject it without further checking.
+        return false;
+    }
+
+    // Valid and invalid cases when inserting to the [a.b] table:
+    //
+    // ## Invalid
+    //
+    // ```toml
+    // # invalid
+    // [a]
+    // b.c.d = "foo"
+    // [a.b]       # a.b is already defined and closed
+    // d = "bar"
+    // ```
+    // ```toml
+    // # invalid
+    // a = {b.c.d = "foo"}
+    // [a.b] # a is already defined and inline table is closed
+    // d = "bar"
+    // ```
+    // ```toml
+    // # invalid
+    // a.b.c.d = "foo"
+    // [a.b] # a.b is already defined and dotted-key table is closed
+    // d = "bar"
+    // ```
+    //
+    // ## Valid
+    //
+    // ```toml
+    // # OK. a.b is defined, but is *overwritable*
+    // [a.b.c]
+    // d = "foo"
+    // [a.b]
+    // d = "bar"
+    // ```
+    // ```toml
+    // # OK. a.b is defined, but is *overwritable*
+    // [a]
+    // b.c.d = "foo"
+    // b.e = "bar"
+    // ```
+
+    // ------------------------------------------------------------------------
+    // check table defined before
+
+    std::string internal = "";
+    if(const auto ptr = detail::get_region(fwd))
+    {
+        internal = ptr->str();
+    }
+    location def("internal", std::move(internal));
+    if(const auto tabkeys = parse_table_key(def)) // [table.key]
+    {
+        // table keys always contains all the nodes from the root.
+        const auto& tks = tabkeys.unwrap().first;
+        if(std::size_t(std::distance(key_first, key_last)) == tks.size() &&
+           std::equal(tks.begin(), tks.end(), key_first))
+        {
+            // the keys are equivalent. it is not allowed.
+            return false;
+        }
+        // the keys are not equivalent. it is allowed.
+        return true;
+    }
+    // nested array-of-table definition implicitly defines tables.
+    // those tables can be reopened.
+    if(const auto atabkeys = parse_array_table_key(def))
+    {
+        // table keys always contains all the nodes from the root.
+        const auto& tks = atabkeys.unwrap().first;
+        if(std::size_t(std::distance(key_first, key_last)) == tks.size() &&
+           std::equal(tks.begin(), tks.end(), key_first))
+        {
+            // the keys are equivalent. it is not allowed.
+            return false;
+        }
+        // the keys are not equivalent. it is allowed.
+        return true;
+    }
+    if(const auto dotkeys = parse_key(def)) // a.b.c = "foo"
+    {
+        // consider the following case.
+        // [a]
+        // b.c = {d = 42}
+        // [a.b.c]
+        // e = 2.71
+        // this defines the table [a.b.c] twice. no?
+        if(const auto reopening_dotkey_by_table = parse_table_key(inserting_def))
+        {
+            // re-opening a dotkey-defined table by a table is invalid.
+            // only dotkey can append a key-val. Like:
+            // ```toml
+            // a.b.c = "foo"
+            // a.b.d = "bar" # OK. reopen `a.b` by dotkey
+            // [a.b]
+            // e = "bar" # Invalid. re-opening `a.b` by [a.b] is not allowed.
+            // ```
+            return false;
+        }
+
+        // a dotted key starts from the node representing a table in which the
+        // dotted key belongs to.
+        const auto& dks = dotkeys.unwrap().first;
+        if(std::size_t(std::distance(key_curr, key_last)) == dks.size() &&
+           std::equal(dks.begin(), dks.end(), key_curr))
+        {
+            // the keys are equivalent. it is not allowed.
+            return false;
+        }
+        // the keys are not equivalent. it is allowed.
+        return true;
+    }
+    return false;
+}
+
+template<typename Value, typename InputIterator>
+result<bool, std::string>
+insert_nested_key(typename Value::table_type& root, const Value& v,
+                  InputIterator iter, const InputIterator last,
+                  region key_reg,
+                  const bool is_array_of_table = false)
+{
+    static_assert(std::is_same<key,
+        typename std::iterator_traits<InputIterator>::value_type>::value,"");
+
+    using value_type = Value;
+    using table_type = typename value_type::table_type;
+    using array_type = typename value_type::array_type;
+
+    const auto first = iter;
+    assert(iter != last);
+
+    table_type* tab = std::addressof(root);
+    for(; iter != last; ++iter) // search recursively
+    {
+        const key& k = *iter;
+        if(std::next(iter) == last) // k is the last key
+        {
+            // XXX if the value is array-of-tables, there can be several
+            //     tables that are in the same array. in that case, we need to
+            //     find the last element and insert it to there.
+            if(is_array_of_table)
+            {
+                if(tab->count(k) == 1) // there is already an array of table
+                {
+                    if(tab->at(k).is_table())
+                    {
+                        // show special err msg for conflicting table
+                        throw syntax_error(format_underline(concat_to_string(
+                            "toml::insert_value: array of table (\"",
+                            format_dotted_keys(first, last),
+                            "\") cannot be defined"), {
+                                {tab->at(k).location(), "table already defined"},
+                                {v.location(), "this conflicts with the previous table"}
+                            }), v.location());
+                    }
+                    else if(!(tab->at(k).is_array()))
+                    {
+                        throw syntax_error(format_underline(concat_to_string(
+                            "toml::insert_value: array of table (\"",
+                            format_dotted_keys(first, last), "\") collides with"
+                            " existing value"), {
+                                {tab->at(k).location(),
+                                 concat_to_string("this ", tab->at(k).type(),
+                                                  " value already exists")},
+                                {v.location(),
+                                 "while inserting this array-of-tables"}
+                            }), v.location());
+                    }
+                    // the above if-else-if checks tab->at(k) is an array
+                    auto& a = tab->at(k).as_array();
+                    // If table element is defined as [[array_of_tables]], it
+                    // cannot be an empty array. If an array of tables is
+                    // defined as `aot = []`, it cannot be appended.
+                    if(a.empty() || !(a.front().is_table()))
+                    {
+                        throw syntax_error(format_underline(concat_to_string(
+                            "toml::insert_value: array of table (\"",
+                            format_dotted_keys(first, last), "\") collides with"
+                            " existing value"), {
+                                {tab->at(k).location(),
+                                 concat_to_string("this ", tab->at(k).type(),
+                                                  " value already exists")},
+                                {v.location(),
+                                 "while inserting this array-of-tables"}
+                            }), v.location());
+                    }
+                    // avoid conflicting array of table like the following.
+                    // ```toml
+                    // a = [{b = 42}] # define a as an array of *inline* tables
+                    // [[a]]          # a is an array of *multi-line* tables
+                    // b = 54
+                    // ```
+                    // Here, from the type information, these cannot be detected
+                    // because inline table is also a table.
+                    // But toml v0.5.0 explicitly says it is invalid. The above
+                    // array-of-tables has a static size and appending to the
+                    // array is invalid.
+                    // In this library, multi-line table value has a region
+                    // that points to the key of the table (e.g. [[a]]). By
+                    // comparing the first two letters in key, we can detect
+                    // the array-of-table is inline or multiline.
+                    if(const auto ptr = detail::get_region(a.front()))
+                    {
+                        if(ptr->str().substr(0,2) != "[[")
+                        {
+                            throw syntax_error(format_underline(concat_to_string(
+                                "toml::insert_value: array of table (\"",
+                                format_dotted_keys(first, last), "\") collides "
+                                "with existing array-of-tables"), {
+                                    {tab->at(k).location(),
+                                     concat_to_string("this ", tab->at(k).type(),
+                                                      " value has static size")},
+                                    {v.location(),
+                                     "appending it to the statically sized array"}
+                                }), v.location());
+                        }
+                    }
+                    a.push_back(v);
+                    return ok(true);
+                }
+                else // if not, we need to create the array of table
+                {
+                    // XXX: Consider the following array of tables.
+                    // ```toml
+                    // # This is a comment.
+                    // [[aot]]
+                    // foo = "bar"
+                    // ```
+                    // Here, the comment is for `aot`. But here, actually two
+                    // values are defined. An array that contains tables, named
+                    // `aot`, and the 0th element of the `aot`, `{foo = "bar"}`.
+                    // Those two are different from each other. But both of them
+                    // points to the same portion of the TOML file, `[[aot]]`,
+                    // so `key_reg.comments()` returns `# This is a comment`.
+                    // If it is assigned as a comment of `aot` defined here, the
+                    // comment will be duplicated. Both the `aot` itself and
+                    // the 0-th element will have the same comment. This causes
+                    // "duplication of the same comments" bug when the data is
+                    // serialized.
+                    //     Next, consider the following.
+                    // ```toml
+                    // # comment 1
+                    // aot = [
+                    //     # comment 2
+                    //     {foo = "bar"},
+                    // ]
+                    // ```
+                    // In this case, we can distinguish those two comments. So
+                    // here we need to add "comment 1" to the `aot` and
+                    // "comment 2" to the 0th element of that.
+                    //     To distinguish those two, we check the key region.
+                    std::vector<std::string> comments{/* empty by default */};
+                    if(key_reg.str().substr(0, 2) != "[[")
+                    {
+                        comments = key_reg.comments();
+                    }
+                    value_type aot(array_type(1, v), key_reg, std::move(comments));
+                    tab->insert(std::make_pair(k, aot));
+                    return ok(true);
+                }
+            } // end if(array of table)
+
+            if(tab->count(k) == 1)
+            {
+                if(tab->at(k).is_table() && v.is_table())
+                {
+                    if(!is_valid_forward_table_definition(
+                                tab->at(k), v, first, iter, last))
+                    {
+                        throw syntax_error(format_underline(concat_to_string(
+                            "toml::insert_value: table (\"",
+                            format_dotted_keys(first, last),
+                            "\") already exists."), {
+                                {tab->at(k).location(), "table already exists here"},
+                                {v.location(), "table defined twice"}
+                            }), v.location());
+                    }
+                    // to allow the following toml file.
+                    // [a.b.c]
+                    // d = 42
+                    // [a]
+                    // e = 2.71
+                    auto& t = tab->at(k).as_table();
+                    for(const auto& kv : v.as_table())
+                    {
+                        if(tab->at(k).contains(kv.first))
+                        {
+                            throw syntax_error(format_underline(concat_to_string(
+                                "toml::insert_value: value (\"",
+                                format_dotted_keys(first, last),
+                                "\") already exists."), {
+                                    {t.at(kv.first).location(), "already exists here"},
+                                    {v.location(), "this defined twice"}
+                                }), v.location());
+                        }
+                        t[kv.first] = kv.second;
+                    }
+                    detail::change_region(tab->at(k), key_reg);
+                    return ok(true);
+                }
+                else if(v.is_table()                     &&
+                        tab->at(k).is_array()            &&
+                        tab->at(k).as_array().size() > 0 &&
+                        tab->at(k).as_array().front().is_table())
+                {
+                    throw syntax_error(format_underline(concat_to_string(
+                        "toml::insert_value: array of tables (\"",
+                        format_dotted_keys(first, last), "\") already exists."), {
+                            {tab->at(k).location(), "array of tables defined here"},
+                            {v.location(), "table conflicts with the previous array of table"}
+                        }), v.location());
+                }
+                else
+                {
+                    throw syntax_error(format_underline(concat_to_string(
+                        "toml::insert_value: value (\"",
+                        format_dotted_keys(first, last), "\") already exists."), {
+                            {tab->at(k).location(), "value already exists here"},
+                            {v.location(), "value defined twice"}
+                        }), v.location());
+                }
+            }
+            tab->insert(std::make_pair(k, v));
+            return ok(true);
+        }
+        else // k is not the last one, we should insert recursively
+        {
+            // if there is no corresponding value, insert it first.
+            // related: you don't need to write
+            // # [x]
+            // # [x.y]
+            // to write
+            // [x.y.z]
+            if(tab->count(k) == 0)
+            {
+                // a table that is defined implicitly doesn't have any comments.
+                (*tab)[k] = value_type(table_type{}, key_reg, {/*no comment*/});
+            }
+
+            // type checking...
+            if(tab->at(k).is_table())
+            {
+                // According to toml-lang/toml:36d3091b3 "Clarify that inline
+                // tables are immutable", check if it adds key-value pair to an
+                // inline table.
+                if(const auto* ptr = get_region(tab->at(k)))
+                {
+                    // here, if the value is a (multi-line) table, the region
+                    // should be something like `[table-name]`.
+                    if(ptr->front() == '{')
+                    {
+                        throw syntax_error(format_underline(concat_to_string(
+                            "toml::insert_value: inserting to an inline table (",
+                            format_dotted_keys(first, std::next(iter)),
+                            ") but inline tables are immutable"), {
+                                {tab->at(k).location(), "inline tables are immutable"},
+                                {v.location(), "inserting this"}
+                            }), v.location());
+                    }
+                }
+                tab = std::addressof((*tab)[k].as_table());
+            }
+            else if(tab->at(k).is_array()) // inserting to array-of-tables?
+            {
+                auto& a = (*tab)[k].as_array();
+                if(!a.back().is_table())
+                {
+                    throw syntax_error(format_underline(concat_to_string(
+                        "toml::insert_value: target (",
+                        format_dotted_keys(first, std::next(iter)),
+                        ") is neither table nor an array of tables"), {
+                            {a.back().location(), concat_to_string(
+                                    "actual type is ", a.back().type())},
+                            {v.location(), "inserting this"}
+                        }), v.location());
+                }
+                if(a.empty())
+                {
+                    throw syntax_error(format_underline(concat_to_string(
+                        "toml::insert_value: table (\"",
+                        format_dotted_keys(first, last), "\") conflicts with"
+                        " existing value"), {
+                            {tab->at(k).location(), std::string("this array is not insertable")},
+                            {v.location(), std::string("appending it to the statically sized array")}
+                        }), v.location());
+                }
+                if(const auto ptr = detail::get_region(a.at(0)))
+                {
+                    if(ptr->str().substr(0,2) != "[[")
+                    {
+                        throw syntax_error(format_underline(concat_to_string(
+                            "toml::insert_value: a table (\"",
+                            format_dotted_keys(first, last), "\") cannot be "
+                            "inserted to an existing inline array-of-tables"), {
+                                {tab->at(k).location(), std::string("this array of table has a static size")},
+                                {v.location(), std::string("appending it to the statically sized array")}
+                            }), v.location());
+                    }
+                }
+                tab = std::addressof(a.back().as_table());
+            }
+            else
+            {
+                throw syntax_error(format_underline(concat_to_string(
+                    "toml::insert_value: target (",
+                    format_dotted_keys(first, std::next(iter)),
+                    ") is neither table nor an array of tables"), {
+                        {tab->at(k).location(), concat_to_string(
+                                "actual type is ", tab->at(k).type())},
+                        {v.location(), "inserting this"}
+                    }), v.location());
+            }
+        }
+    }
+    return err(std::string("toml::detail::insert_nested_key: never reach here"));
+}
+
+template<typename Value>
+result<std::pair<typename Value::table_type, region>, std::string>
+parse_inline_table(location& loc, const std::size_t n_rec)
+{
+    using value_type = Value;
+    using table_type = typename value_type::table_type;
+
+    if(n_rec > TOML11_VALUE_RECURSION_LIMIT)
+    {
+        throw syntax_error(std::string("toml::parse_inline_table: recursion limit ("
+                TOML11_STRINGIZE(TOML11_VALUE_RECURSION_LIMIT) ") exceeded"),
+                source_location(loc));
+    }
+
+    const auto first = loc.iter();
+    table_type retval;
+    if(!(loc.iter() != loc.end() && *loc.iter() == '{'))
+    {
+        return err(format_underline("toml::parse_inline_table: ",
+            {{source_location(loc), "the next token is not an inline table"}}));
+    }
+    loc.advance();
+
+    // check if the inline table is an empty table = { }
+    maybe<lex_ws>::invoke(loc);
+    if(loc.iter() != loc.end() && *loc.iter() == '}')
+    {
+        loc.advance(); // skip `}`
+        return ok(std::make_pair(retval, region(loc, first, loc.iter())));
+    }
+
+    // it starts from "{". it should be formatted as inline-table
+    while(loc.iter() != loc.end())
+    {
+        const auto kv_r = parse_key_value_pair<value_type>(loc, n_rec+1);
+        if(!kv_r)
+        {
+            return err(kv_r.unwrap_err());
+        }
+
+        const auto&              kvpair  = kv_r.unwrap();
+        const std::vector<key>&  keys    = kvpair.first.first;
+        const auto&              key_reg = kvpair.first.second;
+        const value_type&        val     = kvpair.second;
+
+        const auto inserted =
+            insert_nested_key(retval, val, keys.begin(), keys.end(), key_reg);
+        if(!inserted)
+        {
+            throw internal_error("toml::parse_inline_table: "
+                "failed to insert value into table: " + inserted.unwrap_err(),
+                source_location(loc));
+        }
+
+        using lex_table_separator = sequence<maybe<lex_ws>, character<','>>;
+        const auto sp = lex_table_separator::invoke(loc);
+
+        if(!sp)
+        {
+            maybe<lex_ws>::invoke(loc);
+
+            if(loc.iter() == loc.end())
+            {
+                throw syntax_error(format_underline(
+                    "toml::parse_inline_table: missing table separator `}` ",
+                    {{source_location(loc), "should be `}`"}}),
+                    source_location(loc));
+            }
+            else if(*loc.iter() == '}')
+            {
+                loc.advance(); // skip `}`
+                return ok(std::make_pair(
+                            retval, region(loc, first, loc.iter())));
+            }
+            else if(*loc.iter() == '#' || *loc.iter() == '\r' || *loc.iter() == '\n')
+            {
+                throw syntax_error(format_underline(
+                    "toml::parse_inline_table: missing curly brace `}`",
+                    {{source_location(loc), "should be `}`"}}),
+                    source_location(loc));
+            }
+            else
+            {
+                throw syntax_error(format_underline(
+                    "toml::parse_inline_table: missing table separator `,` ",
+                    {{source_location(loc), "should be `,`"}}),
+                    source_location(loc));
+            }
+        }
+        else // `,` is found
+        {
+            maybe<lex_ws>::invoke(loc);
+            if(loc.iter() != loc.end() && *loc.iter() == '}')
+            {
+                throw syntax_error(format_underline(
+                    "toml::parse_inline_table: trailing comma is not allowed in"
+                    " an inline table",
+                    {{source_location(loc), "should be `}`"}}),
+                    source_location(loc));
+            }
+        }
+    }
+    loc.reset(first);
+    throw syntax_error(format_underline("toml::parse_inline_table: "
+            "inline table did not closed by `}`",
+            {{source_location(loc), "should be closed"}}),
+            source_location(loc));
+}
+
+inline result<value_t, std::string> guess_number_type(const location& l)
+{
+    // This function tries to find some (common) mistakes by checking characters
+    // that follows the last character of a value. But it is often difficult
+    // because some non-newline characters can appear after a value. E.g.
+    // spaces, tabs, commas (in an array or inline table), closing brackets
+    // (of an array or inline table), comment-sign (#). Since this function
+    // does not parse further, those characters are always allowed to be there.
+    location loc = l;
+
+    if(lex_offset_date_time::invoke(loc)) {return ok(value_t::offset_datetime);}
+    loc.reset(l.iter());
+
+    if(lex_local_date_time::invoke(loc))
+    {
+        // bad offset may appear after this.
+        if(loc.iter() != loc.end() && (*loc.iter() == '+' || *loc.iter() == '-'
+                    || *loc.iter() == 'Z' || *loc.iter() == 'z'))
+        {
+            return err(format_underline("bad offset: should be [+-]HH:MM or Z",
+                        {{source_location(loc), "[+-]HH:MM or Z"}},
+                        {"pass: +09:00, -05:30", "fail: +9:00, -5:30"}));
+        }
+        return ok(value_t::local_datetime);
+    }
+    loc.reset(l.iter());
+
+    if(lex_local_date::invoke(loc))
+    {
+        // bad time may appear after this.
+        // A space is allowed as a delimiter between local time. But there are
+        // both cases in which a space becomes valid or invalid.
+        // - invalid: 2019-06-16 7:00:00
+        // - valid  : 2019-06-16 07:00:00
+        if(loc.iter() != loc.end())
+        {
+            const auto c = *loc.iter();
+            if(c == 'T' || c == 't')
+            {
+                return err(format_underline("bad time: should be HH:MM:SS.subsec",
+                        {{source_location(loc), "HH:MM:SS.subsec"}},
+                        {"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999",
+                         "fail: 1979-05-27T7:32:00, 1979-05-27 17:32"}));
+            }
+            if('0' <= c && c <= '9')
+            {
+                return err(format_underline("bad time: missing T",
+                        {{source_location(loc), "T or space required here"}},
+                        {"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999",
+                         "fail: 1979-05-27T7:32:00, 1979-05-27 7:32"}));
+            }
+            if(c == ' ' && std::next(loc.iter()) != loc.end() &&
+                ('0' <= *std::next(loc.iter()) && *std::next(loc.iter())<= '9'))
+            {
+                loc.advance();
+                return err(format_underline("bad time: should be HH:MM:SS.subsec",
+                        {{source_location(loc), "HH:MM:SS.subsec"}},
+                        {"pass: 1979-05-27T07:32:00, 1979-05-27 07:32:00.999999",
+                         "fail: 1979-05-27T7:32:00, 1979-05-27 7:32"}));
+            }
+        }
+        return ok(value_t::local_date);
+    }
+    loc.reset(l.iter());
+
+    if(lex_local_time::invoke(loc)) {return ok(value_t::local_time);}
+    loc.reset(l.iter());
+
+    if(lex_float::invoke(loc))
+    {
+        if(loc.iter() != loc.end() && *loc.iter() == '_')
+        {
+            return err(format_underline("bad float: `_` should be surrounded by digits",
+                        {{source_location(loc), "here"}},
+                        {"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan",
+                         "fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"}));
+        }
+        return ok(value_t::floating);
+    }
+    loc.reset(l.iter());
+
+    if(lex_integer::invoke(loc))
+    {
+        if(loc.iter() != loc.end())
+        {
+            const auto c = *loc.iter();
+            if(c == '_')
+            {
+                return err(format_underline("bad integer: `_` should be surrounded by digits",
+                            {{source_location(loc), "here"}},
+                            {"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755",
+                             "fail: 1__000, 0123"}));
+            }
+            if('0' <= c && c <= '9')
+            {
+                // leading zero. point '0'
+                loc.retrace();
+                return err(format_underline("bad integer: leading zero",
+                            {{source_location(loc), "here"}},
+                            {"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755",
+                             "fail: 1__000, 0123"}));
+            }
+            if(c == ':' || c == '-')
+            {
+                return err(format_underline("bad datetime: invalid format",
+                            {{source_location(loc), "here"}},
+                            {"pass: 1979-05-27T07:32:00-07:00, 1979-05-27 07:32:00.999999Z",
+                             "fail: 1979-05-27T7:32:00-7:00, 1979-05-27 7:32-00:30"}));
+            }
+            if(c == '.' || c == 'e' || c == 'E')
+            {
+                return err(format_underline("bad float: invalid format",
+                            {{source_location(loc), "here"}},
+                            {"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan",
+                             "fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"}));
+            }
+        }
+        return ok(value_t::integer);
+    }
+    if(loc.iter() != loc.end() && *loc.iter() == '.')
+    {
+        return err(format_underline("bad float: invalid format",
+                {{source_location(loc), "integer part required before this"}},
+                {"pass: +1.0, -2e-2, 3.141_592_653_589, inf, nan",
+                 "fail: .0, 1., _1.0, 1.0_, 1_.0, 1.0__0"}));
+    }
+    if(loc.iter() != loc.end() && *loc.iter() == '_')
+    {
+        return err(format_underline("bad number: `_` should be surrounded by digits",
+                {{source_location(loc), "`_` is not surrounded by digits"}},
+                {"pass: -42, 1_000, 1_2_3_4_5, 0xC0FFEE, 0b0010, 0o755",
+                 "fail: 1__000, 0123"}));
+    }
+    return err(format_underline("bad format: unknown value appeared",
+                {{source_location(loc), "here"}}));
+}
+
+inline result<value_t, std::string> guess_value_type(const location& loc)
+{
+    switch(*loc.iter())
+    {
+        case '"' : {return ok(value_t::string);  }
+        case '\'': {return ok(value_t::string);  }
+        case 't' : {return ok(value_t::boolean); }
+        case 'f' : {return ok(value_t::boolean); }
+        case '[' : {return ok(value_t::array);   }
+        case '{' : {return ok(value_t::table);   }
+        case 'i' : {return ok(value_t::floating);} // inf.
+        case 'n' : {return ok(value_t::floating);} // nan.
+        default  : {return guess_number_type(loc);}
+    }
+}
+
+template<typename Value, typename T>
+result<Value, std::string>
+parse_value_helper(result<std::pair<T, region>, std::string> rslt)
+{
+    if(rslt.is_ok())
+    {
+        auto comments = rslt.as_ok().second.comments();
+        return ok(Value(std::move(rslt.as_ok()), std::move(comments)));
+    }
+    else
+    {
+        return err(std::move(rslt.as_err()));
+    }
+}
+
+template<typename Value>
+result<Value, std::string> parse_value(location& loc, const std::size_t n_rec)
+{
+    const auto first = loc.iter();
+    if(first == loc.end())
+    {
+        return err(format_underline("toml::parse_value: input is empty",
+                   {{source_location(loc), ""}}));
+    }
+
+    const auto type = guess_value_type(loc);
+    if(!type)
+    {
+        return err(type.unwrap_err());
+    }
+
+    switch(type.unwrap())
+    {
+        case value_t::boolean        : {return parse_value_helper<Value>(parse_boolean(loc)            );}
+        case value_t::integer        : {return parse_value_helper<Value>(parse_integer(loc)            );}
+        case value_t::floating       : {return parse_value_helper<Value>(parse_floating(loc)           );}
+        case value_t::string         : {return parse_value_helper<Value>(parse_string(loc)             );}
+        case value_t::offset_datetime: {return parse_value_helper<Value>(parse_offset_datetime(loc)    );}
+        case value_t::local_datetime : {return parse_value_helper<Value>(parse_local_datetime(loc)     );}
+        case value_t::local_date     : {return parse_value_helper<Value>(parse_local_date(loc)         );}
+        case value_t::local_time     : {return parse_value_helper<Value>(parse_local_time(loc)         );}
+        case value_t::array          : {return parse_value_helper<Value>(parse_array<Value>(loc, n_rec));}
+        case value_t::table          : {return parse_value_helper<Value>(parse_inline_table<Value>(loc, n_rec));}
+        default:
+        {
+            const auto msg = format_underline("toml::parse_value: "
+                    "unknown token appeared", {{source_location(loc), "unknown"}});
+            loc.reset(first);
+            return err(msg);
+        }
+    }
+}
+
+inline result<std::pair<std::vector<key>, region>, std::string>
+parse_table_key(location& loc)
+{
+    if(auto token = lex_std_table::invoke(loc))
+    {
+        location inner_loc(loc.name(), token.unwrap().str());
+
+        const auto open = lex_std_table_open::invoke(inner_loc);
+        if(!open || inner_loc.iter() == inner_loc.end())
+        {
+            throw internal_error(format_underline(
+                "toml::parse_table_key: no `[`",
+                {{source_location(inner_loc), "should be `[`"}}),
+                source_location(inner_loc));
+        }
+        // to skip [ a . b . c ]
+        //          ^----------- this whitespace
+        lex_ws::invoke(inner_loc);
+        const auto keys = parse_key(inner_loc);
+        if(!keys)
+        {
+            throw internal_error(format_underline(
+                "toml::parse_table_key: invalid key",
+                {{source_location(inner_loc), "not key"}}),
+                source_location(inner_loc));
+        }
+        // to skip [ a . b . c ]
+        //                    ^-- this whitespace
+        lex_ws::invoke(inner_loc);
+        const auto close = lex_std_table_close::invoke(inner_loc);
+        if(!close)
+        {
+            throw internal_error(format_underline(
+                "toml::parse_table_key: no `]`",
+                {{source_location(inner_loc), "should be `]`"}}),
+                source_location(inner_loc));
+        }
+
+        // after [table.key], newline or EOF(empty table) required.
+        if(loc.iter() != loc.end())
+        {
+            using lex_newline_after_table_key =
+                sequence<maybe<lex_ws>, maybe<lex_comment>, lex_newline>;
+            const auto nl = lex_newline_after_table_key::invoke(loc);
+            if(!nl)
+            {
+                throw syntax_error(format_underline(
+                    "toml::parse_table_key: newline required after [table.key]",
+                    {{source_location(loc), "expected newline"}}),
+                    source_location(loc));
+            }
+        }
+        return ok(std::make_pair(keys.unwrap().first, token.unwrap()));
+    }
+    else
+    {
+        return err(format_underline("toml::parse_table_key: "
+            "not a valid table key", {{source_location(loc), "here"}}));
+    }
+}
+
+inline result<std::pair<std::vector<key>, region>, std::string>
+parse_array_table_key(location& loc)
+{
+    if(auto token = lex_array_table::invoke(loc))
+    {
+        location inner_loc(loc.name(), token.unwrap().str());
+
+        const auto open = lex_array_table_open::invoke(inner_loc);
+        if(!open || inner_loc.iter() == inner_loc.end())
+        {
+            throw internal_error(format_underline(
+                "toml::parse_array_table_key: no `[[`",
+                {{source_location(inner_loc), "should be `[[`"}}),
+                source_location(inner_loc));
+        }
+        lex_ws::invoke(inner_loc);
+        const auto keys = parse_key(inner_loc);
+        if(!keys)
+        {
+            throw internal_error(format_underline(
+                "toml::parse_array_table_key: invalid key",
+                {{source_location(inner_loc), "not a key"}}),
+                source_location(inner_loc));
+        }
+        lex_ws::invoke(inner_loc);
+        const auto close = lex_array_table_close::invoke(inner_loc);
+        if(!close)
+        {
+            throw internal_error(format_underline(
+                "toml::parse_array_table_key: no `]]`",
+                {{source_location(inner_loc), "should be `]]`"}}),
+                source_location(inner_loc));
+        }
+
+        // after [[table.key]], newline or EOF(empty table) required.
+        if(loc.iter() != loc.end())
+        {
+            using lex_newline_after_table_key =
+                sequence<maybe<lex_ws>, maybe<lex_comment>, lex_newline>;
+            const auto nl = lex_newline_after_table_key::invoke(loc);
+            if(!nl)
+            {
+                throw syntax_error(format_underline("toml::"
+                    "parse_array_table_key: newline required after [[table.key]]",
+                    {{source_location(loc), "expected newline"}}),
+                    source_location(loc));
+            }
+        }
+        return ok(std::make_pair(keys.unwrap().first, token.unwrap()));
+    }
+    else
+    {
+        return err(format_underline("toml::parse_array_table_key: "
+            "not a valid table key", {{source_location(loc), "here"}}));
+    }
+}
+
+// parse table body (key-value pairs until the iter hits the next [tablekey])
+template<typename Value>
+result<typename Value::table_type, std::string>
+parse_ml_table(location& loc)
+{
+    using value_type = Value;
+    using table_type = typename value_type::table_type;
+
+    const auto first = loc.iter();
+    if(first == loc.end())
+    {
+        return ok(table_type{});
+    }
+
+    // XXX at lest one newline is needed.
+    using skip_line = repeat<
+        sequence<maybe<lex_ws>, maybe<lex_comment>, lex_newline>, at_least<1>>;
+    skip_line::invoke(loc);
+    lex_ws::invoke(loc);
+
+    table_type tab;
+    while(loc.iter() != loc.end())
+    {
+        lex_ws::invoke(loc);
+        const auto before = loc.iter();
+        if(const auto tmp = parse_array_table_key(loc)) // next table found
+        {
+            loc.reset(before);
+            return ok(tab);
+        }
+        if(const auto tmp = parse_table_key(loc)) // next table found
+        {
+            loc.reset(before);
+            return ok(tab);
+        }
+
+        if(const auto kv = parse_key_value_pair<value_type>(loc, 0))
+        {
+            const auto&              kvpair  = kv.unwrap();
+            const std::vector<key>&  keys    = kvpair.first.first;
+            const auto&              key_reg = kvpair.first.second;
+            const value_type&        val     = kvpair.second;
+            const auto inserted =
+                insert_nested_key(tab, val, keys.begin(), keys.end(), key_reg);
+            if(!inserted)
+            {
+                return err(inserted.unwrap_err());
+            }
+        }
+        else
+        {
+            return err(kv.unwrap_err());
+        }
+
+        // comment lines are skipped by the above function call.
+        // However, since the `skip_line` requires at least 1 newline, it fails
+        // if the file ends with ws and/or comment without newline.
+        // `skip_line` matches `ws? + comment? + newline`, not `ws` or `comment`
+        // itself. To skip the last ws and/or comment, call lexers.
+        // It does not matter if these fails, so the return value is discarded.
+        lex_ws::invoke(loc);
+        lex_comment::invoke(loc);
+
+        // skip_line is (whitespace? comment? newline)_{1,}. multiple empty lines
+        // and comments after the last key-value pairs are allowed.
+        const auto newline = skip_line::invoke(loc);
+        if(!newline && loc.iter() != loc.end())
+        {
+            const auto before2 = loc.iter();
+            lex_ws::invoke(loc); // skip whitespace
+            const auto msg = format_underline("toml::parse_table: "
+                "invalid line format", {{source_location(loc), concat_to_string(
+                "expected newline, but got '", show_char(*loc.iter()), "'.")}});
+            loc.reset(before2);
+            return err(msg);
+        }
+
+        // the skip_lines only matches with lines that includes newline.
+        // to skip the last line that includes comment and/or whitespace
+        // but no newline, call them one more time.
+        lex_ws::invoke(loc);
+        lex_comment::invoke(loc);
+    }
+    return ok(tab);
+}
+
+template<typename Value>
+result<Value, std::string> parse_toml_file(location& loc)
+{
+    using value_type = Value;
+    using table_type = typename value_type::table_type;
+
+    const auto first = loc.iter();
+    if(first == loc.end())
+    {
+        // For empty files, return an empty table with an empty region (zero-length).
+        // Without the region, error messages would miss the filename.
+        return ok(value_type(table_type{}, region(loc, first, first), {}));
+    }
+
+    // put the first line as a region of a file
+    // Here first != loc.end(), so taking std::next is okay
+    const region file(loc, first, std::next(loc.iter()));
+
+    // The first successive comments that are separated from the first value
+    // by an empty line are for a file itself.
+    // ```toml
+    // # this is a comment for a file.
+    //
+    // key = "the first value"
+    // ```
+    // ```toml
+    // # this is a comment for "the first value".
+    // key = "the first value"
+    // ```
+    std::vector<std::string> comments;
+    using lex_first_comments = sequence<
+        repeat<sequence<maybe<lex_ws>, lex_comment, lex_newline>, at_least<1>>,
+        sequence<maybe<lex_ws>, lex_newline>
+        >;
+    if(const auto token = lex_first_comments::invoke(loc))
+    {
+        location inner_loc(loc.name(), token.unwrap().str());
+        while(inner_loc.iter() != inner_loc.end())
+        {
+            maybe<lex_ws>::invoke(inner_loc); // remove ws if exists
+            if(lex_newline::invoke(inner_loc))
+            {
+                assert(inner_loc.iter() == inner_loc.end());
+                break; // empty line found.
+            }
+            auto com = lex_comment::invoke(inner_loc).unwrap().str();
+            com.erase(com.begin()); // remove # sign
+            comments.push_back(std::move(com));
+            lex_newline::invoke(inner_loc);
+        }
+    }
+
+    table_type data;
+    // root object is also a table, but without [tablename]
+    if(const auto tab = parse_ml_table<value_type>(loc))
+    {
+        data = std::move(tab.unwrap());
+    }
+    else // failed (empty table is regarded as success in parse_ml_table)
+    {
+        return err(tab.unwrap_err());
+    }
+    while(loc.iter() != loc.end())
+    {
+        // here, the region of [table] is regarded as the table-key because
+        // the table body is normally too big and it is not so informative
+        // if the first key-value pair of the table is shown in the error
+        // message.
+        if(const auto tabkey = parse_array_table_key(loc))
+        {
+            const auto tab = parse_ml_table<value_type>(loc);
+            if(!tab){return err(tab.unwrap_err());}
+
+            const auto& tk   = tabkey.unwrap();
+            const auto& keys = tk.first;
+            const auto& reg  = tk.second;
+
+            const auto inserted = insert_nested_key(data,
+                    value_type(tab.unwrap(), reg, reg.comments()),
+                    keys.begin(), keys.end(), reg,
+                    /*is_array_of_table=*/ true);
+            if(!inserted) {return err(inserted.unwrap_err());}
+
+            continue;
+        }
+        if(const auto tabkey = parse_table_key(loc))
+        {
+            const auto tab = parse_ml_table<value_type>(loc);
+            if(!tab){return err(tab.unwrap_err());}
+
+            const auto& tk   = tabkey.unwrap();
+            const auto& keys = tk.first;
+            const auto& reg  = tk.second;
+
+            const auto inserted = insert_nested_key(data,
+                value_type(tab.unwrap(), reg, reg.comments()),
+                keys.begin(), keys.end(), reg);
+            if(!inserted) {return err(inserted.unwrap_err());}
+
+            continue;
+        }
+        return err(format_underline("toml::parse_toml_file: "
+            "unknown line appeared", {{source_location(loc), "unknown format"}}));
+    }
+
+    return ok(Value(std::move(data), file, comments));
+}
+
+template<typename                     Comment = TOML11_DEFAULT_COMMENT_STRATEGY,
+         template<typename ...> class Table   = std::unordered_map,
+         template<typename ...> class Array   = std::vector>
+basic_value<Comment, Table, Array>
+parse(std::vector<char>& letters, const std::string& fname)
+{
+    using value_type = basic_value<Comment, Table, Array>;
+
+    // append LF.
+    // Although TOML does not require LF at the EOF, to make parsing logic
+    // simpler, we "normalize" the content by adding LF if it does not exist.
+    // It also checks if the last char is CR, to avoid changing the meaning.
+    // This is not the *best* way to deal with the last character, but is a
+    // simple and quick fix.
+    if(!letters.empty() && letters.back() != '\n' && letters.back() != '\r')
+    {
+        letters.push_back('\n');
+    }
+
+    detail::location loc(std::move(fname), std::move(letters));
+
+    // skip BOM if exists.
+    // XXX component of BOM (like 0xEF) exceeds the representable range of
+    // signed char, so on some (actually, most) of the environment, these cannot
+    // be compared to char. However, since we are always out of luck, we need to
+    // check our chars are equivalent to BOM. To do this, first we need to
+    // convert char to unsigned char to guarantee the comparability.
+    if(loc.source()->size() >= 3)
+    {
+        std::array<unsigned char, 3> BOM;
+        std::memcpy(BOM.data(), loc.source()->data(), 3);
+        if(BOM[0] == 0xEF && BOM[1] == 0xBB && BOM[2] == 0xBF)
+        {
+            loc.advance(3); // BOM found. skip.
+        }
+    }
+
+    if (auto data = detail::parse_toml_file<value_type>(loc))
+    {
+        return std::move(data).unwrap();
+    }
+    else
+    {
+        throw syntax_error(std::move(data).unwrap_err(), source_location(loc));
+    }
+}
+
+} // detail
+
+template<typename                     Comment = TOML11_DEFAULT_COMMENT_STRATEGY,
+         template<typename ...> class Table   = std::unordered_map,
+         template<typename ...> class Array   = std::vector>
+basic_value<Comment, Table, Array>
+parse(FILE * file, const std::string& fname)
+{
+    const long beg = std::ftell(file);
+    if (beg == -1l)
+    {
+        throw file_io_error(errno, "Failed to access", fname);
+    }
+
+    const int res_seekend = std::fseek(file, 0, SEEK_END);
+    if (res_seekend != 0)
+    {
+        throw file_io_error(errno, "Failed to seek", fname);
+    }
+
+    const long end = std::ftell(file);
+    if (end == -1l)
+    {
+        throw file_io_error(errno, "Failed to access", fname);
+    }
+
+    const auto fsize = end - beg;
+
+    const auto res_seekbeg = std::fseek(file, beg, SEEK_SET);
+    if (res_seekbeg != 0)
+    {
+        throw file_io_error(errno, "Failed to seek", fname);
+    }
+
+    // read whole file as a sequence of char
+    assert(fsize >= 0);
+    std::vector<char> letters(static_cast<std::size_t>(fsize));
+    std::fread(letters.data(), sizeof(char), static_cast<std::size_t>(fsize), file);
+
+    return detail::parse<Comment, Table, Array>(letters, fname);
+}
+
+template<typename                     Comment = TOML11_DEFAULT_COMMENT_STRATEGY,
+         template<typename ...> class Table   = std::unordered_map,
+         template<typename ...> class Array   = std::vector>
+basic_value<Comment, Table, Array>
+parse(std::istream& is, std::string fname = "unknown file")
+{
+    const auto beg = is.tellg();
+    is.seekg(0, std::ios::end);
+    const auto end = is.tellg();
+    const auto fsize = end - beg;
+    is.seekg(beg);
+
+    // read whole file as a sequence of char
+    assert(fsize >= 0);
+    std::vector<char> letters(static_cast<std::size_t>(fsize));
+    is.read(letters.data(), fsize);
+
+    return detail::parse<Comment, Table, Array>(letters, fname);
+}
+
+template<typename                     Comment = TOML11_DEFAULT_COMMENT_STRATEGY,
+         template<typename ...> class Table   = std::unordered_map,
+         template<typename ...> class Array   = std::vector>
+basic_value<Comment, Table, Array> parse(std::string fname)
+{
+    std::ifstream ifs(fname, std::ios_base::binary);
+    if(!ifs.good())
+    {
+        throw std::ios_base::failure(
+                "toml::parse: Error opening file \"" + fname + "\"");
+    }
+    ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
+    return parse<Comment, Table, Array>(ifs, std::move(fname));
+}
+
+#ifdef TOML11_HAS_STD_FILESYSTEM
+// This function just forwards `parse("filename.toml")` to std::string version
+// to avoid the ambiguity in overload resolution.
+//
+// Both std::string and std::filesystem::path are convertible from const char*.
+// Without this, both parse(std::string) and parse(std::filesystem::path)
+// matches to parse("filename.toml"). This breaks the existing code.
+//
+// This function exactly matches to the invocation with c-string.
+// So this function is preferred than others and the ambiguity disappears.
+template<typename                     Comment = TOML11_DEFAULT_COMMENT_STRATEGY,
+         template<typename ...> class Table   = std::unordered_map,
+         template<typename ...> class Array   = std::vector>
+basic_value<Comment, Table, Array> parse(const char* fname)
+{
+    return parse<Comment, Table, Array>(std::string(fname));
+}
+
+template<typename                     Comment = TOML11_DEFAULT_COMMENT_STRATEGY,
+         template<typename ...> class Table   = std::unordered_map,
+         template<typename ...> class Array   = std::vector>
+basic_value<Comment, Table, Array> parse(const std::filesystem::path& fpath)
+{
+    std::ifstream ifs(fpath, std::ios_base::binary);
+    if(!ifs.good())
+    {
+        throw std::ios_base::failure(
+                "toml::parse: Error opening file \"" + fpath.string() + "\"");
+    }
+    ifs.exceptions(std::ifstream::failbit | std::ifstream::badbit);
+    return parse<Comment, Table, Array>(ifs, fpath.string());
+}
+#endif // TOML11_HAS_STD_FILESYSTEM
+
+} // toml
+#endif// TOML11_PARSER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/region.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,416 @@
+//     Copyright Toru Niina 2017.
+// Distributed under the MIT License.
+#ifndef TOML11_REGION_HPP
+#define TOML11_REGION_HPP
+#include <memory>
+#include <vector>
+#include <algorithm>
+#include <initializer_list>
+#include <iterator>
+#include <iomanip>
+#include <cassert>
+#include "color.hpp"
+
+namespace toml
+{
+namespace detail
+{
+
+// helper function to avoid std::string(0, 'c') or std::string(iter, iter)
+template<typename Iterator>
+std::string make_string(Iterator first, Iterator last)
+{
+    if(first == last) {return "";}
+    return std::string(first, last);
+}
+inline std::string make_string(std::size_t len, char c)
+{
+    if(len == 0) {return "";}
+    return std::string(len, c);
+}
+
+// region_base is a base class of location and region that are defined below.
+// it will be used to generate better error messages.
+struct region_base
+{
+    region_base() = default;
+    virtual ~region_base() = default;
+    region_base(const region_base&) = default;
+    region_base(region_base&&     ) = default;
+    region_base& operator=(const region_base&) = default;
+    region_base& operator=(region_base&&     ) = default;
+
+    virtual bool is_ok()           const noexcept {return false;}
+    virtual char front()           const noexcept {return '\0';}
+
+    virtual std::string str()      const {return std::string("unknown region");}
+    virtual std::string name()     const {return std::string("unknown file");}
+    virtual std::string line()     const {return std::string("unknown line");}
+    virtual std::string line_num() const {return std::string("?");}
+
+    // length of the region
+    virtual std::size_t size()     const noexcept {return 0;}
+    // number of characters in the line before the region
+    virtual std::size_t before()   const noexcept {return 0;}
+    // number of characters in the line after the region
+    virtual std::size_t after()    const noexcept {return 0;}
+
+    virtual std::vector<std::string> comments() const {return {};}
+    // ```toml
+    // # comment_before
+    // key = "value" # comment_inline
+    // ```
+};
+
+// location represents a position in a container, which contains a file content.
+// it can be considered as a region that contains only one character.
+//
+// it contains pointer to the file content and iterator that points the current
+// location.
+struct location final : public region_base
+{
+    using const_iterator  = typename std::vector<char>::const_iterator;
+    using difference_type = typename std::iterator_traits<const_iterator>::difference_type;
+    using source_ptr      = std::shared_ptr<const std::vector<char>>;
+
+    location(std::string source_name, std::vector<char> cont)
+      : source_(std::make_shared<std::vector<char>>(std::move(cont))),
+        line_number_(1), source_name_(std::move(source_name)), iter_(source_->cbegin())
+    {}
+    location(std::string source_name, const std::string& cont)
+      : source_(std::make_shared<std::vector<char>>(cont.begin(), cont.end())),
+        line_number_(1), source_name_(std::move(source_name)), iter_(source_->cbegin())
+    {}
+
+    location(const location&) = default;
+    location(location&&)      = default;
+    location& operator=(const location&) = default;
+    location& operator=(location&&)      = default;
+    ~location() = default;
+
+    bool is_ok() const noexcept override {return static_cast<bool>(source_);}
+    char front() const noexcept override {return *iter_;}
+
+    // this const prohibits codes like `++(loc.iter())`.
+    std::add_const<const_iterator>::type iter()  const noexcept {return iter_;}
+
+    const_iterator begin() const noexcept {return source_->cbegin();}
+    const_iterator end()   const noexcept {return source_->cend();}
+
+    // XXX `location::line_num()` used to be implemented using `std::count` to
+    // count a number of '\n'. But with a long toml file (typically, 10k lines),
+    // it becomes intolerably slow because each time it generates error messages,
+    // it counts '\n' from thousands of characters. To workaround it, I decided
+    // to introduce `location::line_number_` member variable and synchronize it
+    // to the location changes the point to look. So an overload of `iter()`
+    // which returns mutable reference is removed and `advance()`, `retrace()`
+    // and `reset()` is added.
+    void advance(difference_type n = 1) noexcept
+    {
+        this->line_number_ += static_cast<std::size_t>(
+                std::count(this->iter_, std::next(this->iter_, n), '\n'));
+        this->iter_ += n;
+        return;
+    }
+    void retrace(difference_type n = 1) noexcept
+    {
+        this->line_number_ -= static_cast<std::size_t>(
+                std::count(std::prev(this->iter_, n), this->iter_, '\n'));
+        this->iter_ -= n;
+        return;
+    }
+    void reset(const_iterator rollback) noexcept
+    {
+        // since c++11, std::distance works in both ways for random-access
+        // iterators and returns a negative value if `first > last`.
+        if(0 <= std::distance(rollback, this->iter_)) // rollback < iter
+        {
+            this->line_number_ -= static_cast<std::size_t>(
+                    std::count(rollback, this->iter_, '\n'));
+        }
+        else // iter < rollback [[unlikely]]
+        {
+            this->line_number_ += static_cast<std::size_t>(
+                    std::count(this->iter_, rollback, '\n'));
+        }
+        this->iter_ = rollback;
+        return;
+    }
+
+    std::string str()  const override {return make_string(1, *this->iter());}
+    std::string name() const override {return source_name_;}
+
+    std::string line_num() const override
+    {
+        return std::to_string(this->line_number_);
+    }
+
+    std::string line() const override
+    {
+        return make_string(this->line_begin(), this->line_end());
+    }
+
+    const_iterator line_begin() const noexcept
+    {
+        using reverse_iterator = std::reverse_iterator<const_iterator>;
+        return std::find(reverse_iterator(this->iter()),
+                         reverse_iterator(this->begin()), '\n').base();
+    }
+    const_iterator line_end() const noexcept
+    {
+        return std::find(this->iter(), this->end(), '\n');
+    }
+
+    // location is always points a character. so the size is 1.
+    std::size_t size() const noexcept override
+    {
+        return 1u;
+    }
+    std::size_t before() const noexcept override
+    {
+        const auto sz = std::distance(this->line_begin(), this->iter());
+        assert(sz >= 0);
+        return static_cast<std::size_t>(sz);
+    }
+    std::size_t after() const noexcept override
+    {
+        const auto sz = std::distance(this->iter(), this->line_end());
+        assert(sz >= 0);
+        return static_cast<std::size_t>(sz);
+    }
+
+    source_ptr const& source() const& noexcept {return source_;}
+    source_ptr&&      source() &&     noexcept {return std::move(source_);}
+
+  private:
+
+    source_ptr     source_;
+    std::size_t    line_number_;
+    std::string    source_name_;
+    const_iterator iter_;
+};
+
+// region represents a range in a container, which contains a file content.
+//
+// it contains pointer to the file content and iterator that points the first
+// and last location.
+struct region final : public region_base
+{
+    using const_iterator = typename std::vector<char>::const_iterator;
+    using source_ptr     = std::shared_ptr<const std::vector<char>>;
+
+    // delete default constructor. source_ never be null.
+    region() = delete;
+
+    explicit region(const location& loc)
+      : source_(loc.source()), source_name_(loc.name()),
+        first_(loc.iter()), last_(loc.iter())
+    {}
+    explicit region(location&& loc)
+      : source_(loc.source()), source_name_(loc.name()),
+        first_(loc.iter()), last_(loc.iter())
+    {}
+
+    region(const location& loc, const_iterator f, const_iterator l)
+      : source_(loc.source()), source_name_(loc.name()), first_(f), last_(l)
+    {}
+    region(location&& loc, const_iterator f, const_iterator l)
+      : source_(loc.source()), source_name_(loc.name()), first_(f), last_(l)
+    {}
+
+    region(const region&) = default;
+    region(region&&)      = default;
+    region& operator=(const region&) = default;
+    region& operator=(region&&)      = default;
+    ~region() = default;
+
+    region& operator+=(const region& other)
+    {
+        // different regions cannot be concatenated
+        assert(this->source_ == other.source_ && this->last_ == other.first_);
+
+        this->last_ = other.last_;
+        return *this;
+    }
+
+    bool is_ok() const noexcept override {return static_cast<bool>(source_);}
+    char front() const noexcept override {return *first_;}
+
+    std::string str()  const override {return make_string(first_, last_);}
+    std::string line() const override
+    {
+        if(this->contain_newline())
+        {
+            return make_string(this->line_begin(),
+                    std::find(this->line_begin(), this->last(), '\n'));
+        }
+        return make_string(this->line_begin(), this->line_end());
+    }
+    std::string line_num() const override
+    {
+        return std::to_string(1 + std::count(this->begin(), this->first(), '\n'));
+    }
+
+    std::size_t size() const noexcept override
+    {
+        const auto sz = std::distance(first_, last_);
+        assert(sz >= 0);
+        return static_cast<std::size_t>(sz);
+    }
+    std::size_t before() const noexcept override
+    {
+        const auto sz = std::distance(this->line_begin(), this->first());
+        assert(sz >= 0);
+        return static_cast<std::size_t>(sz);
+    }
+    std::size_t after() const noexcept override
+    {
+        const auto sz = std::distance(this->last(), this->line_end());
+        assert(sz >= 0);
+        return static_cast<std::size_t>(sz);
+    }
+
+    bool contain_newline() const noexcept
+    {
+        return std::find(this->first(), this->last(), '\n') != this->last();
+    }
+
+    const_iterator line_begin() const noexcept
+    {
+        using reverse_iterator = std::reverse_iterator<const_iterator>;
+        return std::find(reverse_iterator(this->first()),
+                         reverse_iterator(this->begin()), '\n').base();
+    }
+    const_iterator line_end() const noexcept
+    {
+        return std::find(this->last(), this->end(), '\n');
+    }
+
+    const_iterator begin() const noexcept {return source_->cbegin();}
+    const_iterator end()   const noexcept {return source_->cend();}
+    const_iterator first() const noexcept {return first_;}
+    const_iterator last()  const noexcept {return last_;}
+
+    source_ptr const& source() const& noexcept {return source_;}
+    source_ptr&&      source() &&     noexcept {return std::move(source_);}
+
+    std::string name() const override {return source_name_;}
+
+    std::vector<std::string> comments() const override
+    {
+        // assuming the current region (`*this`) points a value.
+        // ```toml
+        // a = "value"
+        //     ^^^^^^^- this region
+        // ```
+        using rev_iter = std::reverse_iterator<const_iterator>;
+
+        std::vector<std::string> com{};
+        {
+            // find comments just before the current region.
+            // ```toml
+            // # this should be collected.
+            // # this also.
+            // a = value # not this.
+            // ```
+
+            // # this is a comment for `a`, not array elements.
+            // a = [1, 2, 3, 4, 5]
+            if(this->first() == std::find_if(this->line_begin(), this->first(),
+                [](const char c) noexcept -> bool {return c == '[' || c == '{';}))
+            {
+                auto iter = this->line_begin(); // points the first character
+                while(iter != this->begin())
+                {
+                    iter = std::prev(iter);
+
+                    // range [line_start, iter) represents the previous line
+                    const auto line_start   = std::find(
+                            rev_iter(iter), rev_iter(this->begin()), '\n').base();
+                    const auto comment_found = std::find(line_start, iter, '#');
+                    if(comment_found == iter)
+                    {
+                        break; // comment not found.
+                    }
+
+                    // exclude the following case.
+                    // > a = "foo" # comment // <-- this is not a comment for b but a.
+                    // > b = "current value"
+                    if(std::all_of(line_start, comment_found,
+                            [](const char c) noexcept -> bool {
+                                return c == ' ' || c == '\t';
+                            }))
+                    {
+                        // unwrap the first '#' by std::next.
+                        auto s = make_string(std::next(comment_found), iter);
+                        if(!s.empty() && s.back() == '\r') {s.pop_back();}
+                        com.push_back(std::move(s));
+                    }
+                    else
+                    {
+                        break;
+                    }
+                    iter = line_start;
+                }
+            }
+        }
+
+        if(com.size() > 1)
+        {
+            std::reverse(com.begin(), com.end());
+        }
+
+        {
+            // find comments just after the current region.
+            // ```toml
+            // # not this.
+            // a = value # this one.
+            // a = [ # not this (technically difficult)
+            //
+            // ] # and this.
+            // ```
+            // The reason why it's difficult is that it requires parsing in the
+            // following case.
+            // ```toml
+            // a = [ 10 # this comment is for `10`. not for `a` but `a[0]`.
+            // # ...
+            // ] # this is apparently a comment for a.
+            //
+            // b = [
+            // 3.14 ] # there is no way to add a comment to `3.14` currently.
+            //
+            // c = [
+            //   3.14 # do this if you need a comment here.
+            // ]
+            // ```
+            const auto comment_found =
+                std::find(this->last(), this->line_end(), '#');
+            if(comment_found != this->line_end()) // '#' found
+            {
+                // table = {key = "value"} # what is this for?
+                // the above comment is not for "value", but {key="value"}.
+                if(comment_found == std::find_if(this->last(), comment_found,
+                    [](const char c) noexcept -> bool {
+                        return !(c == ' ' || c == '\t' || c == ',');
+                    }))
+                {
+                    // unwrap the first '#' by std::next.
+                    auto s = make_string(std::next(comment_found), this->line_end());
+                    if(!s.empty() && s.back() == '\r') {s.pop_back();}
+                    com.push_back(std::move(s));
+                }
+            }
+        }
+        return com;
+    }
+
+  private:
+
+    source_ptr     source_;
+    std::string    source_name_;
+    const_iterator first_, last_;
+};
+
+} // detail
+} // toml
+#endif// TOML11_REGION_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/result.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,717 @@
+//     Copyright Toru Niina 2017.
+// Distributed under the MIT License.
+#ifndef TOML11_RESULT_HPP
+#define TOML11_RESULT_HPP
+#include "traits.hpp"
+#include <type_traits>
+#include <stdexcept>
+#include <utility>
+#include <new>
+#include <string>
+#include <sstream>
+#include <cassert>
+
+namespace toml
+{
+
+template<typename T>
+struct success
+{
+    using value_type = T;
+    value_type value;
+
+    explicit success(const value_type& v)
+        noexcept(std::is_nothrow_copy_constructible<value_type>::value)
+        : value(v)
+    {}
+    explicit success(value_type&& v)
+        noexcept(std::is_nothrow_move_constructible<value_type>::value)
+        : value(std::move(v))
+    {}
+
+    template<typename U>
+    explicit success(U&& v): value(std::forward<U>(v)) {}
+
+    template<typename U>
+    explicit success(const success<U>& v): value(v.value) {}
+    template<typename U>
+    explicit success(success<U>&& v): value(std::move(v.value)) {}
+
+    ~success() = default;
+    success(const success&) = default;
+    success(success&&)      = default;
+    success& operator=(const success&) = default;
+    success& operator=(success&&)      = default;
+};
+
+template<typename T>
+struct failure
+{
+    using value_type = T;
+    value_type value;
+
+    explicit failure(const value_type& v)
+        noexcept(std::is_nothrow_copy_constructible<value_type>::value)
+        : value(v)
+    {}
+    explicit failure(value_type&& v)
+        noexcept(std::is_nothrow_move_constructible<value_type>::value)
+        : value(std::move(v))
+    {}
+
+    template<typename U>
+    explicit failure(U&& v): value(std::forward<U>(v)) {}
+
+    template<typename U>
+    explicit failure(const failure<U>& v): value(v.value) {}
+    template<typename U>
+    explicit failure(failure<U>&& v): value(std::move(v.value)) {}
+
+    ~failure() = default;
+    failure(const failure&) = default;
+    failure(failure&&)      = default;
+    failure& operator=(const failure&) = default;
+    failure& operator=(failure&&)      = default;
+};
+
+template<typename T>
+success<typename std::remove_cv<typename std::remove_reference<T>::type>::type>
+ok(T&& v)
+{
+    return success<
+        typename std::remove_cv<typename std::remove_reference<T>::type>::type
+        >(std::forward<T>(v));
+}
+template<typename T>
+failure<typename std::remove_cv<typename std::remove_reference<T>::type>::type>
+err(T&& v)
+{
+    return failure<
+        typename std::remove_cv<typename std::remove_reference<T>::type>::type
+        >(std::forward<T>(v));
+}
+
+inline success<std::string> ok(const char* literal)
+{
+    return success<std::string>(std::string(literal));
+}
+inline failure<std::string> err(const char* literal)
+{
+    return failure<std::string>(std::string(literal));
+}
+
+
+template<typename T, typename E>
+struct result
+{
+    using value_type = T;
+    using error_type = E;
+    using success_type = success<value_type>;
+    using failure_type = failure<error_type>;
+
+    result(const success_type& s): is_ok_(true)
+    {
+        auto tmp = ::new(std::addressof(this->succ)) success_type(s);
+        assert(tmp == std::addressof(this->succ));
+        (void)tmp;
+    }
+    result(const failure_type& f): is_ok_(false)
+    {
+        auto tmp = ::new(std::addressof(this->fail)) failure_type(f);
+        assert(tmp == std::addressof(this->fail));
+        (void)tmp;
+    }
+    result(success_type&& s): is_ok_(true)
+    {
+        auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s));
+        assert(tmp == std::addressof(this->succ));
+        (void)tmp;
+    }
+    result(failure_type&& f): is_ok_(false)
+    {
+        auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f));
+        assert(tmp == std::addressof(this->fail));
+        (void)tmp;
+    }
+
+    template<typename U>
+    result(const success<U>& s): is_ok_(true)
+    {
+        auto tmp = ::new(std::addressof(this->succ)) success_type(s.value);
+        assert(tmp == std::addressof(this->succ));
+        (void)tmp;
+    }
+    template<typename U>
+    result(const failure<U>& f): is_ok_(false)
+    {
+        auto tmp = ::new(std::addressof(this->fail)) failure_type(f.value);
+        assert(tmp == std::addressof(this->fail));
+        (void)tmp;
+    }
+    template<typename U>
+    result(success<U>&& s): is_ok_(true)
+    {
+        auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s.value));
+        assert(tmp == std::addressof(this->succ));
+        (void)tmp;
+    }
+    template<typename U>
+    result(failure<U>&& f): is_ok_(false)
+    {
+        auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f.value));
+        assert(tmp == std::addressof(this->fail));
+        (void)tmp;
+    }
+
+    result& operator=(const success_type& s)
+    {
+        this->cleanup();
+        this->is_ok_ = true;
+        auto tmp = ::new(std::addressof(this->succ)) success_type(s);
+        assert(tmp == std::addressof(this->succ));
+        (void)tmp;
+        return *this;
+    }
+    result& operator=(const failure_type& f)
+    {
+        this->cleanup();
+        this->is_ok_ = false;
+        auto tmp = ::new(std::addressof(this->fail)) failure_type(f);
+        assert(tmp == std::addressof(this->fail));
+        (void)tmp;
+        return *this;
+    }
+    result& operator=(success_type&& s)
+    {
+        this->cleanup();
+        this->is_ok_ = true;
+        auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s));
+        assert(tmp == std::addressof(this->succ));
+        (void)tmp;
+        return *this;
+    }
+    result& operator=(failure_type&& f)
+    {
+        this->cleanup();
+        this->is_ok_ = false;
+        auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f));
+        assert(tmp == std::addressof(this->fail));
+        (void)tmp;
+        return *this;
+    }
+
+    template<typename U>
+    result& operator=(const success<U>& s)
+    {
+        this->cleanup();
+        this->is_ok_ = true;
+        auto tmp = ::new(std::addressof(this->succ)) success_type(s.value);
+        assert(tmp == std::addressof(this->succ));
+        (void)tmp;
+        return *this;
+    }
+    template<typename U>
+    result& operator=(const failure<U>& f)
+    {
+        this->cleanup();
+        this->is_ok_ = false;
+        auto tmp = ::new(std::addressof(this->fail)) failure_type(f.value);
+        assert(tmp == std::addressof(this->fail));
+        (void)tmp;
+        return *this;
+    }
+    template<typename U>
+    result& operator=(success<U>&& s)
+    {
+        this->cleanup();
+        this->is_ok_ = true;
+        auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(s.value));
+        assert(tmp == std::addressof(this->succ));
+        (void)tmp;
+        return *this;
+    }
+    template<typename U>
+    result& operator=(failure<U>&& f)
+    {
+        this->cleanup();
+        this->is_ok_ = false;
+        auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(f.value));
+        assert(tmp == std::addressof(this->fail));
+        (void)tmp;
+        return *this;
+    }
+
+    ~result() noexcept {this->cleanup();}
+
+    result(const result& other): is_ok_(other.is_ok())
+    {
+        if(other.is_ok())
+        {
+            auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
+            assert(tmp == std::addressof(this->succ));
+            (void)tmp;
+        }
+        else
+        {
+            auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
+            assert(tmp == std::addressof(this->fail));
+            (void)tmp;
+        }
+    }
+    result(result&& other): is_ok_(other.is_ok())
+    {
+        if(other.is_ok())
+        {
+            auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
+            assert(tmp == std::addressof(this->succ));
+            (void)tmp;
+        }
+        else
+        {
+            auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
+            assert(tmp == std::addressof(this->fail));
+            (void)tmp;
+        }
+    }
+
+    template<typename U, typename F>
+    result(const result<U, F>& other): is_ok_(other.is_ok())
+    {
+        if(other.is_ok())
+        {
+            auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
+            assert(tmp == std::addressof(this->succ));
+            (void)tmp;
+        }
+        else
+        {
+            auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
+            assert(tmp == std::addressof(this->fail));
+            (void)tmp;
+        }
+    }
+    template<typename U, typename F>
+    result(result<U, F>&& other): is_ok_(other.is_ok())
+    {
+        if(other.is_ok())
+        {
+            auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
+            assert(tmp == std::addressof(this->succ));
+            (void)tmp;
+        }
+        else
+        {
+            auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
+            assert(tmp == std::addressof(this->fail));
+            (void)tmp;
+        }
+    }
+
+    result& operator=(const result& other)
+    {
+        this->cleanup();
+        if(other.is_ok())
+        {
+            auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
+            assert(tmp == std::addressof(this->succ));
+            (void)tmp;
+        }
+        else
+        {
+            auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
+            assert(tmp == std::addressof(this->fail));
+            (void)tmp;
+        }
+        is_ok_ = other.is_ok();
+        return *this;
+    }
+    result& operator=(result&& other)
+    {
+        this->cleanup();
+        if(other.is_ok())
+        {
+            auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
+            assert(tmp == std::addressof(this->succ));
+            (void)tmp;
+        }
+        else
+        {
+            auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
+            assert(tmp == std::addressof(this->fail));
+            (void)tmp;
+        }
+        is_ok_ = other.is_ok();
+        return *this;
+    }
+
+    template<typename U, typename F>
+    result& operator=(const result<U, F>& other)
+    {
+        this->cleanup();
+        if(other.is_ok())
+        {
+            auto tmp = ::new(std::addressof(this->succ)) success_type(other.as_ok());
+            assert(tmp == std::addressof(this->succ));
+            (void)tmp;
+        }
+        else
+        {
+            auto tmp = ::new(std::addressof(this->fail)) failure_type(other.as_err());
+            assert(tmp == std::addressof(this->fail));
+            (void)tmp;
+        }
+        is_ok_ = other.is_ok();
+        return *this;
+    }
+    template<typename U, typename F>
+    result& operator=(result<U, F>&& other)
+    {
+        this->cleanup();
+        if(other.is_ok())
+        {
+            auto tmp = ::new(std::addressof(this->succ)) success_type(std::move(other.as_ok()));
+            assert(tmp == std::addressof(this->succ));
+            (void)tmp;
+        }
+        else
+        {
+            auto tmp = ::new(std::addressof(this->fail)) failure_type(std::move(other.as_err()));
+            assert(tmp == std::addressof(this->fail));
+            (void)tmp;
+        }
+        is_ok_ = other.is_ok();
+        return *this;
+    }
+
+    bool is_ok()  const noexcept {return is_ok_;}
+    bool is_err() const noexcept {return !is_ok_;}
+
+    operator bool() const noexcept {return is_ok_;}
+
+    value_type&       unwrap() &
+    {
+        if(is_err())
+        {
+            throw std::runtime_error("toml::result: bad unwrap: " +
+                                     format_error(this->as_err()));
+        }
+        return this->succ.value;
+    }
+    value_type const& unwrap() const&
+    {
+        if(is_err())
+        {
+            throw std::runtime_error("toml::result: bad unwrap: " +
+                                     format_error(this->as_err()));
+        }
+        return this->succ.value;
+    }
+    value_type&&      unwrap() &&
+    {
+        if(is_err())
+        {
+            throw std::runtime_error("toml::result: bad unwrap: " +
+                                     format_error(this->as_err()));
+        }
+        return std::move(this->succ.value);
+    }
+
+    value_type&       unwrap_or(value_type& opt) &
+    {
+        if(is_err()) {return opt;}
+        return this->succ.value;
+    }
+    value_type const& unwrap_or(value_type const& opt) const&
+    {
+        if(is_err()) {return opt;}
+        return this->succ.value;
+    }
+    value_type        unwrap_or(value_type opt) &&
+    {
+        if(is_err()) {return opt;}
+        return this->succ.value;
+    }
+
+    error_type&       unwrap_err() &
+    {
+        if(is_ok()) {throw std::runtime_error("toml::result: bad unwrap_err");}
+        return this->fail.value;
+    }
+    error_type const& unwrap_err() const&
+    {
+        if(is_ok()) {throw std::runtime_error("toml::result: bad unwrap_err");}
+        return this->fail.value;
+    }
+    error_type&&      unwrap_err() &&
+    {
+        if(is_ok()) {throw std::runtime_error("toml::result: bad unwrap_err");}
+        return std::move(this->fail.value);
+    }
+
+    value_type&       as_ok() &      noexcept {return this->succ.value;}
+    value_type const& as_ok() const& noexcept {return this->succ.value;}
+    value_type&&      as_ok() &&     noexcept {return std::move(this->succ.value);}
+
+    error_type&       as_err() &      noexcept {return this->fail.value;}
+    error_type const& as_err() const& noexcept {return this->fail.value;}
+    error_type&&      as_err() &&     noexcept {return std::move(this->fail.value);}
+
+
+    // prerequisities
+    // F: T -> U
+    // retval: result<U, E>
+    template<typename F>
+    result<detail::return_type_of_t<F, value_type&>, error_type>
+    map(F&& f) &
+    {
+        if(this->is_ok()){return ok(f(this->as_ok()));}
+        return err(this->as_err());
+    }
+    template<typename F>
+    result<detail::return_type_of_t<F, value_type const&>, error_type>
+    map(F&& f) const&
+    {
+        if(this->is_ok()){return ok(f(this->as_ok()));}
+        return err(this->as_err());
+    }
+    template<typename F>
+    result<detail::return_type_of_t<F, value_type &&>, error_type>
+    map(F&& f) &&
+    {
+        if(this->is_ok()){return ok(f(std::move(this->as_ok())));}
+        return err(std::move(this->as_err()));
+    }
+
+    // prerequisities
+    // F: E -> F
+    // retval: result<T, F>
+    template<typename F>
+    result<value_type, detail::return_type_of_t<F, error_type&>>
+    map_err(F&& f) &
+    {
+        if(this->is_err()){return err(f(this->as_err()));}
+        return ok(this->as_ok());
+    }
+    template<typename F>
+    result<value_type, detail::return_type_of_t<F, error_type const&>>
+    map_err(F&& f) const&
+    {
+        if(this->is_err()){return err(f(this->as_err()));}
+        return ok(this->as_ok());
+    }
+    template<typename F>
+    result<value_type, detail::return_type_of_t<F, error_type&&>>
+    map_err(F&& f) &&
+    {
+        if(this->is_err()){return err(f(std::move(this->as_err())));}
+        return ok(std::move(this->as_ok()));
+    }
+
+    // prerequisities
+    // F: T -> U
+    // retval: U
+    template<typename F, typename U>
+    detail::return_type_of_t<F, value_type&>
+    map_or_else(F&& f, U&& opt) &
+    {
+        if(this->is_err()){return std::forward<U>(opt);}
+        return f(this->as_ok());
+    }
+    template<typename F, typename U>
+    detail::return_type_of_t<F, value_type const&>
+    map_or_else(F&& f, U&& opt) const&
+    {
+        if(this->is_err()){return std::forward<U>(opt);}
+        return f(this->as_ok());
+    }
+    template<typename F, typename U>
+    detail::return_type_of_t<F, value_type&&>
+    map_or_else(F&& f, U&& opt) &&
+    {
+        if(this->is_err()){return std::forward<U>(opt);}
+        return f(std::move(this->as_ok()));
+    }
+
+    // prerequisities
+    // F: E -> U
+    // retval: U
+    template<typename F, typename U>
+    detail::return_type_of_t<F, error_type&>
+    map_err_or_else(F&& f, U&& opt) &
+    {
+        if(this->is_ok()){return std::forward<U>(opt);}
+        return f(this->as_err());
+    }
+    template<typename F, typename U>
+    detail::return_type_of_t<F, error_type const&>
+    map_err_or_else(F&& f, U&& opt) const&
+    {
+        if(this->is_ok()){return std::forward<U>(opt);}
+        return f(this->as_err());
+    }
+    template<typename F, typename U>
+    detail::return_type_of_t<F, error_type&&>
+    map_err_or_else(F&& f, U&& opt) &&
+    {
+        if(this->is_ok()){return std::forward<U>(opt);}
+        return f(std::move(this->as_err()));
+    }
+
+    // prerequisities:
+    // F: func T -> U
+    // toml::err(error_type) should be convertible to U.
+    // normally, type U is another result<S, F> and E is convertible to F
+    template<typename F>
+    detail::return_type_of_t<F, value_type&>
+    and_then(F&& f) &
+    {
+        if(this->is_ok()){return f(this->as_ok());}
+        return err(this->as_err());
+    }
+    template<typename F>
+    detail::return_type_of_t<F, value_type const&>
+    and_then(F&& f) const&
+    {
+        if(this->is_ok()){return f(this->as_ok());}
+        return err(this->as_err());
+    }
+    template<typename F>
+    detail::return_type_of_t<F, value_type&&>
+    and_then(F&& f) &&
+    {
+        if(this->is_ok()){return f(std::move(this->as_ok()));}
+        return err(std::move(this->as_err()));
+    }
+
+    // prerequisities:
+    // F: func E -> U
+    // toml::ok(value_type) should be convertible to U.
+    // normally, type U is another result<S, F> and T is convertible to S
+    template<typename F>
+    detail::return_type_of_t<F, error_type&>
+    or_else(F&& f) &
+    {
+        if(this->is_err()){return f(this->as_err());}
+        return ok(this->as_ok());
+    }
+    template<typename F>
+    detail::return_type_of_t<F, error_type const&>
+    or_else(F&& f) const&
+    {
+        if(this->is_err()){return f(this->as_err());}
+        return ok(this->as_ok());
+    }
+    template<typename F>
+    detail::return_type_of_t<F, error_type&&>
+    or_else(F&& f) &&
+    {
+        if(this->is_err()){return f(std::move(this->as_err()));}
+        return ok(std::move(this->as_ok()));
+    }
+
+    // if *this is error, returns *this. otherwise, returns other.
+    result and_other(const result& other) const&
+    {
+        return this->is_err() ? *this : other;
+    }
+    result and_other(result&& other) &&
+    {
+        return this->is_err() ? std::move(*this) : std::move(other);
+    }
+
+    // if *this is okay, returns *this. otherwise, returns other.
+    result or_other(const result& other) const&
+    {
+        return this->is_ok() ? *this : other;
+    }
+    result or_other(result&& other) &&
+    {
+        return this->is_ok() ? std::move(*this) : std::move(other);
+    }
+
+    void swap(result<T, E>& other)
+    {
+        result<T, E> tmp(std::move(*this));
+        *this = std::move(other);
+        other = std::move(tmp);
+        return ;
+    }
+
+  private:
+
+    static std::string format_error(std::exception const& excpt)
+    {
+        return std::string(excpt.what());
+    }
+    template<typename U, typename std::enable_if<!std::is_base_of<
+        std::exception, U>::value, std::nullptr_t>::type = nullptr>
+    static std::string format_error(U const& others)
+    {
+        std::ostringstream oss; oss << others;
+        return oss.str();
+    }
+
+    void cleanup() noexcept
+    {
+        if(this->is_ok_) {this->succ.~success_type();}
+        else             {this->fail.~failure_type();}
+        return;
+    }
+
+  private:
+
+    bool      is_ok_;
+    union
+    {
+        success_type succ;
+        failure_type fail;
+    };
+};
+
+template<typename T, typename E>
+void swap(result<T, E>& lhs, result<T, E>& rhs)
+{
+    lhs.swap(rhs);
+    return;
+}
+
+// this might be confusing because it eagerly evaluated, while in the other
+// cases operator && and || are short-circuited.
+//
+// template<typename T, typename E>
+// inline result<T, E>
+// operator&&(const result<T, E>& lhs, const result<T, E>& rhs) noexcept
+// {
+//     return lhs.is_ok() ? rhs : lhs;
+// }
+//
+// template<typename T, typename E>
+// inline result<T, E>
+// operator||(const result<T, E>& lhs, const result<T, E>& rhs) noexcept
+// {
+//     return lhs.is_ok() ? lhs : rhs;
+// }
+
+// ----------------------------------------------------------------------------
+// re-use result<T, E> as a optional<T> with none_t
+
+namespace detail
+{
+struct none_t {};
+inline bool operator==(const none_t&, const none_t&) noexcept {return true;}
+inline bool operator!=(const none_t&, const none_t&) noexcept {return false;}
+inline bool operator< (const none_t&, const none_t&) noexcept {return false;}
+inline bool operator<=(const none_t&, const none_t&) noexcept {return true;}
+inline bool operator> (const none_t&, const none_t&) noexcept {return false;}
+inline bool operator>=(const none_t&, const none_t&) noexcept {return true;}
+template<typename charT, typename traitsT>
+std::basic_ostream<charT, traitsT>&
+operator<<(std::basic_ostream<charT, traitsT>& os, const none_t&)
+{
+    os << "none";
+    return os;
+}
+inline failure<none_t> none() noexcept {return failure<none_t>{none_t{}};}
+} // detail
+} // toml11
+#endif// TOML11_RESULT_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/serializer.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,994 @@
+//     Copyright Toru Niina 2019.
+// Distributed under the MIT License.
+#ifndef TOML11_SERIALIZER_HPP
+#define TOML11_SERIALIZER_HPP
+#include <cmath>
+#include <cstdio>
+
+#include <limits>
+
+#if defined(_WIN32)
+#include <locale.h>
+#elif defined(__APPLE__) || defined(__FreeBSD__)
+#include <xlocale.h>
+#elif defined(__linux__)
+#include <locale.h>
+#endif
+
+#include "lexer.hpp"
+#include "value.hpp"
+
+namespace toml
+{
+
+// This function serialize a key. It checks a string is a bare key and
+// escapes special characters if the string is not compatible to a bare key.
+// ```cpp
+// std::string k("non.bare.key"); // the key itself includes `.`s.
+// std::string formatted = toml::format_key(k);
+// assert(formatted == "\"non.bare.key\"");
+// ```
+//
+// This function is exposed to make it easy to write a user-defined serializer.
+// Since toml restricts characters available in a bare key, generally a string
+// should be escaped. But checking whether a string needs to be surrounded by
+// a `"` and escaping some special character is boring.
+template<typename charT, typename traits, typename Alloc>
+std::basic_string<charT, traits, Alloc>
+format_key(const std::basic_string<charT, traits, Alloc>& k)
+{
+    if(k.empty())
+    {
+        return std::string("\"\"");
+    }
+
+    // check the key can be a bare (unquoted) key
+    detail::location loc(k, std::vector<char>(k.begin(), k.end()));
+    detail::lex_unquoted_key::invoke(loc);
+    if(loc.iter() == loc.end())
+    {
+        return k; // all the tokens are consumed. the key is unquoted-key.
+    }
+
+    //if it includes special characters, then format it in a "quoted" key.
+    std::basic_string<charT, traits, Alloc> serialized("\"");
+    for(const char c : k)
+    {
+        switch(c)
+        {
+            case '\\': {serialized += "\\\\"; break;}
+            case '\"': {serialized += "\\\""; break;}
+            case '\b': {serialized += "\\b";  break;}
+            case '\t': {serialized += "\\t";  break;}
+            case '\f': {serialized += "\\f";  break;}
+            case '\n': {serialized += "\\n";  break;}
+            case '\r': {serialized += "\\r";  break;}
+            default: {
+                if (c >= 0x00 && c < 0x20)
+                {
+                    std::array<char, 7> buf;
+                    std::snprintf(buf.data(), buf.size(), "\\u00%02x", static_cast<int>(c));
+                    serialized += buf.data();
+                }
+                else
+                {
+                    serialized += c;
+                }
+                break;
+            }
+        }
+    }
+    serialized += "\"";
+    return serialized;
+}
+
+template<typename charT, typename traits, typename Alloc>
+std::basic_string<charT, traits, Alloc>
+format_keys(const std::vector<std::basic_string<charT, traits, Alloc>>& keys)
+{
+    if(keys.empty())
+    {
+        return std::string("\"\"");
+    }
+
+    std::basic_string<charT, traits, Alloc> serialized;
+    for(const auto& ky : keys)
+    {
+        serialized += format_key(ky);
+        serialized += charT('.');
+    }
+    serialized.pop_back(); // remove the last dot '.'
+    return serialized;
+}
+
+template<typename Value>
+struct serializer
+{
+    static_assert(detail::is_basic_value<Value>::value,
+                  "toml::serializer is for toml::value and its variants, "
+                  "toml::basic_value<...>.");
+
+    using value_type           = Value;
+    using key_type             = typename value_type::key_type            ;
+    using comment_type         = typename value_type::comment_type        ;
+    using boolean_type         = typename value_type::boolean_type        ;
+    using integer_type         = typename value_type::integer_type        ;
+    using floating_type        = typename value_type::floating_type       ;
+    using string_type          = typename value_type::string_type         ;
+    using local_time_type      = typename value_type::local_time_type     ;
+    using local_date_type      = typename value_type::local_date_type     ;
+    using local_datetime_type  = typename value_type::local_datetime_type ;
+    using offset_datetime_type = typename value_type::offset_datetime_type;
+    using array_type           = typename value_type::array_type          ;
+    using table_type           = typename value_type::table_type          ;
+
+    serializer(const std::size_t w              = 80u,
+               const int         float_prec     = std::numeric_limits<toml::floating>::max_digits10,
+               const bool        can_be_inlined = false,
+               const bool        no_comment     = false,
+               std::vector<toml::key> ks        = {},
+               const bool     value_has_comment = false)
+        : can_be_inlined_(can_be_inlined), no_comment_(no_comment),
+          value_has_comment_(value_has_comment && !no_comment),
+          float_prec_(float_prec), width_(w), keys_(std::move(ks))
+    {}
+    ~serializer() = default;
+
+    std::string operator()(const boolean_type& b) const
+    {
+        return b ? "true" : "false";
+    }
+    std::string operator()(const integer_type i) const
+    {
+#if defined(_WIN32)
+        _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
+        const std::string original_locale(setlocale(LC_NUMERIC, nullptr));
+        setlocale(LC_NUMERIC, "C");
+#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
+        const auto c_locale = newlocale(LC_NUMERIC_MASK, "C", locale_t(0));
+        locale_t original_locale(0);
+        if(c_locale != locale_t(0))
+        {
+            original_locale = uselocale(c_locale);
+        }
+#endif
+
+        const auto str = std::to_string(i);
+
+#if defined(_WIN32)
+        setlocale(LC_NUMERIC, original_locale.c_str());
+        _configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
+#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
+        if(original_locale != locale_t(0))
+        {
+            uselocale(original_locale);
+        }
+#endif
+        return str;
+    }
+    std::string operator()(const floating_type f) const
+    {
+        if(std::isnan(f))
+        {
+            if(std::signbit(f))
+            {
+                return std::string("-nan");
+            }
+            else
+            {
+                return std::string("nan");
+            }
+        }
+        else if(!std::isfinite(f))
+        {
+            if(std::signbit(f))
+            {
+                return std::string("-inf");
+            }
+            else
+            {
+                return std::string("inf");
+            }
+        }
+
+        // set locale to "C".
+        // To make it thread-local, we use OS-specific features.
+        // If we set process-global locale, it can break other thread that also
+        // outputs something simultaneously.
+#if defined(_WIN32)
+        _configthreadlocale(_ENABLE_PER_THREAD_LOCALE);
+        const std::string original_locale(setlocale(LC_NUMERIC, nullptr));
+        setlocale(LC_NUMERIC, "C");
+#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
+        const auto c_locale = newlocale(LC_NUMERIC_MASK, "C", locale_t(0));
+        locale_t original_locale(0);
+        if(c_locale != locale_t(0))
+        {
+            original_locale = uselocale(c_locale);
+        }
+#endif
+
+        const auto fmt = "%.*g";
+        const auto bsz = std::snprintf(nullptr, 0, fmt, this->float_prec_, f);
+        // +1 for null character(\0)
+        std::vector<char> buf(static_cast<std::size_t>(bsz + 1), '\0');
+        std::snprintf(buf.data(), buf.size(), fmt, this->float_prec_, f);
+
+        // restore the original locale
+#if defined(_WIN32)
+        setlocale(LC_NUMERIC, original_locale.c_str());
+        _configthreadlocale(_DISABLE_PER_THREAD_LOCALE);
+#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__linux__)
+        if(original_locale != locale_t(0))
+        {
+            uselocale(original_locale);
+        }
+#endif
+
+        std::string token(buf.begin(), std::prev(buf.end()));
+        if(!token.empty() && token.back() == '.') // 1. => 1.0
+        {
+            token += '0';
+        }
+
+        const auto e = std::find_if(
+            token.cbegin(), token.cend(), [](const char c) noexcept -> bool {
+                return c == 'e' || c == 'E';
+            });
+        const auto has_exponent = (token.cend() != e);
+        const auto has_fraction = (token.cend() != std::find(
+            token.cbegin(), token.cend(), '.'));
+
+        if(!has_exponent && !has_fraction)
+        {
+            // the resulting value does not have any float specific part!
+            token += ".0";
+        }
+        return token;
+    }
+    std::string operator()(const string_type& s) const
+    {
+        if(s.kind == string_t::basic)
+        {
+            if((std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
+                std::find(s.str.cbegin(), s.str.cend(), '\"') != s.str.cend()) &&
+               this->width_ != (std::numeric_limits<std::size_t>::max)())
+            {
+                // if linefeed or double-quote is contained,
+                // make it multiline basic string.
+                const auto escaped = this->escape_ml_basic_string(s.str);
+                std::string open("\"\"\"");
+                std::string close("\"\"\"");
+                if(escaped.find('\n') != std::string::npos ||
+                   this->width_ < escaped.size() + 6)
+                {
+                    // if the string body contains newline or is enough long,
+                    // add newlines after and before delimiters.
+                    open += "\n";
+                    close = std::string("\\\n") + close;
+                }
+                return open + escaped + close;
+            }
+
+            // no linefeed. try to make it oneline-string.
+            std::string oneline = this->escape_basic_string(s.str);
+            if(oneline.size() + 2 < width_ || width_ < 2)
+            {
+                const std::string quote("\"");
+                return quote + oneline + quote;
+            }
+
+            // the line is too long compared to the specified width.
+            // split it into multiple lines.
+            std::string token("\"\"\"\n");
+            while(!oneline.empty())
+            {
+                if(oneline.size() < width_)
+                {
+                    token += oneline;
+                    oneline.clear();
+                }
+                else if(oneline.at(width_-2) == '\\')
+                {
+                    token += oneline.substr(0, width_-2);
+                    token += "\\\n";
+                    oneline.erase(0, width_-2);
+                }
+                else
+                {
+                    token += oneline.substr(0, width_-1);
+                    token += "\\\n";
+                    oneline.erase(0, width_-1);
+                }
+            }
+            return token + std::string("\\\n\"\"\"");
+        }
+        else // the string `s` is literal-string.
+        {
+            if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
+               std::find(s.str.cbegin(), s.str.cend(), '\'') != s.str.cend() )
+            {
+                std::string open("'''");
+                if(this->width_ + 6 < s.str.size())
+                {
+                    open += '\n'; // the first newline is ignored by TOML spec
+                }
+                const std::string close("'''");
+                return open + s.str + close;
+            }
+            else
+            {
+                const std::string quote("'");
+                return quote + s.str + quote;
+            }
+        }
+    }
+
+    std::string operator()(const local_date_type& d) const
+    {
+        std::ostringstream oss;
+        oss << d;
+        return oss.str();
+    }
+    std::string operator()(const local_time_type& t) const
+    {
+        std::ostringstream oss;
+        oss << t;
+        return oss.str();
+    }
+    std::string operator()(const local_datetime_type& dt) const
+    {
+        std::ostringstream oss;
+        oss << dt;
+        return oss.str();
+    }
+    std::string operator()(const offset_datetime_type& odt) const
+    {
+        std::ostringstream oss;
+        oss << odt;
+        return oss.str();
+    }
+
+    std::string operator()(const array_type& v) const
+    {
+        if(v.empty())
+        {
+            return std::string("[]");
+        }
+        if(this->is_array_of_tables(v))
+        {
+            return make_array_of_tables(v);
+        }
+
+        // not an array of tables. normal array.
+        // first, try to make it inline if none of the elements have a comment.
+        if( ! this->has_comment_inside(v))
+        {
+            const auto inl = this->make_inline_array(v);
+            if(inl.size() < this->width_ &&
+               std::find(inl.cbegin(), inl.cend(), '\n') == inl.cend())
+            {
+                return inl;
+            }
+        }
+
+        // if the length exceeds this->width_, print multiline array.
+        // key = [
+        //   # ...
+        //   42,
+        //   ...
+        // ]
+        std::string token;
+        std::string current_line;
+        token += "[\n";
+        for(const auto& item : v)
+        {
+            if( ! item.comments().empty() && !no_comment_)
+            {
+                // if comment exists, the element must be the only element in the line.
+                // e.g. the following is not allowed.
+                // ```toml
+                // array = [
+                // # comment for what?
+                // 1, 2, 3, 4, 5
+                // ]
+                // ```
+                if(!current_line.empty())
+                {
+                    if(current_line.back() != '\n')
+                    {
+                        current_line += '\n';
+                    }
+                    token += current_line;
+                    current_line.clear();
+                }
+                for(const auto& c : item.comments())
+                {
+                    token += '#';
+                    token += c;
+                    token += '\n';
+                }
+                token += toml::visit(*this, item);
+                if(!token.empty() && token.back() == '\n') {token.pop_back();}
+                token += ",\n";
+                continue;
+            }
+            std::string next_elem;
+            if(item.is_table())
+            {
+                serializer ser(*this);
+                ser.can_be_inlined_ = true;
+                ser.width_ = (std::numeric_limits<std::size_t>::max)();
+                next_elem += toml::visit(ser, item);
+            }
+            else
+            {
+                next_elem += toml::visit(*this, item);
+            }
+
+            // comma before newline.
+            if(!next_elem.empty() && next_elem.back() == '\n') {next_elem.pop_back();}
+
+            // if current line does not exceeds the width limit, continue.
+            if(current_line.size() + next_elem.size() + 1 < this->width_)
+            {
+                current_line += next_elem;
+                current_line += ',';
+            }
+            else if(current_line.empty())
+            {
+                // if current line was empty, force put the next_elem because
+                // next_elem is not splittable
+                token += next_elem;
+                token += ",\n";
+                // current_line is kept empty
+            }
+            else // reset current_line
+            {
+                assert(current_line.back() == ',');
+                token += current_line;
+                token += '\n';
+                current_line = next_elem;
+                current_line += ',';
+            }
+        }
+        if(!current_line.empty())
+        {
+            if(!current_line.empty() && current_line.back() != '\n')
+            {
+                current_line += '\n';
+            }
+            token += current_line;
+        }
+        token += "]\n";
+        return token;
+    }
+
+    // templatize for any table-like container
+    std::string operator()(const table_type& v) const
+    {
+        // if an element has a comment, then it can't be inlined.
+        // table = {# how can we write a comment for this? key = "value"}
+        if(this->can_be_inlined_ && !(this->has_comment_inside(v)))
+        {
+            std::string token;
+            if(!this->keys_.empty())
+            {
+                token += format_key(this->keys_.back());
+                token += " = ";
+            }
+            token += this->make_inline_table(v);
+            if(token.size() < this->width_ &&
+               token.end() == std::find(token.begin(), token.end(), '\n'))
+            {
+                return token;
+            }
+        }
+
+        std::string token;
+        if(!keys_.empty())
+        {
+            token += '[';
+            token += format_keys(keys_);
+            token += "]\n";
+        }
+        token += this->make_multiline_table(v);
+        return token;
+    }
+
+  private:
+
+    std::string escape_basic_string(const std::string& s) const
+    {
+        //XXX assuming `s` is a valid utf-8 sequence.
+        std::string retval;
+        for(const char c : s)
+        {
+            switch(c)
+            {
+                case '\\': {retval += "\\\\"; break;}
+                case '\"': {retval += "\\\""; break;}
+                case '\b': {retval += "\\b";  break;}
+                case '\t': {retval += "\\t";  break;}
+                case '\f': {retval += "\\f";  break;}
+                case '\n': {retval += "\\n";  break;}
+                case '\r': {retval += "\\r";  break;}
+                default  :
+                {
+                    if((0x00 <= c && c <= 0x08) || (0x0A <= c && c <= 0x1F) || c == 0x7F)
+                    {
+                        retval += "\\u00";
+                        retval += char(48 + (c / 16));
+                        retval += char((c % 16 < 10 ? 48 : 55) + (c % 16));
+                    }
+                    else
+                    {
+                        retval += c;
+                    }
+                }
+            }
+        }
+        return retval;
+    }
+
+    std::string escape_ml_basic_string(const std::string& s) const
+    {
+        std::string retval;
+        for(auto i=s.cbegin(), e=s.cend(); i!=e; ++i)
+        {
+            switch(*i)
+            {
+                case '\\': {retval += "\\\\"; break;}
+                // One or two consecutive "s are allowed.
+                // Later we will check there are no three consecutive "s.
+                //   case '\"': {retval += "\\\""; break;}
+                case '\b': {retval += "\\b";  break;}
+                case '\t': {retval += "\\t";  break;}
+                case '\f': {retval += "\\f";  break;}
+                case '\n': {retval += "\n";   break;}
+                case '\r':
+                {
+                    if(std::next(i) != e && *std::next(i) == '\n')
+                    {
+                        retval += "\r\n";
+                        ++i;
+                    }
+                    else
+                    {
+                        retval += "\\r";
+                    }
+                    break;
+                }
+                default  :
+                {
+                    const auto c = *i;
+                    if((0x00 <= c && c <= 0x08) || (0x0A <= c && c <= 0x1F) || c == 0x7F)
+                    {
+                        retval += "\\u00";
+                        retval += char(48 + (c / 16));
+                        retval += char((c % 16 < 10 ? 48 : 55) + (c % 16));
+                    }
+                    else
+                    {
+                        retval += c;
+                    }
+                }
+
+            }
+        }
+        // Only 1 or 2 consecutive `"`s are allowed in multiline basic string.
+        // 3 consecutive `"`s are considered as a closing delimiter.
+        // We need to check if there are 3 or more consecutive `"`s and insert
+        // backslash to break them down into several short `"`s like the `str6`
+        // in the following example.
+        // ```toml
+        // str4 = """Here are two quotation marks: "". Simple enough."""
+        // # str5 = """Here are three quotation marks: """."""  # INVALID
+        // str5 = """Here are three quotation marks: ""\"."""
+        // str6 = """Here are fifteen quotation marks: ""\"""\"""\"""\"""\"."""
+        // ```
+        auto found_3_quotes = retval.find("\"\"\"");
+        while(found_3_quotes != std::string::npos)
+        {
+            retval.replace(found_3_quotes, 3, "\"\"\\\"");
+            found_3_quotes = retval.find("\"\"\"");
+        }
+        return retval;
+    }
+
+    // if an element of a table or an array has a comment, it cannot be inlined.
+    bool has_comment_inside(const array_type& a) const noexcept
+    {
+        // if no_comment is set, comments would not be written.
+        if(this->no_comment_) {return false;}
+
+        for(const auto& v : a)
+        {
+            if(!v.comments().empty()) {return true;}
+        }
+        return false;
+    }
+    bool has_comment_inside(const table_type& t) const noexcept
+    {
+        // if no_comment is set, comments would not be written.
+        if(this->no_comment_) {return false;}
+
+        for(const auto& kv : t)
+        {
+            if(!kv.second.comments().empty()) {return true;}
+        }
+        return false;
+    }
+
+    std::string make_inline_array(const array_type& v) const
+    {
+        assert(!has_comment_inside(v));
+        std::string token;
+        token += '[';
+        bool is_first = true;
+        for(const auto& item : v)
+        {
+            if(is_first) {is_first = false;} else {token += ',';}
+            token += visit(serializer(
+                (std::numeric_limits<std::size_t>::max)(), this->float_prec_,
+                /* inlined */ true, /*no comment*/ false, /*keys*/ {},
+                /*has_comment*/ !item.comments().empty()), item);
+        }
+        token += ']';
+        return token;
+    }
+
+    std::string make_inline_table(const table_type& v) const
+    {
+        assert(!has_comment_inside(v));
+        assert(this->can_be_inlined_);
+        std::string token;
+        token += '{';
+        bool is_first = true;
+        for(const auto& kv : v)
+        {
+            // in inline tables, trailing comma is not allowed (toml-lang #569).
+            if(is_first) {is_first = false;} else {token += ',';}
+            token += format_key(kv.first);
+            token += '=';
+            token += visit(serializer(
+                (std::numeric_limits<std::size_t>::max)(), this->float_prec_,
+                /* inlined */ true, /*no comment*/ false, /*keys*/ {},
+                /*has_comment*/ !kv.second.comments().empty()), kv.second);
+        }
+        token += '}';
+        return token;
+    }
+
+    std::string make_multiline_table(const table_type& v) const
+    {
+        std::string token;
+
+        // print non-table elements first.
+        // ```toml
+        // [foo]         # a table we're writing now here
+        // key = "value" # <- non-table element, "key"
+        // # ...
+        // [foo.bar] # <- table element, "bar"
+        // ```
+        // because after printing [foo.bar], the remaining non-table values will
+        // be assigned into [foo.bar], not [foo]. Those values should be printed
+        // earlier.
+        for(const auto& kv : v)
+        {
+            if(kv.second.is_table() || is_array_of_tables(kv.second))
+            {
+                continue;
+            }
+
+            token += write_comments(kv.second);
+
+            const auto key_and_sep    = format_key(kv.first) + " = ";
+            const auto residual_width = (this->width_ > key_and_sep.size()) ?
+                                        this->width_ - key_and_sep.size() : 0;
+            token += key_and_sep;
+            token += visit(serializer(residual_width, this->float_prec_,
+                /*can be inlined*/ true, /*no comment*/ false, /*keys*/ {},
+                /*has_comment*/ !kv.second.comments().empty()), kv.second);
+
+            if(token.back() != '\n')
+            {
+                token += '\n';
+            }
+        }
+
+        // normal tables / array of tables
+
+        // after multiline table appeared, the other tables cannot be inline
+        // because the table would be assigned into the table.
+        // [foo]
+        // ...
+        // bar = {...} # <- bar will be a member of [foo].
+        bool multiline_table_printed = false;
+        for(const auto& kv : v)
+        {
+            if(!kv.second.is_table() && !is_array_of_tables(kv.second))
+            {
+                continue; // other stuff are already serialized. skip them.
+            }
+
+            std::vector<toml::key> ks(this->keys_);
+            ks.push_back(kv.first);
+
+            auto tmp = visit(serializer(this->width_, this->float_prec_,
+                !multiline_table_printed, this->no_comment_, ks,
+                /*has_comment*/ !kv.second.comments().empty()), kv.second);
+
+            // If it is the first time to print a multi-line table, it would be
+            // helpful to separate normal key-value pair and subtables by a
+            // newline.
+            // (this checks if the current key-value pair contains newlines.
+            //  but it is not perfect because multi-line string can also contain
+            //  a newline. in such a case, an empty line will be written) TODO
+            if((!multiline_table_printed) &&
+               std::find(tmp.cbegin(), tmp.cend(), '\n') != tmp.cend())
+            {
+                multiline_table_printed = true;
+                token += '\n'; // separate key-value pairs and subtables
+
+                token += write_comments(kv.second);
+                token += tmp;
+
+                // care about recursive tables (all tables in each level prints
+                // newline and there will be a full of newlines)
+                if(tmp.substr(tmp.size() - 2, 2) != "\n\n" &&
+                   tmp.substr(tmp.size() - 4, 4) != "\r\n\r\n" )
+                {
+                    token += '\n';
+                }
+            }
+            else
+            {
+                token += write_comments(kv.second);
+                token += tmp;
+                token += '\n';
+            }
+        }
+        return token;
+    }
+
+    std::string make_array_of_tables(const array_type& v) const
+    {
+        // if it's not inlined, we need to add `[[table.key]]`.
+        // but if it can be inlined, we can format it as the following.
+        // ```
+        // table.key = [
+        //   {...},
+        //   # comment
+        //   {...},
+        // ]
+        // ```
+        // This function checks if inlinization is possible or not, and then
+        // format the array-of-tables in a proper way.
+        //
+        // Note about comments:
+        //
+        // If the array itself has a comment (value_has_comment_ == true), we
+        // should try to make it inline.
+        // ```toml
+        // # comment about array
+        // array = [
+        //   # comment about table element
+        //   {of = "table"}
+        // ]
+        // ```
+        // If it is formatted as a multiline table, the two comments becomes
+        // indistinguishable.
+        // ```toml
+        // # comment about array
+        // # comment about table element
+        // [[array]]
+        // of = "table"
+        // ```
+        // So we need to try to make it inline, and it force-inlines regardless
+        // of the line width limit.
+        //     It may fail if the element of a table has comment. In that case,
+        // the array-of-tables will be formatted as a multiline table.
+        if(this->can_be_inlined_ || this->value_has_comment_)
+        {
+            std::string token;
+            if(!keys_.empty())
+            {
+                token += format_key(keys_.back());
+                token += " = ";
+            }
+
+            bool failed = false;
+            token += "[\n";
+            for(const auto& item : v)
+            {
+                // if an element of the table has a comment, the table
+                // cannot be inlined.
+                if(this->has_comment_inside(item.as_table()))
+                {
+                    failed = true;
+                    break;
+                }
+                // write comments for the table itself
+                token += write_comments(item);
+
+                const auto t = this->make_inline_table(item.as_table());
+
+                if(t.size() + 1 > width_ || // +1 for the last comma {...},
+                   std::find(t.cbegin(), t.cend(), '\n') != t.cend())
+                {
+                    // if the value itself has a comment, ignore the line width limit
+                    if( ! this->value_has_comment_)
+                    {
+                        failed = true;
+                        break;
+                    }
+                }
+                token += t;
+                token += ",\n";
+            }
+
+            if( ! failed)
+            {
+                token += "]\n";
+                return token;
+            }
+            // if failed, serialize them as [[array.of.tables]].
+        }
+
+        std::string token;
+        for(const auto& item : v)
+        {
+            token += write_comments(item);
+            token += "[[";
+            token += format_keys(keys_);
+            token += "]]\n";
+            token += this->make_multiline_table(item.as_table());
+        }
+        return token;
+    }
+
+    std::string write_comments(const value_type& v) const
+    {
+        std::string retval;
+        if(this->no_comment_) {return retval;}
+
+        for(const auto& c : v.comments())
+        {
+            retval += '#';
+            retval += c;
+            retval += '\n';
+        }
+        return retval;
+    }
+
+    bool is_array_of_tables(const value_type& v) const
+    {
+        if(!v.is_array() || v.as_array().empty()) {return false;}
+        return is_array_of_tables(v.as_array());
+    }
+    bool is_array_of_tables(const array_type& v) const
+    {
+        // Since TOML v0.5.0, heterogeneous arrays are allowed. So we need to
+        // check all the element in an array to check if the array is an array
+        // of tables.
+        return std::all_of(v.begin(), v.end(), [](const value_type& elem) {
+                return elem.is_table();
+            });
+    }
+
+  private:
+
+    bool        can_be_inlined_;
+    bool        no_comment_;
+    bool        value_has_comment_;
+    int         float_prec_;
+    std::size_t width_;
+    std::vector<toml::key> keys_;
+};
+
+template<typename C,
+         template<typename ...> class M, template<typename ...> class V>
+std::string
+format(const basic_value<C, M, V>& v, std::size_t w = 80u,
+       int fprec = std::numeric_limits<toml::floating>::max_digits10,
+       bool no_comment = false, bool force_inline = false)
+{
+    using value_type = basic_value<C, M, V>;
+    // if value is a table, it is considered to be a root object.
+    // the root object can't be an inline table.
+    if(v.is_table())
+    {
+        std::ostringstream oss;
+        if(!v.comments().empty())
+        {
+            oss << v.comments();
+            oss << '\n'; // to split the file comment from the first element
+        }
+        const auto serialized = visit(serializer<value_type>(w, fprec, false, no_comment), v);
+        oss << serialized;
+        return oss.str();
+    }
+    return visit(serializer<value_type>(w, fprec, force_inline), v);
+}
+
+namespace detail
+{
+template<typename charT, typename traits>
+int comment_index(std::basic_ostream<charT, traits>&)
+{
+    static const int index = std::ios_base::xalloc();
+    return index;
+}
+} // detail
+
+template<typename charT, typename traits>
+std::basic_ostream<charT, traits>&
+nocomment(std::basic_ostream<charT, traits>& os)
+{
+    // by default, it is zero. and by default, it shows comments.
+    os.iword(detail::comment_index(os)) = 1;
+    return os;
+}
+
+template<typename charT, typename traits>
+std::basic_ostream<charT, traits>&
+showcomment(std::basic_ostream<charT, traits>& os)
+{
+    // by default, it is zero. and by default, it shows comments.
+    os.iword(detail::comment_index(os)) = 0;
+    return os;
+}
+
+template<typename charT, typename traits, typename C,
+         template<typename ...> class M, template<typename ...> class V>
+std::basic_ostream<charT, traits>&
+operator<<(std::basic_ostream<charT, traits>& os, const basic_value<C, M, V>& v)
+{
+    using value_type = basic_value<C, M, V>;
+
+    // get status of std::setw().
+    const auto w     = static_cast<std::size_t>(os.width());
+    const int  fprec = static_cast<int>(os.precision());
+    os.width(0);
+
+    // by default, iword is initialized by 0. And by default, toml11 outputs
+    // comments. So `0` means showcomment. 1 means nocommnet.
+    const bool no_comment = (1 == os.iword(detail::comment_index(os)));
+
+    if(!no_comment && v.is_table() && !v.comments().empty())
+    {
+        os << v.comments();
+        os << '\n'; // to split the file comment from the first element
+    }
+    // the root object can't be an inline table. so pass `false`.
+    const auto serialized = visit(serializer<value_type>(w, fprec, no_comment, false), v);
+    os << serialized;
+
+    // if v is a non-table value, and has only one comment, then
+    // put a comment just after a value. in the following way.
+    //
+    // ```toml
+    // key = "value" # comment.
+    // ```
+    //
+    // Since the top-level toml object is a table, one who want to put a
+    // non-table toml value must use this in a following way.
+    //
+    // ```cpp
+    // toml::value v;
+    // std::cout << "user-defined-key = " << v << std::endl;
+    // ```
+    //
+    // In this case, it is impossible to put comments before key-value pair.
+    // The only way to preserve comments is to put all of them after a value.
+    if(!no_comment && !v.is_table() && !v.comments().empty())
+    {
+        os << " #";
+        for(const auto& c : v.comments()) {os << c;}
+    }
+    return os;
+}
+
+} // toml
+#endif// TOML11_SERIALIZER_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/source_location.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,239 @@
+//     Copyright Toru Niina 2019.
+// Distributed under the MIT License.
+#ifndef TOML11_SOURCE_LOCATION_HPP
+#define TOML11_SOURCE_LOCATION_HPP
+#include <cstdint>
+#include <sstream>
+
+#include "region.hpp"
+
+namespace toml
+{
+
+// A struct to contain location in a toml file.
+// The interface imitates std::experimental::source_location,
+// but not completely the same.
+//
+// It would be constructed by toml::value. It can be used to generate
+// user-defined error messages.
+//
+// - std::uint_least32_t line() const noexcept
+//   - returns the line number where the region is on.
+// - std::uint_least32_t column() const noexcept
+//   - returns the column number where the region starts.
+// - std::uint_least32_t region() const noexcept
+//   - returns the size of the region.
+//
+// +-- line()       +-- region of interest (region() == 9)
+// v            .---+---.
+// 12 | value = "foo bar"
+//              ^
+//              +-- column()
+//
+// - std::string const& file_name() const noexcept;
+//   - name of the file.
+// - std::string const& line_str() const noexcept;
+//   - the whole line that contains the region of interest.
+//
+struct source_location
+{
+  public:
+
+    source_location()
+        : line_num_(1), column_num_(1), region_size_(1),
+          file_name_("unknown file"), line_str_("")
+    {}
+
+    explicit source_location(const detail::region_base* reg)
+        : line_num_(1), column_num_(1), region_size_(1),
+          file_name_("unknown file"), line_str_("")
+    {
+        if(reg)
+        {
+            if(reg->line_num() != detail::region_base().line_num())
+            {
+                line_num_ = static_cast<std::uint_least32_t>(
+                        std::stoul(reg->line_num()));
+            }
+            column_num_  = static_cast<std::uint_least32_t>(reg->before() + 1);
+            region_size_ = static_cast<std::uint_least32_t>(reg->size());
+            file_name_   = reg->name();
+            line_str_    = reg->line();
+        }
+    }
+
+    explicit source_location(const detail::region& reg)
+        : line_num_(static_cast<std::uint_least32_t>(std::stoul(reg.line_num()))),
+          column_num_(static_cast<std::uint_least32_t>(reg.before() + 1)),
+          region_size_(static_cast<std::uint_least32_t>(reg.size())),
+          file_name_(reg.name()),
+          line_str_ (reg.line())
+    {}
+    explicit source_location(const detail::location& loc)
+        : line_num_(static_cast<std::uint_least32_t>(std::stoul(loc.line_num()))),
+          column_num_(static_cast<std::uint_least32_t>(loc.before() + 1)),
+          region_size_(static_cast<std::uint_least32_t>(loc.size())),
+          file_name_(loc.name()),
+          line_str_ (loc.line())
+    {}
+
+    ~source_location() = default;
+    source_location(source_location const&) = default;
+    source_location(source_location &&)     = default;
+    source_location& operator=(source_location const&) = default;
+    source_location& operator=(source_location &&)     = default;
+
+    std::uint_least32_t line()      const noexcept {return line_num_;}
+    std::uint_least32_t column()    const noexcept {return column_num_;}
+    std::uint_least32_t region()    const noexcept {return region_size_;}
+
+    std::string const&  file_name() const noexcept {return file_name_;}
+    std::string const&  line_str()  const noexcept {return line_str_;}
+
+  private:
+
+    std::uint_least32_t line_num_;
+    std::uint_least32_t column_num_;
+    std::uint_least32_t region_size_;
+    std::string         file_name_;
+    std::string         line_str_;
+};
+
+namespace detail
+{
+
+// internal error message generation.
+inline std::string format_underline(const std::string& message,
+        const std::vector<std::pair<source_location, std::string>>& loc_com,
+        const std::vector<std::string>& helps = {},
+        const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
+{
+    std::size_t line_num_width = 0;
+    for(const auto& lc : loc_com)
+    {
+        std::uint_least32_t line = lc.first.line();
+        std::size_t        digit = 0;
+        while(line != 0)
+        {
+            line  /= 10;
+            digit +=  1;
+        }
+        line_num_width = (std::max)(line_num_width, digit);
+    }
+    // 1 is the minimum width
+    line_num_width = std::max<std::size_t>(line_num_width, 1);
+
+    std::ostringstream retval;
+
+    if(color::should_color() || colorize)
+    {
+        retval << color::colorize; // turn on ANSI color
+    }
+
+    // XXX
+    // Here, before `colorize` support, it does not output `[error]` prefix
+    // automatically. So some user may output it manually and this change may
+    // duplicate the prefix. To avoid it, check the first 7 characters and
+    // if it is "[error]", it removes that part from the message shown.
+    if(message.size() > 7 && message.substr(0, 7) == "[error]")
+    {
+        retval
+#ifndef TOML11_NO_ERROR_PREFIX
+               << color::bold << color::red << "[error]" << color::reset
+#endif
+               << color::bold << message.substr(7) << color::reset << '\n';
+    }
+    else
+    {
+        retval
+#ifndef TOML11_NO_ERROR_PREFIX
+               << color::bold << color::red << "[error] " << color::reset
+#endif
+               << color::bold << message << color::reset << '\n';
+    }
+
+    const auto format_one_location = [line_num_width]
+        (std::ostringstream& oss,
+         const source_location& loc, const std::string& comment) -> void
+        {
+            oss << ' ' << color::bold << color::blue
+                << std::setw(static_cast<int>(line_num_width))
+                << std::right << loc.line() << " | "  << color::reset
+                << loc.line_str() << '\n';
+
+            oss << make_string(line_num_width + 1, ' ')
+                << color::bold << color::blue << " | " << color::reset
+                << make_string(loc.column()-1 /*1-origin*/, ' ');
+
+            if(loc.region() == 1)
+            {
+                // invalid
+                // ^------
+                oss << color::bold << color::red << "^---" << color::reset;
+            }
+            else
+            {
+                // invalid
+                // ~~~~~~~
+                const auto underline_len = (std::min)(
+                    static_cast<std::size_t>(loc.region()), loc.line_str().size());
+                oss << color::bold << color::red
+                    << make_string(underline_len, '~') << color::reset;
+            }
+            oss << ' ';
+            oss << comment;
+            return;
+        };
+
+    assert(!loc_com.empty());
+
+    // --> example.toml
+    //   |
+    retval << color::bold << color::blue << " --> " << color::reset
+           << loc_com.front().first.file_name() << '\n';
+    retval << make_string(line_num_width + 1, ' ')
+           << color::bold << color::blue << " |\n"  << color::reset;
+    // 1 | key value
+    //   |    ^--- missing =
+    format_one_location(retval, loc_com.front().first, loc_com.front().second);
+
+    // process the rest of the locations
+    for(std::size_t i=1; i<loc_com.size(); ++i)
+    {
+        const auto& prev = loc_com.at(i-1);
+        const auto& curr = loc_com.at(i);
+
+        retval << '\n';
+        // if the filenames are the same, print "..."
+        if(prev.first.file_name() == curr.first.file_name())
+        {
+            retval << color::bold << color::blue << " ...\n" << color::reset;
+        }
+        else // if filename differs, print " --> filename.toml" again
+        {
+            retval << color::bold << color::blue << " --> " << color::reset
+                   << curr.first.file_name() << '\n';
+            retval << make_string(line_num_width + 1, ' ')
+                   << color::bold << color::blue << " |\n"  << color::reset;
+        }
+
+        format_one_location(retval, curr.first, curr.second);
+    }
+
+    if(!helps.empty())
+    {
+        retval << '\n';
+        retval << make_string(line_num_width + 1, ' ');
+        retval << color::bold << color::blue << " |" << color::reset;
+        for(const auto& help : helps)
+        {
+            retval << color::bold << "\nHint: " << color::reset;
+            retval << help;
+        }
+    }
+    return retval.str();
+}
+
+} // detail
+} // toml
+#endif// TOML11_SOURCE_LOCATION_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/storage.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,43 @@
+//     Copyright Toru Niina 2017.
+// Distributed under the MIT License.
+#ifndef TOML11_STORAGE_HPP
+#define TOML11_STORAGE_HPP
+#include "utility.hpp"
+
+namespace toml
+{
+namespace detail
+{
+
+// this contains pointer and deep-copy the content if copied.
+// to avoid recursive pointer.
+template<typename T>
+struct storage
+{
+    using value_type = T;
+
+    explicit storage(value_type const& v): ptr(toml::make_unique<T>(v)) {}
+    explicit storage(value_type&&      v): ptr(toml::make_unique<T>(std::move(v))) {}
+    ~storage() = default;
+    storage(const storage& rhs): ptr(toml::make_unique<T>(*rhs.ptr)) {}
+    storage& operator=(const storage& rhs)
+    {
+        this->ptr = toml::make_unique<T>(*rhs.ptr);
+        return *this;
+    }
+    storage(storage&&) = default;
+    storage& operator=(storage&&) = default;
+
+    bool is_ok() const noexcept {return static_cast<bool>(ptr);}
+
+    value_type&       value() &      noexcept {return *ptr;}
+    value_type const& value() const& noexcept {return *ptr;}
+    value_type&&      value() &&     noexcept {return std::move(*ptr);}
+
+  private:
+    std::unique_ptr<value_type> ptr;
+};
+
+} // detail
+} // toml
+#endif// TOML11_STORAGE_HPP
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/string.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,228 @@
+//     Copyright Toru Niina 2017.
+// Distributed under the MIT License.
+#ifndef TOML11_STRING_HPP
+#define TOML11_STRING_HPP
+
+#include "version.hpp"
+
+#include <cstdint>
+
+#include <algorithm>
+#include <string>
+
+#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
+#if __has_include(<string_view>)
+#define TOML11_USING_STRING_VIEW 1
+#include <string_view>
+#endif
+#endif
+
+namespace toml
+{
+
+enum class string_t : std::uint8_t
+{
+    basic   = 0,
+    literal = 1,
+};
+
+struct string
+{
+    string()  = default;
+    ~string() = default;
+    string(const string& s) = default;
+    string(string&& s)      = default;
+    string& operator=(const string& s) = default;
+    string& operator=(string&& s)      = default;
+
+    string(const std::string& s): kind(string_t::basic), str(s){}
+    string(const std::string& s, string_t k):   kind(k), str(s){}
+    string(const char* s):        kind(string_t::basic), str(s){}
+    string(const char* s,        string_t k):   kind(k), str(s){}
+
+    string(std::string&& s): kind(string_t::basic), str(std::move(s)){}
+    string(std::string&& s, string_t k):   kind(k), str(std::move(s)){}
+
+    string& operator=(const std::string& s)
+    {kind = string_t::basic; str = s; return *this;}
+    string& operator=(std::string&& s)
+    {kind = string_t::basic; str = std::move(s); return *this;}
+
+    operator std::string&       () &      noexcept {return str;}
+    operator std::string const& () const& noexcept {return str;}
+    operator std::string&&      () &&     noexcept {return std::move(str);}
+
+    string& operator+=(const char*        rhs) {str += rhs; return *this;}
+    string& operator+=(const char         rhs) {str += rhs; return *this;}
+    string& operator+=(const std::string& rhs) {str += rhs; return *this;}
+    string& operator+=(const string&      rhs) {str += rhs.str; return *this;}
+
+#if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0
+    explicit string(std::string_view s): kind(string_t::basic), str(s){}
+    string(std::string_view s, string_t k): kind(k), str(s){}
+
+    string& operator=(std::string_view s)
+    {kind = string_t::basic; str = s; return *this;}
+
+    explicit operator std::string_view() const noexcept
+    {return std::string_view(str);}
+
+    string& operator+=(const std::string_view& rhs) {str += rhs; return *this;}
+#endif
+
+    string_t    kind;
+    std::string str;
+};
+
+inline bool operator==(const string& lhs, const string& rhs)
+{
+    return lhs.kind == rhs.kind && lhs.str == rhs.str;
+}
+inline bool operator!=(const string& lhs, const string& rhs)
+{
+    return !(lhs == rhs);
+}
+inline bool operator<(const string& lhs, const string& rhs)
+{
+    return (lhs.kind == rhs.kind) ? (lhs.str < rhs.str) : (lhs.kind < rhs.kind);
+}
+inline bool operator>(const string& lhs, const string& rhs)
+{
+    return rhs < lhs;
+}
+inline bool operator<=(const string& lhs, const string& rhs)
+{
+    return !(rhs < lhs);
+}
+inline bool operator>=(const string& lhs, const string& rhs)
+{
+    return !(lhs < rhs);
+}
+
+inline bool
+operator==(const string& lhs, const std::string& rhs) {return lhs.str == rhs;}
+inline bool
+operator!=(const string& lhs, const std::string& rhs) {return lhs.str != rhs;}
+inline bool
+operator< (const string& lhs, const std::string& rhs) {return lhs.str <  rhs;}
+inline bool
+operator> (const string& lhs, const std::string& rhs) {return lhs.str >  rhs;}
+inline bool
+operator<=(const string& lhs, const std::string& rhs) {return lhs.str <= rhs;}
+inline bool
+operator>=(const string& lhs, const std::string& rhs) {return lhs.str >= rhs;}
+
+inline bool
+operator==(const std::string& lhs, const string& rhs) {return lhs == rhs.str;}
+inline bool
+operator!=(const std::string& lhs, const string& rhs) {return lhs != rhs.str;}
+inline bool
+operator< (const std::string& lhs, const string& rhs) {return lhs <  rhs.str;}
+inline bool
+operator> (const std::string& lhs, const string& rhs) {return lhs >  rhs.str;}
+inline bool
+operator<=(const std::string& lhs, const string& rhs) {return lhs <= rhs.str;}
+inline bool
+operator>=(const std::string& lhs, const string& rhs) {return lhs >= rhs.str;}
+
+inline bool
+operator==(const string& lhs, const char* rhs) {return lhs.str == std::string(rhs);}
+inline bool
+operator!=(const string& lhs, const char* rhs) {return lhs.str != std::string(rhs);}
+inline bool
+operator< (const string& lhs, const char* rhs) {return lhs.str <  std::string(rhs);}
+inline bool
+operator> (const string& lhs, const char* rhs) {return lhs.str >  std::string(rhs);}
+inline bool
+operator<=(const string& lhs, const char* rhs) {return lhs.str <= std::string(rhs);}
+inline bool
+operator>=(const string& lhs, const char* rhs) {return lhs.str >= std::string(rhs);}
+
+inline bool
+operator==(const char* lhs, const string& rhs) {return std::string(lhs) == rhs.str;}
+inline bool
+operator!=(const char* lhs, const string& rhs) {return std::string(lhs) != rhs.str;}
+inline bool
+operator< (const char* lhs, const string& rhs) {return std::string(lhs) <  rhs.str;}
+inline bool
+operator> (const char* lhs, const string& rhs) {return std::string(lhs) >  rhs.str;}
+inline bool
+operator<=(const char* lhs, const string& rhs) {return std::string(lhs) <= rhs.str;}
+inline bool
+operator>=(const char* lhs, const string& rhs) {return std::string(lhs) >= rhs.str;}
+
+template<typename charT, typename traits>
+std::basic_ostream<charT, traits>&
+operator<<(std::basic_ostream<charT, traits>& os, const string& s)
+{
+    if(s.kind == string_t::basic)
+    {
+        if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend())
+        {
+            // it contains newline. make it multiline string.
+            os << "\"\"\"\n";
+            for(auto i=s.str.cbegin(), e=s.str.cend(); i!=e; ++i)
+            {
+                switch(*i)
+                {
+                    case '\\': {os << "\\\\"; break;}
+                    case '\"': {os << "\\\""; break;}
+                    case '\b': {os << "\\b";  break;}
+                    case '\t': {os << "\\t";  break;}
+                    case '\f': {os << "\\f";  break;}
+                    case '\n': {os << '\n';   break;}
+                    case '\r':
+                    {
+                        // since it is a multiline string,
+                        // CRLF is not needed to be escaped.
+                        if(std::next(i) != e && *std::next(i) == '\n')
+                        {
+                            os << "\r\n";
+                            ++i;
+                        }
+                        else
+                        {
+                            os << "\\r";
+                        }
+                        break;
+                    }
+                    default: {os << *i; break;}
+                }
+            }
+            os << "\\\n\"\"\"";
+            return os;
+        }
+        // no newline. make it inline.
+        os << "\"";
+        for(const auto c : s.str)
+        {
+            switch(c)
+            {
+                case '\\': {os << "\\\\"; break;}
+                case '\"': {os << "\\\""; break;}
+                case '\b': {os << "\\b";  break;}
+                case '\t': {os << "\\t";  break;}
+                case '\f': {os << "\\f";  break;}
+                case '\n': {os << "\\n";  break;}
+                case '\r': {os << "\\r";  break;}
+                default  : {os << c;      break;}
+            }
+        }
+        os << "\"";
+        return os;
+    }
+    // the string `s` is literal-string.
+    if(std::find(s.str.cbegin(), s.str.cend(), '\n') != s.str.cend() ||
+       std::find(s.str.cbegin(), s.str.cend(), '\'') != s.str.cend() )
+    {
+        // contains newline or single quote. make it multiline.
+        os << "'''\n" << s.str << "'''";
+        return os;
+    }
+    // normal literal string
+    os << '\'' << s.str << '\'';
+    return os;
+}
+
+} // toml
+#endif// TOML11_STRING_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/traits.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,328 @@
+//     Copyright Toru Niina 2017.
+// Distributed under the MIT License.
+#ifndef TOML11_TRAITS_HPP
+#define TOML11_TRAITS_HPP
+
+#include "from.hpp"
+#include "into.hpp"
+#include "version.hpp"
+
+#include <chrono>
+#include <forward_list>
+#include <string>
+#include <tuple>
+#include <type_traits>
+#include <utility>
+
+#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
+#if __has_include(<string_view>)
+#include <string_view>
+#endif // has_include(<string_view>)
+#endif // cplusplus   >= C++17
+
+namespace toml
+{
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+class basic_value;
+
+namespace detail
+{
+// ---------------------------------------------------------------------------
+// check whether type T is a kind of container/map class
+
+struct has_iterator_impl
+{
+    template<typename T> static std::true_type  check(typename T::iterator*);
+    template<typename T> static std::false_type check(...);
+};
+struct has_value_type_impl
+{
+    template<typename T> static std::true_type  check(typename T::value_type*);
+    template<typename T> static std::false_type check(...);
+};
+struct has_key_type_impl
+{
+    template<typename T> static std::true_type  check(typename T::key_type*);
+    template<typename T> static std::false_type check(...);
+};
+struct has_mapped_type_impl
+{
+    template<typename T> static std::true_type  check(typename T::mapped_type*);
+    template<typename T> static std::false_type check(...);
+};
+struct has_reserve_method_impl
+{
+    template<typename T> static std::false_type check(...);
+    template<typename T> static std::true_type  check(
+        decltype(std::declval<T>().reserve(std::declval<std::size_t>()))*);
+};
+struct has_push_back_method_impl
+{
+    template<typename T> static std::false_type check(...);
+    template<typename T> static std::true_type  check(
+        decltype(std::declval<T>().push_back(std::declval<typename T::value_type>()))*);
+};
+struct is_comparable_impl
+{
+    template<typename T> static std::false_type check(...);
+    template<typename T> static std::true_type  check(
+        decltype(std::declval<T>() < std::declval<T>())*);
+};
+
+struct has_from_toml_method_impl
+{
+    template<typename T, typename C,
+             template<typename ...> class Tb, template<typename ...> class A>
+    static std::true_type  check(
+        decltype(std::declval<T>().from_toml(
+                std::declval<::toml::basic_value<C, Tb, A>>()))*);
+
+    template<typename T, typename C,
+             template<typename ...> class Tb, template<typename ...> class A>
+    static std::false_type check(...);
+};
+struct has_into_toml_method_impl
+{
+    template<typename T>
+    static std::true_type  check(decltype(std::declval<T>().into_toml())*);
+    template<typename T>
+    static std::false_type check(...);
+};
+
+struct has_specialized_from_impl
+{
+    template<typename T>
+    static std::false_type check(...);
+    template<typename T, std::size_t S = sizeof(::toml::from<T>)>
+    static std::true_type check(::toml::from<T>*);
+};
+struct has_specialized_into_impl
+{
+    template<typename T>
+    static std::false_type check(...);
+    template<typename T, std::size_t S = sizeof(::toml::into<T>)>
+    static std::true_type check(::toml::from<T>*);
+};
+
+
+/// Intel C++ compiler can not use decltype in parent class declaration, here
+/// is a hack to work around it. https://stackoverflow.com/a/23953090/4692076
+#ifdef __INTEL_COMPILER
+#define decltype(...) std::enable_if<true, decltype(__VA_ARGS__)>::type
+#endif
+
+template<typename T>
+struct has_iterator    : decltype(has_iterator_impl::check<T>(nullptr)){};
+template<typename T>
+struct has_value_type  : decltype(has_value_type_impl::check<T>(nullptr)){};
+template<typename T>
+struct has_key_type    : decltype(has_key_type_impl::check<T>(nullptr)){};
+template<typename T>
+struct has_mapped_type : decltype(has_mapped_type_impl::check<T>(nullptr)){};
+template<typename T>
+struct has_reserve_method : decltype(has_reserve_method_impl::check<T>(nullptr)){};
+template<typename T>
+struct has_push_back_method : decltype(has_push_back_method_impl::check<T>(nullptr)){};
+template<typename T>
+struct is_comparable : decltype(is_comparable_impl::check<T>(nullptr)){};
+
+template<typename T, typename C,
+         template<typename ...> class Tb, template<typename ...> class A>
+struct has_from_toml_method
+: decltype(has_from_toml_method_impl::check<T, C, Tb, A>(nullptr)){};
+
+template<typename T>
+struct has_into_toml_method
+: decltype(has_into_toml_method_impl::check<T>(nullptr)){};
+
+template<typename T>
+struct has_specialized_from : decltype(has_specialized_from_impl::check<T>(nullptr)){};
+template<typename T>
+struct has_specialized_into : decltype(has_specialized_into_impl::check<T>(nullptr)){};
+
+#ifdef __INTEL_COMPILER
+#undef decltype
+#endif
+
+// ---------------------------------------------------------------------------
+// C++17 and/or/not
+
+#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
+
+using std::conjunction;
+using std::disjunction;
+using std::negation;
+
+#else
+
+template<typename ...> struct conjunction : std::true_type{};
+template<typename T>   struct conjunction<T> : T{};
+template<typename T, typename ... Ts>
+struct conjunction<T, Ts...> :
+    std::conditional<static_cast<bool>(T::value), conjunction<Ts...>, T>::type
+{};
+
+template<typename ...> struct disjunction : std::false_type{};
+template<typename T>   struct disjunction<T> : T {};
+template<typename T, typename ... Ts>
+struct disjunction<T, Ts...> :
+    std::conditional<static_cast<bool>(T::value), T, disjunction<Ts...>>::type
+{};
+
+template<typename T>
+struct negation : std::integral_constant<bool, !static_cast<bool>(T::value)>{};
+
+#endif
+
+// ---------------------------------------------------------------------------
+// type checkers
+
+template<typename T> struct is_std_pair : std::false_type{};
+template<typename T1, typename T2>
+struct is_std_pair<std::pair<T1, T2>> : std::true_type{};
+
+template<typename T> struct is_std_tuple : std::false_type{};
+template<typename ... Ts>
+struct is_std_tuple<std::tuple<Ts...>> : std::true_type{};
+
+template<typename T> struct is_std_forward_list : std::false_type{};
+template<typename T>
+struct is_std_forward_list<std::forward_list<T>> : std::true_type{};
+
+template<typename T> struct is_chrono_duration: std::false_type{};
+template<typename Rep, typename Period>
+struct is_chrono_duration<std::chrono::duration<Rep, Period>>: std::true_type{};
+
+template<typename T>
+struct is_map : conjunction< // map satisfies all the following conditions
+    has_iterator<T>,         // has T::iterator
+    has_value_type<T>,       // has T::value_type
+    has_key_type<T>,         // has T::key_type
+    has_mapped_type<T>       // has T::mapped_type
+    >{};
+template<typename T> struct is_map<T&>                : is_map<T>{};
+template<typename T> struct is_map<T const&>          : is_map<T>{};
+template<typename T> struct is_map<T volatile&>       : is_map<T>{};
+template<typename T> struct is_map<T const volatile&> : is_map<T>{};
+
+template<typename T>
+struct is_container : conjunction<
+    negation<is_map<T>>,                         // not a map
+    negation<std::is_same<T, std::string>>,      // not a std::string
+#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L
+#if __has_include(<string_view>)
+    negation<std::is_same<T, std::string_view>>, // not a std::string_view
+#endif // has_include(<string_view>)
+#endif
+    has_iterator<T>,                             // has T::iterator
+    has_value_type<T>                            // has T::value_type
+    >{};
+template<typename T> struct is_container<T&>                : is_container<T>{};
+template<typename T> struct is_container<T const&>          : is_container<T>{};
+template<typename T> struct is_container<T volatile&>       : is_container<T>{};
+template<typename T> struct is_container<T const volatile&> : is_container<T>{};
+
+template<typename T>
+struct is_basic_value: std::false_type{};
+template<typename T> struct is_basic_value<T&>                : is_basic_value<T>{};
+template<typename T> struct is_basic_value<T const&>          : is_basic_value<T>{};
+template<typename T> struct is_basic_value<T volatile&>       : is_basic_value<T>{};
+template<typename T> struct is_basic_value<T const volatile&> : is_basic_value<T>{};
+template<typename C, template<typename ...> class M, template<typename ...> class V>
+struct is_basic_value<::toml::basic_value<C, M, V>>: std::true_type{};
+
+// ---------------------------------------------------------------------------
+// C++14 index_sequence
+
+#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
+
+using std::index_sequence;
+using std::make_index_sequence;
+
+#else
+
+template<std::size_t ... Ns> struct index_sequence{};
+
+template<typename IS, std::size_t N> struct push_back_index_sequence{};
+template<std::size_t N, std::size_t ... Ns>
+struct push_back_index_sequence<index_sequence<Ns...>, N>
+{
+    typedef index_sequence<Ns..., N> type;
+};
+
+template<std::size_t N>
+struct index_sequence_maker
+{
+    typedef typename push_back_index_sequence<
+        typename index_sequence_maker<N-1>::type, N>::type type;
+};
+template<>
+struct index_sequence_maker<0>
+{
+    typedef index_sequence<0> type;
+};
+template<std::size_t N>
+using make_index_sequence = typename index_sequence_maker<N-1>::type;
+
+#endif // cplusplus >= 2014
+
+// ---------------------------------------------------------------------------
+// C++14 enable_if_t
+
+#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
+
+using std::enable_if_t;
+
+#else
+
+template<bool B, typename T>
+using enable_if_t = typename std::enable_if<B, T>::type;
+
+#endif // cplusplus >= 2014
+
+// ---------------------------------------------------------------------------
+// return_type_of_t
+
+#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201703L && defined(__cpp_lib_is_invocable) && __cpp_lib_is_invocable>=201703
+
+template<typename F, typename ... Args>
+using return_type_of_t = std::invoke_result_t<F, Args...>;
+
+#else
+// result_of is deprecated after C++17
+template<typename F, typename ... Args>
+using return_type_of_t = typename std::result_of<F(Args...)>::type;
+
+#endif
+
+// ---------------------------------------------------------------------------
+// is_string_literal
+//
+// to use this, pass `typename remove_reference<T>::type` to T.
+
+template<typename T>
+struct is_string_literal:
+disjunction<
+    std::is_same<const char*, T>,
+    conjunction<
+        std::is_array<T>,
+        std::is_same<const char, typename std::remove_extent<T>::type>
+        >
+    >{};
+
+// ---------------------------------------------------------------------------
+// C++20 remove_cvref_t
+
+template<typename T>
+struct remove_cvref
+{
+    using type = typename std::remove_cv<
+        typename std::remove_reference<T>::type>::type;
+};
+
+template<typename T>
+using remove_cvref_t = typename remove_cvref<T>::type;
+
+}// detail
+}//toml
+#endif // TOML_TRAITS
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/types.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,173 @@
+//     Copyright Toru Niina 2017.
+// Distributed under the MIT License.
+#ifndef TOML11_TYPES_HPP
+#define TOML11_TYPES_HPP
+#include <unordered_map>
+#include <vector>
+
+#include "comments.hpp"
+#include "datetime.hpp"
+#include "string.hpp"
+#include "traits.hpp"
+
+namespace toml
+{
+
+template<typename Comment, // discard/preserve_comment
+         template<typename ...> class Table, // map-like class
+         template<typename ...> class Array> // vector-like class
+class basic_value;
+
+using character = char;
+using key = std::string;
+
+#if !defined(__clang__) && defined(__GNUC__) && __GNUC__ <= 4
+#  pragma GCC diagnostic push
+#  pragma GCC diagnostic ignored "-Wshadow"
+#endif
+
+using boolean        = bool;
+using integer        = std::int64_t;
+using floating       = double; // "float" is a keyword, cannot use it here.
+// the following stuffs are structs defined here, so aliases are not needed.
+// - string
+// - offset_datetime
+// - offset_datetime
+// - local_datetime
+// - local_date
+// - local_time
+
+#if defined(__GNUC__) && !defined(__clang__)
+#  pragma GCC diagnostic pop
+#endif
+
+// default toml::value and default array/table. these are defined after defining
+// basic_value itself.
+// using value = basic_value<discard_comments, std::unordered_map, std::vector>;
+// using array = typename value::array_type;
+// using table = typename value::table_type;
+
+// to avoid warnings about `value_t::integer` is "shadowing" toml::integer in
+// GCC -Wshadow=global.
+#if defined(__GNUC__) && !defined(__clang__)
+#  pragma GCC diagnostic push
+#  if 7 <= __GNUC__
+#    pragma GCC diagnostic ignored "-Wshadow=global"
+#  else // gcc-6 or older
+#    pragma GCC diagnostic ignored "-Wshadow"
+#  endif
+#endif
+enum class value_t : std::uint8_t
+{
+    empty           =  0,
+    boolean         =  1,
+    integer         =  2,
+    floating        =  3,
+    string          =  4,
+    offset_datetime =  5,
+    local_datetime  =  6,
+    local_date      =  7,
+    local_time      =  8,
+    array           =  9,
+    table           = 10,
+};
+#if defined(__GNUC__) && !defined(__clang__)
+#  pragma GCC diagnostic pop
+#endif
+
+template<typename charT, typename traits>
+inline std::basic_ostream<charT, traits>&
+operator<<(std::basic_ostream<charT, traits>& os, value_t t)
+{
+    switch(t)
+    {
+        case value_t::boolean         : os << "boolean";         return os;
+        case value_t::integer         : os << "integer";         return os;
+        case value_t::floating        : os << "floating";        return os;
+        case value_t::string          : os << "string";          return os;
+        case value_t::offset_datetime : os << "offset_datetime"; return os;
+        case value_t::local_datetime  : os << "local_datetime";  return os;
+        case value_t::local_date      : os << "local_date";      return os;
+        case value_t::local_time      : os << "local_time";      return os;
+        case value_t::array           : os << "array";           return os;
+        case value_t::table           : os << "table";           return os;
+        case value_t::empty           : os << "empty";           return os;
+        default                       : os << "unknown";         return os;
+    }
+}
+
+template<typename charT = char,
+         typename traits = std::char_traits<charT>,
+         typename alloc = std::allocator<charT>>
+inline std::basic_string<charT, traits, alloc> stringize(value_t t)
+{
+    std::basic_ostringstream<charT, traits, alloc> oss;
+    oss << t;
+    return oss.str();
+}
+
+namespace detail
+{
+
+// helper to define a type that represents a value_t value.
+template<value_t V>
+using value_t_constant = std::integral_constant<value_t, V>;
+
+// meta-function that convertes from value_t to the exact toml type that corresponds to.
+// It takes toml::basic_value type because array and table types depend on it.
+template<value_t t, typename Value> struct enum_to_type                      {using type = void                      ;};
+template<typename Value> struct enum_to_type<value_t::empty          , Value>{using type = void                      ;};
+template<typename Value> struct enum_to_type<value_t::boolean        , Value>{using type = boolean                   ;};
+template<typename Value> struct enum_to_type<value_t::integer        , Value>{using type = integer                   ;};
+template<typename Value> struct enum_to_type<value_t::floating       , Value>{using type = floating                  ;};
+template<typename Value> struct enum_to_type<value_t::string         , Value>{using type = string                    ;};
+template<typename Value> struct enum_to_type<value_t::offset_datetime, Value>{using type = offset_datetime           ;};
+template<typename Value> struct enum_to_type<value_t::local_datetime , Value>{using type = local_datetime            ;};
+template<typename Value> struct enum_to_type<value_t::local_date     , Value>{using type = local_date                ;};
+template<typename Value> struct enum_to_type<value_t::local_time     , Value>{using type = local_time                ;};
+template<typename Value> struct enum_to_type<value_t::array          , Value>{using type = typename Value::array_type;};
+template<typename Value> struct enum_to_type<value_t::table          , Value>{using type = typename Value::table_type;};
+
+// meta-function that converts from an exact toml type to the enum that corresponds to.
+template<typename T, typename Value>
+struct type_to_enum : std::conditional<
+    std::is_same<T, typename Value::array_type>::value, // if T == array_type,
+    value_t_constant<value_t::array>,                   // then value_t::array
+    typename std::conditional<                          // else...
+        std::is_same<T, typename Value::table_type>::value, // if T == table_type
+        value_t_constant<value_t::table>,               // then value_t::table
+        value_t_constant<value_t::empty>                // else value_t::empty
+        >::type
+    >::type {};
+template<typename Value> struct type_to_enum<boolean        , Value>: value_t_constant<value_t::boolean        > {};
+template<typename Value> struct type_to_enum<integer        , Value>: value_t_constant<value_t::integer        > {};
+template<typename Value> struct type_to_enum<floating       , Value>: value_t_constant<value_t::floating       > {};
+template<typename Value> struct type_to_enum<string         , Value>: value_t_constant<value_t::string         > {};
+template<typename Value> struct type_to_enum<offset_datetime, Value>: value_t_constant<value_t::offset_datetime> {};
+template<typename Value> struct type_to_enum<local_datetime , Value>: value_t_constant<value_t::local_datetime > {};
+template<typename Value> struct type_to_enum<local_date     , Value>: value_t_constant<value_t::local_date     > {};
+template<typename Value> struct type_to_enum<local_time     , Value>: value_t_constant<value_t::local_time     > {};
+
+// meta-function that checks the type T is the same as one of the toml::* types.
+template<typename T, typename Value>
+struct is_exact_toml_type : disjunction<
+    std::is_same<T, boolean        >,
+    std::is_same<T, integer        >,
+    std::is_same<T, floating       >,
+    std::is_same<T, string         >,
+    std::is_same<T, offset_datetime>,
+    std::is_same<T, local_datetime >,
+    std::is_same<T, local_date     >,
+    std::is_same<T, local_time     >,
+    std::is_same<T, typename Value::array_type>,
+    std::is_same<T, typename Value::table_type>
+    >{};
+template<typename T, typename V> struct is_exact_toml_type<T&, V>               : is_exact_toml_type<T, V>{};
+template<typename T, typename V> struct is_exact_toml_type<T const&, V>         : is_exact_toml_type<T, V>{};
+template<typename T, typename V> struct is_exact_toml_type<T volatile&, V>      : is_exact_toml_type<T, V>{};
+template<typename T, typename V> struct is_exact_toml_type<T const volatile&, V>: is_exact_toml_type<T, V>{};
+
+} // detail
+} // toml
+
+#endif// TOML11_TYPES_H
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/utility.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,150 @@
+//     Copyright Toru Niina 2017.
+// Distributed under the MIT License.
+#ifndef TOML11_UTILITY_HPP
+#define TOML11_UTILITY_HPP
+#include <memory>
+#include <sstream>
+#include <utility>
+
+#include "traits.hpp"
+#include "version.hpp"
+
+#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
+#  define TOML11_MARK_AS_DEPRECATED(msg) [[deprecated(msg)]]
+#elif defined(__GNUC__)
+#  define TOML11_MARK_AS_DEPRECATED(msg) __attribute__((deprecated(msg)))
+#elif defined(_MSC_VER)
+#  define TOML11_MARK_AS_DEPRECATED(msg) __declspec(deprecated(msg))
+#else
+#  define TOML11_MARK_AS_DEPRECATED
+#endif
+
+namespace toml
+{
+
+#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
+
+using std::make_unique;
+
+#else
+
+template<typename T, typename ... Ts>
+inline std::unique_ptr<T> make_unique(Ts&& ... args)
+{
+    return std::unique_ptr<T>(new T(std::forward<Ts>(args)...));
+}
+
+#endif // TOML11_CPLUSPLUS_STANDARD_VERSION >= 2014
+
+namespace detail
+{
+template<typename Container>
+void try_reserve_impl(Container& container, std::size_t N, std::true_type)
+{
+    container.reserve(N);
+    return;
+}
+template<typename Container>
+void try_reserve_impl(Container&, std::size_t, std::false_type) noexcept
+{
+    return;
+}
+} // detail
+
+template<typename Container>
+void try_reserve(Container& container, std::size_t N)
+{
+    if(N <= container.size()) {return;}
+    detail::try_reserve_impl(container, N, detail::has_reserve_method<Container>{});
+    return;
+}
+
+namespace detail
+{
+inline std::string concat_to_string_impl(std::ostringstream& oss)
+{
+    return oss.str();
+}
+template<typename T, typename ... Ts>
+std::string concat_to_string_impl(std::ostringstream& oss, T&& head, Ts&& ... tail)
+{
+    oss << std::forward<T>(head);
+    return concat_to_string_impl(oss, std::forward<Ts>(tail) ... );
+}
+} // detail
+
+template<typename ... Ts>
+std::string concat_to_string(Ts&& ... args)
+{
+    std::ostringstream oss;
+    oss << std::boolalpha << std::fixed;
+    return detail::concat_to_string_impl(oss, std::forward<Ts>(args) ...);
+}
+
+template<typename T>
+T from_string(const std::string& str, T opt)
+{
+    T v(opt);
+    std::istringstream iss(str);
+    iss >> v;
+    return v;
+}
+
+namespace detail
+{
+#if TOML11_CPLUSPLUS_STANDARD_VERSION >= 201402L
+template<typename T>
+decltype(auto) last_one(T&& tail) noexcept
+{
+    return std::forward<T>(tail);
+}
+
+template<typename T, typename ... Ts>
+decltype(auto) last_one(T&& /*head*/, Ts&& ... tail) noexcept
+{
+    return last_one(std::forward<Ts>(tail)...);
+}
+#else // C++11
+// The following code
+// ```cpp
+//  1 | template<typename T, typename ... Ts>
+//  2 | auto last_one(T&& /*head*/, Ts&& ... tail)
+//  3 |  -> decltype(last_one(std::forward<Ts>(tail)...))
+//  4 | {
+//  5 |     return last_one(std::forward<Ts>(tail)...);
+//  6 | }
+// ```
+// does not work because the function `last_one(...)` is not yet defined at
+// line #3, so `decltype()` cannot deduce the type returned from `last_one`.
+// So we need to determine return type in a different way, like a meta func.
+
+template<typename T, typename ... Ts>
+struct last_one_in_pack
+{
+    using type = typename last_one_in_pack<Ts...>::type;
+};
+template<typename T>
+struct last_one_in_pack<T>
+{
+    using type = T;
+};
+template<typename ... Ts>
+using last_one_in_pack_t = typename last_one_in_pack<Ts...>::type;
+
+template<typename T>
+T&& last_one(T&& tail) noexcept
+{
+    return std::forward<T>(tail);
+}
+template<typename T, typename ... Ts>
+enable_if_t<(sizeof...(Ts) > 0), last_one_in_pack_t<Ts&& ...>>
+last_one(T&& /*head*/, Ts&& ... tail)
+{
+    return last_one(std::forward<Ts>(tail)...);
+}
+
+#endif
+} // detail
+
+}// toml
+#endif // TOML11_UTILITY
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/value.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,2037 @@
+//     Copyright Toru Niina 2017.
+// Distributed under the MIT License.
+#ifndef TOML11_VALUE_HPP
+#define TOML11_VALUE_HPP
+#include <cassert>
+
+#include "comments.hpp"
+#include "exception.hpp"
+#include "into.hpp"
+#include "region.hpp"
+#include "source_location.hpp"
+#include "storage.hpp"
+#include "traits.hpp"
+#include "types.hpp"
+#include "utility.hpp"
+
+namespace toml
+{
+
+namespace detail
+{
+
+// to show error messages. not recommended for users.
+template<typename Value>
+inline region_base const* get_region(const Value& v)
+{
+    return v.region_info_.get();
+}
+
+template<typename Value>
+void change_region(Value& v, region reg)
+{
+    v.region_info_ = std::make_shared<region>(std::move(reg));
+    return;
+}
+
+template<value_t Expected, typename Value>
+[[noreturn]] inline void
+throw_bad_cast(const std::string& funcname, value_t actual, const Value& v)
+{
+    throw type_error(detail::format_underline(
+        concat_to_string(funcname, "bad_cast to ", Expected), {
+            {v.location(), concat_to_string("the actual type is ", actual)}
+        }), v.location());
+}
+
+// Throw `out_of_range` from `toml::value::at()` and `toml::find()`
+// after generating an error message.
+//
+// The implementation is a bit complicated and there are many edge-cases.
+// If you are not interested in the error message generation, just skip this.
+template<typename Value>
+[[noreturn]] void
+throw_key_not_found_error(const Value& v, const key& ky)
+{
+    // The top-level table has its region at the first character of the file.
+    // That means that, in the case when a key is not found in the top-level
+    // table, the error message points to the first character. If the file has
+    // its first table at the first line, the error message would be like this.
+    // ```console
+    // [error] key "a" not found
+    //  --> example.toml
+    //    |
+    //  1 | [table]
+    //    | ^------ in this table
+    // ```
+    // It actually points to the top-level table at the first character,
+    // not `[table]`. But it is too confusing. To avoid the confusion, the error
+    // message should explicitly say "key not found in the top-level table",
+    // or "the parsed file is empty" if there is no content at all (0 bytes in file).
+    const auto loc = v.location();
+    if(loc.line() == 1 && loc.region() == 0)
+    {
+        // First line with a zero-length region means "empty file".
+        // The region will be generated at `parse_toml_file` function
+        // if the file contains no bytes.
+        throw std::out_of_range(format_underline(concat_to_string(
+            "key \"", ky, "\" not found in the top-level table"), {
+                {loc, "the parsed file is empty"}
+            }));
+    }
+    else if(loc.line() == 1 && loc.region() == 1)
+    {
+        // Here it assumes that top-level table starts at the first character.
+        // The region corresponds to the top-level table will be generated at
+        // `parse_toml_file` function.
+        //     It also assumes that the top-level table size is just one and
+        // the line number is `1`. It is always satisfied. And those conditions
+        // are satisfied only if the table is the top-level table.
+        //
+        // 1. one-character dot-key at the first line
+        // ```toml
+        // a.b = "c"
+        // ```
+        // toml11 counts whole key as the table key. Here, `a.b` is the region
+        // of the table "a". It could be counter intuitive, but it works.
+        // The size of the region is 3, not 1. The above example is the shortest
+        // dot-key example. The size cannot be 1.
+        //
+        // 2. one-character inline-table at the first line
+        // ```toml
+        // a = {b = "c"}
+        // ```
+        // toml11 considers the inline table body as the table region. Here,
+        // `{b = "c"}` is the region of the table "a". The size of the region
+        // is 9, not 1. The shotest inline table still has two characters, `{`
+        // and `}`. The size cannot be 1.
+        //
+        // 3. one-character table declaration at the first line
+        // ```toml
+        // [a]
+        // ```
+        // toml11 considers the whole table key as the table region. Here,
+        // `[a]` is the table region. The size is 3, not 1.
+        //
+        throw std::out_of_range(format_underline(concat_to_string(
+            "key \"", ky, "\" not found in the top-level table"), {
+                {loc, "the top-level table starts here"}
+            }));
+    }
+    else
+    {
+        // normal table.
+        throw std::out_of_range(format_underline(concat_to_string(
+            "key \"", ky, "\" not found"), { {loc, "in this table"} }));
+    }
+}
+
+// switch by `value_t` at the compile time.
+template<value_t T>
+struct switch_cast {};
+#define TOML11_GENERATE_SWITCH_CASTER(TYPE) \
+    template<>                                                           \
+    struct switch_cast<value_t::TYPE>                                    \
+    {                                                                    \
+        template<typename Value>                                         \
+        static typename Value::TYPE##_type& invoke(Value& v)             \
+        {                                                                \
+            return v.as_##TYPE();                                        \
+        }                                                                \
+        template<typename Value>                                         \
+        static typename Value::TYPE##_type const& invoke(const Value& v) \
+        {                                                                \
+            return v.as_##TYPE();                                        \
+        }                                                                \
+        template<typename Value>                                         \
+        static typename Value::TYPE##_type&& invoke(Value&& v)           \
+        {                                                                \
+            return std::move(v).as_##TYPE();                             \
+        }                                                                \
+    };                                                                   \
+    /**/
+TOML11_GENERATE_SWITCH_CASTER(boolean)
+TOML11_GENERATE_SWITCH_CASTER(integer)
+TOML11_GENERATE_SWITCH_CASTER(floating)
+TOML11_GENERATE_SWITCH_CASTER(string)
+TOML11_GENERATE_SWITCH_CASTER(offset_datetime)
+TOML11_GENERATE_SWITCH_CASTER(local_datetime)
+TOML11_GENERATE_SWITCH_CASTER(local_date)
+TOML11_GENERATE_SWITCH_CASTER(local_time)
+TOML11_GENERATE_SWITCH_CASTER(array)
+TOML11_GENERATE_SWITCH_CASTER(table)
+
+#undef TOML11_GENERATE_SWITCH_CASTER
+
+}// detail
+
+template<typename Comment, // discard/preserve_comment
+         template<typename ...> class Table = std::unordered_map,
+         template<typename ...> class Array = std::vector>
+class basic_value
+{
+    template<typename T, typename U>
+    static void assigner(T& dst, U&& v)
+    {
+        const auto tmp = ::new(std::addressof(dst)) T(std::forward<U>(v));
+        assert(tmp == std::addressof(dst));
+        (void)tmp;
+    }
+
+    using region_base = detail::region_base;
+
+    template<typename C, template<typename ...> class T,
+             template<typename ...> class A>
+    friend class basic_value;
+
+  public:
+
+    using comment_type         = Comment;
+    using key_type             = ::toml::key;
+    using value_type           = basic_value<comment_type, Table, Array>;
+    using boolean_type         = ::toml::boolean;
+    using integer_type         = ::toml::integer;
+    using floating_type        = ::toml::floating;
+    using string_type          = ::toml::string;
+    using local_time_type      = ::toml::local_time;
+    using local_date_type      = ::toml::local_date;
+    using local_datetime_type  = ::toml::local_datetime;
+    using offset_datetime_type = ::toml::offset_datetime;
+    using array_type           = Array<value_type>;
+    using table_type           = Table<key_type, value_type>;
+
+  public:
+
+    basic_value() noexcept
+        : type_(value_t::empty),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {}
+    ~basic_value() noexcept {this->cleanup();}
+
+    basic_value(const basic_value& v)
+        : type_(v.type()), region_info_(v.region_info_), comments_(v.comments_)
+    {
+        switch(v.type())
+        {
+            case value_t::boolean        : assigner(boolean_        , v.boolean_        ); break;
+            case value_t::integer        : assigner(integer_        , v.integer_        ); break;
+            case value_t::floating       : assigner(floating_       , v.floating_       ); break;
+            case value_t::string         : assigner(string_         , v.string_         ); break;
+            case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break;
+            case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break;
+            case value_t::local_date     : assigner(local_date_     , v.local_date_     ); break;
+            case value_t::local_time     : assigner(local_time_     , v.local_time_     ); break;
+            case value_t::array          : assigner(array_          , v.array_          ); break;
+            case value_t::table          : assigner(table_          , v.table_          ); break;
+            default: break;
+        }
+    }
+    basic_value(basic_value&& v)
+        : type_(v.type()), region_info_(std::move(v.region_info_)),
+          comments_(std::move(v.comments_))
+    {
+        switch(this->type_) // here this->type_ is already initialized
+        {
+            case value_t::boolean        : assigner(boolean_        , std::move(v.boolean_        )); break;
+            case value_t::integer        : assigner(integer_        , std::move(v.integer_        )); break;
+            case value_t::floating       : assigner(floating_       , std::move(v.floating_       )); break;
+            case value_t::string         : assigner(string_         , std::move(v.string_         )); break;
+            case value_t::offset_datetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break;
+            case value_t::local_datetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break;
+            case value_t::local_date     : assigner(local_date_     , std::move(v.local_date_     )); break;
+            case value_t::local_time     : assigner(local_time_     , std::move(v.local_time_     )); break;
+            case value_t::array          : assigner(array_          , std::move(v.array_          )); break;
+            case value_t::table          : assigner(table_          , std::move(v.table_          )); break;
+            default: break;
+        }
+    }
+    basic_value& operator=(const basic_value& v)
+    {
+        if(this == std::addressof(v)) {return *this;}
+        this->cleanup();
+        this->region_info_ = v.region_info_;
+        this->comments_ = v.comments_;
+        this->type_ = v.type();
+        switch(this->type_)
+        {
+            case value_t::boolean        : assigner(boolean_        , v.boolean_        ); break;
+            case value_t::integer        : assigner(integer_        , v.integer_        ); break;
+            case value_t::floating       : assigner(floating_       , v.floating_       ); break;
+            case value_t::string         : assigner(string_         , v.string_         ); break;
+            case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break;
+            case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break;
+            case value_t::local_date     : assigner(local_date_     , v.local_date_     ); break;
+            case value_t::local_time     : assigner(local_time_     , v.local_time_     ); break;
+            case value_t::array          : assigner(array_          , v.array_          ); break;
+            case value_t::table          : assigner(table_          , v.table_          ); break;
+            default: break;
+        }
+        return *this;
+    }
+    basic_value& operator=(basic_value&& v)
+    {
+        if(this == std::addressof(v)) {return *this;}
+        this->cleanup();
+        this->region_info_ = std::move(v.region_info_);
+        this->comments_ = std::move(v.comments_);
+        this->type_ = v.type();
+        switch(this->type_)
+        {
+            case value_t::boolean        : assigner(boolean_        , std::move(v.boolean_        )); break;
+            case value_t::integer        : assigner(integer_        , std::move(v.integer_        )); break;
+            case value_t::floating       : assigner(floating_       , std::move(v.floating_       )); break;
+            case value_t::string         : assigner(string_         , std::move(v.string_         )); break;
+            case value_t::offset_datetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break;
+            case value_t::local_datetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break;
+            case value_t::local_date     : assigner(local_date_     , std::move(v.local_date_     )); break;
+            case value_t::local_time     : assigner(local_time_     , std::move(v.local_time_     )); break;
+            case value_t::array          : assigner(array_          , std::move(v.array_          )); break;
+            case value_t::table          : assigner(table_          , std::move(v.table_          )); break;
+            default: break;
+        }
+        return *this;
+    }
+
+    // overwrite comments ----------------------------------------------------
+
+    basic_value(const basic_value& v, std::vector<std::string> com)
+        : type_(v.type()), region_info_(v.region_info_),
+          comments_(std::move(com))
+    {
+        switch(v.type())
+        {
+            case value_t::boolean        : assigner(boolean_        , v.boolean_        ); break;
+            case value_t::integer        : assigner(integer_        , v.integer_        ); break;
+            case value_t::floating       : assigner(floating_       , v.floating_       ); break;
+            case value_t::string         : assigner(string_         , v.string_         ); break;
+            case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break;
+            case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break;
+            case value_t::local_date     : assigner(local_date_     , v.local_date_     ); break;
+            case value_t::local_time     : assigner(local_time_     , v.local_time_     ); break;
+            case value_t::array          : assigner(array_          , v.array_          ); break;
+            case value_t::table          : assigner(table_          , v.table_          ); break;
+            default: break;
+        }
+    }
+
+    basic_value(basic_value&& v, std::vector<std::string> com)
+        : type_(v.type()), region_info_(std::move(v.region_info_)),
+          comments_(std::move(com))
+    {
+        switch(this->type_) // here this->type_ is already initialized
+        {
+            case value_t::boolean        : assigner(boolean_        , std::move(v.boolean_        )); break;
+            case value_t::integer        : assigner(integer_        , std::move(v.integer_        )); break;
+            case value_t::floating       : assigner(floating_       , std::move(v.floating_       )); break;
+            case value_t::string         : assigner(string_         , std::move(v.string_         )); break;
+            case value_t::offset_datetime: assigner(offset_datetime_, std::move(v.offset_datetime_)); break;
+            case value_t::local_datetime : assigner(local_datetime_ , std::move(v.local_datetime_ )); break;
+            case value_t::local_date     : assigner(local_date_     , std::move(v.local_date_     )); break;
+            case value_t::local_time     : assigner(local_time_     , std::move(v.local_time_     )); break;
+            case value_t::array          : assigner(array_          , std::move(v.array_          )); break;
+            case value_t::table          : assigner(table_          , std::move(v.table_          )); break;
+            default: break;
+        }
+    }
+
+    // -----------------------------------------------------------------------
+    // conversion between different basic_values.
+    template<typename C,
+             template<typename ...> class T,
+             template<typename ...> class A>
+    basic_value(const basic_value<C, T, A>& v)
+        : type_(v.type()), region_info_(v.region_info_), comments_(v.comments())
+    {
+        switch(v.type())
+        {
+            case value_t::boolean        : assigner(boolean_        , v.boolean_        ); break;
+            case value_t::integer        : assigner(integer_        , v.integer_        ); break;
+            case value_t::floating       : assigner(floating_       , v.floating_       ); break;
+            case value_t::string         : assigner(string_         , v.string_         ); break;
+            case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break;
+            case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break;
+            case value_t::local_date     : assigner(local_date_     , v.local_date_     ); break;
+            case value_t::local_time     : assigner(local_time_     , v.local_time_     ); break;
+            case value_t::array          :
+            {
+                array_type tmp(v.as_array(std::nothrow).begin(),
+                               v.as_array(std::nothrow).end());
+                assigner(array_, std::move(tmp));
+                break;
+            }
+            case value_t::table          :
+            {
+                table_type tmp(v.as_table(std::nothrow).begin(),
+                               v.as_table(std::nothrow).end());
+                assigner(table_, std::move(tmp));
+                break;
+            }
+            default: break;
+        }
+    }
+    template<typename C,
+             template<typename ...> class T,
+             template<typename ...> class A>
+    basic_value(const basic_value<C, T, A>& v, std::vector<std::string> com)
+        : type_(v.type()), region_info_(v.region_info_),
+          comments_(std::move(com))
+    {
+        switch(v.type())
+        {
+            case value_t::boolean        : assigner(boolean_        , v.boolean_        ); break;
+            case value_t::integer        : assigner(integer_        , v.integer_        ); break;
+            case value_t::floating       : assigner(floating_       , v.floating_       ); break;
+            case value_t::string         : assigner(string_         , v.string_         ); break;
+            case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break;
+            case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break;
+            case value_t::local_date     : assigner(local_date_     , v.local_date_     ); break;
+            case value_t::local_time     : assigner(local_time_     , v.local_time_     ); break;
+            case value_t::array          :
+            {
+                array_type tmp(v.as_array(std::nothrow).begin(),
+                               v.as_array(std::nothrow).end());
+                assigner(array_, std::move(tmp));
+                break;
+            }
+            case value_t::table          :
+            {
+                table_type tmp(v.as_table(std::nothrow).begin(),
+                               v.as_table(std::nothrow).end());
+                assigner(table_, std::move(tmp));
+                break;
+            }
+            default: break;
+        }
+    }
+    template<typename C,
+             template<typename ...> class T,
+             template<typename ...> class A>
+    basic_value& operator=(const basic_value<C, T, A>& v)
+    {
+        this->region_info_ = v.region_info_;
+        this->comments_    = comment_type(v.comments());
+        this->type_        = v.type();
+        switch(v.type())
+        {
+            case value_t::boolean        : assigner(boolean_        , v.boolean_        ); break;
+            case value_t::integer        : assigner(integer_        , v.integer_        ); break;
+            case value_t::floating       : assigner(floating_       , v.floating_       ); break;
+            case value_t::string         : assigner(string_         , v.string_         ); break;
+            case value_t::offset_datetime: assigner(offset_datetime_, v.offset_datetime_); break;
+            case value_t::local_datetime : assigner(local_datetime_ , v.local_datetime_ ); break;
+            case value_t::local_date     : assigner(local_date_     , v.local_date_     ); break;
+            case value_t::local_time     : assigner(local_time_     , v.local_time_     ); break;
+            case value_t::array          :
+            {
+                array_type tmp(v.as_array(std::nothrow).begin(),
+                               v.as_array(std::nothrow).end());
+                assigner(array_, std::move(tmp));
+                break;
+            }
+            case value_t::table          :
+            {
+                table_type tmp(v.as_table(std::nothrow).begin(),
+                               v.as_table(std::nothrow).end());
+                assigner(table_, std::move(tmp));
+                break;
+            }
+            default: break;
+        }
+        return *this;
+    }
+
+    // boolean ==============================================================
+
+    basic_value(boolean b)
+        : type_(value_t::boolean),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->boolean_, b);
+    }
+    basic_value& operator=(boolean b)
+    {
+        this->cleanup();
+        this->type_ = value_t::boolean;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->boolean_, b);
+        return *this;
+    }
+    basic_value(boolean b, std::vector<std::string> com)
+        : type_(value_t::boolean),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->boolean_, b);
+    }
+
+    // integer ==============================================================
+
+    template<typename T, typename std::enable_if<detail::conjunction<
+        std::is_integral<T>, detail::negation<std::is_same<T, boolean>>>::value,
+        std::nullptr_t>::type = nullptr>
+    basic_value(T i)
+        : type_(value_t::integer),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->integer_, static_cast<integer>(i));
+    }
+
+    template<typename T, typename std::enable_if<detail::conjunction<
+        std::is_integral<T>, detail::negation<std::is_same<T, boolean>>>::value,
+        std::nullptr_t>::type = nullptr>
+    basic_value& operator=(T i)
+    {
+        this->cleanup();
+        this->type_ = value_t::integer;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->integer_, static_cast<integer>(i));
+        return *this;
+    }
+
+    template<typename T, typename std::enable_if<detail::conjunction<
+        std::is_integral<T>, detail::negation<std::is_same<T, boolean>>>::value,
+        std::nullptr_t>::type = nullptr>
+    basic_value(T i, std::vector<std::string> com)
+        : type_(value_t::integer),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->integer_, static_cast<integer>(i));
+    }
+
+    // floating =============================================================
+
+    template<typename T, typename std::enable_if<
+        std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
+    basic_value(T f)
+        : type_(value_t::floating),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->floating_, static_cast<floating>(f));
+    }
+
+
+    template<typename T, typename std::enable_if<
+        std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
+    basic_value& operator=(T f)
+    {
+        this->cleanup();
+        this->type_ = value_t::floating;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->floating_, static_cast<floating>(f));
+        return *this;
+    }
+
+    template<typename T, typename std::enable_if<
+        std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
+    basic_value(T f, std::vector<std::string> com)
+        : type_(value_t::floating),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->floating_, f);
+    }
+
+    // string ===============================================================
+
+    basic_value(toml::string s)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->string_, std::move(s));
+    }
+    basic_value& operator=(toml::string s)
+    {
+        this->cleanup();
+        this->type_ = value_t::string ;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->string_, s);
+        return *this;
+    }
+    basic_value(toml::string s, std::vector<std::string> com)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->string_, std::move(s));
+    }
+
+    basic_value(std::string s)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->string_, toml::string(std::move(s)));
+    }
+    basic_value& operator=(std::string s)
+    {
+        this->cleanup();
+        this->type_ = value_t::string ;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->string_, toml::string(std::move(s)));
+        return *this;
+    }
+    basic_value(std::string s, string_t kind)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->string_, toml::string(std::move(s), kind));
+    }
+    basic_value(std::string s, std::vector<std::string> com)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->string_, toml::string(std::move(s)));
+    }
+    basic_value(std::string s, string_t kind, std::vector<std::string> com)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->string_, toml::string(std::move(s), kind));
+    }
+
+    basic_value(const char* s)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->string_, toml::string(std::string(s)));
+    }
+    basic_value& operator=(const char* s)
+    {
+        this->cleanup();
+        this->type_ = value_t::string ;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->string_, toml::string(std::string(s)));
+        return *this;
+    }
+    basic_value(const char* s, string_t kind)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->string_, toml::string(std::string(s), kind));
+    }
+    basic_value(const char* s, std::vector<std::string> com)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->string_, toml::string(std::string(s)));
+    }
+    basic_value(const char* s, string_t kind, std::vector<std::string> com)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->string_, toml::string(std::string(s), kind));
+    }
+
+#if defined(TOML11_USING_STRING_VIEW) && TOML11_USING_STRING_VIEW>0
+    basic_value(std::string_view s)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->string_, toml::string(s));
+    }
+    basic_value& operator=(std::string_view s)
+    {
+        this->cleanup();
+        this->type_ = value_t::string ;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->string_, toml::string(s));
+        return *this;
+    }
+    basic_value(std::string_view s, std::vector<std::string> com)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->string_, toml::string(s));
+    }
+    basic_value(std::string_view s, string_t kind)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->string_, toml::string(s, kind));
+    }
+    basic_value(std::string_view s, string_t kind, std::vector<std::string> com)
+        : type_(value_t::string),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->string_, toml::string(s, kind));
+    }
+#endif
+
+    // local date ===========================================================
+
+    basic_value(const local_date& ld)
+        : type_(value_t::local_date),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->local_date_, ld);
+    }
+    basic_value& operator=(const local_date& ld)
+    {
+        this->cleanup();
+        this->type_ = value_t::local_date;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->local_date_, ld);
+        return *this;
+    }
+    basic_value(const local_date& ld, std::vector<std::string> com)
+        : type_(value_t::local_date),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->local_date_, ld);
+    }
+
+    // local time ===========================================================
+
+    basic_value(const local_time& lt)
+        : type_(value_t::local_time),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->local_time_, lt);
+    }
+    basic_value(const local_time& lt, std::vector<std::string> com)
+        : type_(value_t::local_time),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->local_time_, lt);
+    }
+    basic_value& operator=(const local_time& lt)
+    {
+        this->cleanup();
+        this->type_ = value_t::local_time;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->local_time_, lt);
+        return *this;
+    }
+
+    template<typename Rep, typename Period>
+    basic_value(const std::chrono::duration<Rep, Period>& dur)
+        : type_(value_t::local_time),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->local_time_, local_time(dur));
+    }
+    template<typename Rep, typename Period>
+    basic_value(const std::chrono::duration<Rep, Period>& dur,
+                std::vector<std::string> com)
+        : type_(value_t::local_time),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->local_time_, local_time(dur));
+    }
+    template<typename Rep, typename Period>
+    basic_value& operator=(const std::chrono::duration<Rep, Period>& dur)
+    {
+        this->cleanup();
+        this->type_ = value_t::local_time;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->local_time_, local_time(dur));
+        return *this;
+    }
+
+    // local datetime =======================================================
+
+    basic_value(const local_datetime& ldt)
+        : type_(value_t::local_datetime),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->local_datetime_, ldt);
+    }
+    basic_value(const local_datetime& ldt, std::vector<std::string> com)
+        : type_(value_t::local_datetime),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->local_datetime_, ldt);
+    }
+    basic_value& operator=(const local_datetime& ldt)
+    {
+        this->cleanup();
+        this->type_ = value_t::local_datetime;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->local_datetime_, ldt);
+        return *this;
+    }
+
+    // offset datetime ======================================================
+
+    basic_value(const offset_datetime& odt)
+        : type_(value_t::offset_datetime),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->offset_datetime_, odt);
+    }
+    basic_value(const offset_datetime& odt, std::vector<std::string> com)
+        : type_(value_t::offset_datetime),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->offset_datetime_, odt);
+    }
+    basic_value& operator=(const offset_datetime& odt)
+    {
+        this->cleanup();
+        this->type_ = value_t::offset_datetime;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->offset_datetime_, odt);
+        return *this;
+    }
+    basic_value(const std::chrono::system_clock::time_point& tp)
+        : type_(value_t::offset_datetime),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->offset_datetime_, offset_datetime(tp));
+    }
+    basic_value(const std::chrono::system_clock::time_point& tp,
+                std::vector<std::string> com)
+        : type_(value_t::offset_datetime),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->offset_datetime_, offset_datetime(tp));
+    }
+    basic_value& operator=(const std::chrono::system_clock::time_point& tp)
+    {
+        this->cleanup();
+        this->type_ = value_t::offset_datetime;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->offset_datetime_, offset_datetime(tp));
+        return *this;
+    }
+
+    // array ================================================================
+
+    basic_value(const array_type& ary)
+        : type_(value_t::array),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->array_, ary);
+    }
+    basic_value(const array_type& ary, std::vector<std::string> com)
+        : type_(value_t::array),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->array_, ary);
+    }
+    basic_value& operator=(const array_type& ary)
+    {
+        this->cleanup();
+        this->type_ = value_t::array ;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->array_, ary);
+        return *this;
+    }
+
+    // array (initializer_list) ----------------------------------------------
+
+    template<typename T, typename std::enable_if<
+            std::is_convertible<T, value_type>::value,
+        std::nullptr_t>::type = nullptr>
+    basic_value(std::initializer_list<T> list)
+        : type_(value_t::array),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        array_type ary(list.begin(), list.end());
+        assigner(this->array_, std::move(ary));
+    }
+    template<typename T, typename std::enable_if<
+            std::is_convertible<T, value_type>::value,
+        std::nullptr_t>::type = nullptr>
+    basic_value(std::initializer_list<T> list, std::vector<std::string> com)
+        : type_(value_t::array),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        array_type ary(list.begin(), list.end());
+        assigner(this->array_, std::move(ary));
+    }
+    template<typename T, typename std::enable_if<
+            std::is_convertible<T, value_type>::value,
+        std::nullptr_t>::type = nullptr>
+    basic_value& operator=(std::initializer_list<T> list)
+    {
+        this->cleanup();
+        this->type_ = value_t::array;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+
+        array_type ary(list.begin(), list.end());
+        assigner(this->array_, std::move(ary));
+        return *this;
+    }
+
+    // array (STL Containers) ------------------------------------------------
+
+    template<typename T, typename std::enable_if<detail::conjunction<
+            detail::negation<std::is_same<T, array_type>>,
+            detail::is_container<T>
+        >::value, std::nullptr_t>::type = nullptr>
+    basic_value(const T& list)
+        : type_(value_t::array),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        static_assert(std::is_convertible<typename T::value_type, value_type>::value,
+            "elements of a container should be convertible to toml::value");
+
+        array_type ary(list.size());
+        std::copy(list.begin(), list.end(), ary.begin());
+        assigner(this->array_, std::move(ary));
+    }
+    template<typename T, typename std::enable_if<detail::conjunction<
+            detail::negation<std::is_same<T, array_type>>,
+            detail::is_container<T>
+        >::value, std::nullptr_t>::type = nullptr>
+    basic_value(const T& list, std::vector<std::string> com)
+        : type_(value_t::array),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        static_assert(std::is_convertible<typename T::value_type, value_type>::value,
+            "elements of a container should be convertible to toml::value");
+
+        array_type ary(list.size());
+        std::copy(list.begin(), list.end(), ary.begin());
+        assigner(this->array_, std::move(ary));
+    }
+    template<typename T, typename std::enable_if<detail::conjunction<
+            detail::negation<std::is_same<T, array_type>>,
+            detail::is_container<T>
+        >::value, std::nullptr_t>::type = nullptr>
+    basic_value& operator=(const T& list)
+    {
+        static_assert(std::is_convertible<typename T::value_type, value_type>::value,
+            "elements of a container should be convertible to toml::value");
+
+        this->cleanup();
+        this->type_ = value_t::array;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+
+        array_type ary(list.size());
+        std::copy(list.begin(), list.end(), ary.begin());
+        assigner(this->array_, std::move(ary));
+        return *this;
+    }
+
+    // table ================================================================
+
+    basic_value(const table_type& tab)
+        : type_(value_t::table),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        assigner(this->table_, tab);
+    }
+    basic_value(const table_type& tab, std::vector<std::string> com)
+        : type_(value_t::table),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        assigner(this->table_, tab);
+    }
+    basic_value& operator=(const table_type& tab)
+    {
+        this->cleanup();
+        this->type_ = value_t::table;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+        assigner(this->table_, tab);
+        return *this;
+    }
+
+    // initializer-list ------------------------------------------------------
+
+    basic_value(std::initializer_list<std::pair<key, basic_value>> list)
+        : type_(value_t::table),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        table_type tab;
+        for(const auto& elem : list) {tab[elem.first] = elem.second;}
+        assigner(this->table_, std::move(tab));
+    }
+
+    basic_value(std::initializer_list<std::pair<key, basic_value>> list,
+                std::vector<std::string> com)
+        : type_(value_t::table),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        table_type tab;
+        for(const auto& elem : list) {tab[elem.first] = elem.second;}
+        assigner(this->table_, std::move(tab));
+    }
+    basic_value& operator=(std::initializer_list<std::pair<key, basic_value>> list)
+    {
+        this->cleanup();
+        this->type_ = value_t::table;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+
+        table_type tab;
+        for(const auto& elem : list) {tab[elem.first] = elem.second;}
+        assigner(this->table_, std::move(tab));
+        return *this;
+    }
+
+    // other table-like -----------------------------------------------------
+
+    template<typename Map, typename std::enable_if<detail::conjunction<
+            detail::negation<std::is_same<Map, table_type>>,
+            detail::is_map<Map>
+        >::value, std::nullptr_t>::type = nullptr>
+    basic_value(const Map& mp)
+        : type_(value_t::table),
+          region_info_(std::make_shared<region_base>(region_base{}))
+    {
+        table_type tab;
+        for(const auto& elem : mp) {tab[elem.first] = elem.second;}
+        assigner(this->table_, std::move(tab));
+    }
+    template<typename Map, typename std::enable_if<detail::conjunction<
+            detail::negation<std::is_same<Map, table_type>>,
+            detail::is_map<Map>
+        >::value, std::nullptr_t>::type = nullptr>
+    basic_value(const Map& mp, std::vector<std::string> com)
+        : type_(value_t::table),
+          region_info_(std::make_shared<region_base>(region_base{})),
+          comments_(std::move(com))
+    {
+        table_type tab;
+        for(const auto& elem : mp) {tab[elem.first] = elem.second;}
+        assigner(this->table_, std::move(tab));
+    }
+    template<typename Map, typename std::enable_if<detail::conjunction<
+            detail::negation<std::is_same<Map, table_type>>,
+            detail::is_map<Map>
+        >::value, std::nullptr_t>::type = nullptr>
+    basic_value& operator=(const Map& mp)
+    {
+        this->cleanup();
+        this->type_ = value_t::table;
+        this->region_info_ = std::make_shared<region_base>(region_base{});
+
+        table_type tab;
+        for(const auto& elem : mp) {tab[elem.first] = elem.second;}
+        assigner(this->table_, std::move(tab));
+        return *this;
+    }
+
+    // user-defined =========================================================
+
+    // convert using into_toml() method -------------------------------------
+
+    template<typename T, typename std::enable_if<
+        detail::has_into_toml_method<T>::value, std::nullptr_t>::type = nullptr>
+    basic_value(const T& ud): basic_value(ud.into_toml()) {}
+
+    template<typename T, typename std::enable_if<
+        detail::has_into_toml_method<T>::value, std::nullptr_t>::type = nullptr>
+    basic_value(const T& ud, std::vector<std::string> com)
+        : basic_value(ud.into_toml(), std::move(com))
+    {}
+    template<typename T, typename std::enable_if<
+        detail::has_into_toml_method<T>::value, std::nullptr_t>::type = nullptr>
+    basic_value& operator=(const T& ud)
+    {
+        *this = ud.into_toml();
+        return *this;
+    }
+
+    // convert using into<T> struct -----------------------------------------
+
+    template<typename T, std::size_t S = sizeof(::toml::into<T>)>
+    basic_value(const T& ud): basic_value(::toml::into<T>::into_toml(ud)) {}
+    template<typename T, std::size_t S = sizeof(::toml::into<T>)>
+    basic_value(const T& ud, std::vector<std::string> com)
+        : basic_value(::toml::into<T>::into_toml(ud), std::move(com))
+    {}
+    template<typename T, std::size_t S = sizeof(::toml::into<T>)>
+    basic_value& operator=(const T& ud)
+    {
+        *this = ::toml::into<T>::into_toml(ud);
+        return *this;
+    }
+
+    // for internal use ------------------------------------------------------
+    //
+    // Those constructors take detail::region that contains parse result.
+
+    basic_value(boolean b, detail::region reg, std::vector<std::string> cm)
+        : type_(value_t::boolean),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->boolean_, b);
+    }
+    template<typename T, typename std::enable_if<
+        detail::conjunction<
+            std::is_integral<T>, detail::negation<std::is_same<T, boolean>>
+        >::value, std::nullptr_t>::type = nullptr>
+    basic_value(T i, detail::region reg, std::vector<std::string> cm)
+        : type_(value_t::integer),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->integer_, static_cast<integer>(i));
+    }
+    template<typename T, typename std::enable_if<
+        std::is_floating_point<T>::value, std::nullptr_t>::type = nullptr>
+    basic_value(T f, detail::region reg, std::vector<std::string> cm)
+        : type_(value_t::floating),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->floating_, static_cast<floating>(f));
+    }
+    basic_value(toml::string s, detail::region reg,
+                std::vector<std::string> cm)
+        : type_(value_t::string),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->string_, std::move(s));
+    }
+    basic_value(const local_date& ld, detail::region reg,
+                std::vector<std::string> cm)
+        : type_(value_t::local_date),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->local_date_, ld);
+    }
+    basic_value(const local_time& lt, detail::region reg,
+                std::vector<std::string> cm)
+        : type_(value_t::local_time),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->local_time_, lt);
+    }
+    basic_value(const local_datetime& ldt, detail::region reg,
+                std::vector<std::string> cm)
+        : type_(value_t::local_datetime),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->local_datetime_, ldt);
+    }
+    basic_value(const offset_datetime& odt, detail::region reg,
+                std::vector<std::string> cm)
+        : type_(value_t::offset_datetime),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->offset_datetime_, odt);
+    }
+    basic_value(const array_type& ary, detail::region reg,
+                std::vector<std::string> cm)
+        : type_(value_t::array),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->array_, ary);
+    }
+    basic_value(const table_type& tab, detail::region reg,
+                std::vector<std::string> cm)
+        : type_(value_t::table),
+          region_info_(std::make_shared<detail::region>(std::move(reg))),
+          comments_(std::move(cm))
+    {
+        assigner(this->table_, tab);
+    }
+
+    template<typename T, typename std::enable_if<
+        detail::is_exact_toml_type<T, value_type>::value,
+        std::nullptr_t>::type = nullptr>
+    basic_value(std::pair<T, detail::region> parse_result, std::vector<std::string> com)
+        : basic_value(std::move(parse_result.first),
+                      std::move(parse_result.second),
+                      std::move(com))
+    {}
+
+    // type checking and casting ============================================
+
+    template<typename T, typename std::enable_if<
+        detail::is_exact_toml_type<T, value_type>::value,
+        std::nullptr_t>::type = nullptr>
+    bool is() const noexcept
+    {
+        return detail::type_to_enum<T, value_type>::value == this->type_;
+    }
+    bool is(value_t t) const noexcept {return t == this->type_;}
+
+    bool is_uninitialized()   const noexcept {return this->is(value_t::empty          );}
+    bool is_boolean()         const noexcept {return this->is(value_t::boolean        );}
+    bool is_integer()         const noexcept {return this->is(value_t::integer        );}
+    bool is_floating()        const noexcept {return this->is(value_t::floating       );}
+    bool is_string()          const noexcept {return this->is(value_t::string         );}
+    bool is_offset_datetime() const noexcept {return this->is(value_t::offset_datetime);}
+    bool is_local_datetime()  const noexcept {return this->is(value_t::local_datetime );}
+    bool is_local_date()      const noexcept {return this->is(value_t::local_date     );}
+    bool is_local_time()      const noexcept {return this->is(value_t::local_time     );}
+    bool is_array()           const noexcept {return this->is(value_t::array          );}
+    bool is_table()           const noexcept {return this->is(value_t::table          );}
+
+    value_t type() const noexcept {return type_;}
+
+    template<value_t T>
+    typename detail::enum_to_type<T, value_type>::type&       cast() &
+    {
+        if(this->type_ != T)
+        {
+            detail::throw_bad_cast<T>("toml::value::cast: ", this->type_, *this);
+        }
+        return detail::switch_cast<T>::invoke(*this);
+    }
+    template<value_t T>
+    typename detail::enum_to_type<T, value_type>::type const& cast() const&
+    {
+        if(this->type_ != T)
+        {
+            detail::throw_bad_cast<T>("toml::value::cast: ", this->type_, *this);
+        }
+        return detail::switch_cast<T>::invoke(*this);
+    }
+    template<value_t T>
+    typename detail::enum_to_type<T, value_type>::type&&      cast() &&
+    {
+        if(this->type_ != T)
+        {
+            detail::throw_bad_cast<T>("toml::value::cast: ", this->type_, *this);
+        }
+        return detail::switch_cast<T>::invoke(std::move(*this));
+    }
+
+    // ------------------------------------------------------------------------
+    // nothrow version
+
+    boolean         const& as_boolean        (const std::nothrow_t&) const& noexcept {return this->boolean_;}
+    integer         const& as_integer        (const std::nothrow_t&) const& noexcept {return this->integer_;}
+    floating        const& as_floating       (const std::nothrow_t&) const& noexcept {return this->floating_;}
+    string          const& as_string         (const std::nothrow_t&) const& noexcept {return this->string_;}
+    offset_datetime const& as_offset_datetime(const std::nothrow_t&) const& noexcept {return this->offset_datetime_;}
+    local_datetime  const& as_local_datetime (const std::nothrow_t&) const& noexcept {return this->local_datetime_;}
+    local_date      const& as_local_date     (const std::nothrow_t&) const& noexcept {return this->local_date_;}
+    local_time      const& as_local_time     (const std::nothrow_t&) const& noexcept {return this->local_time_;}
+    array_type      const& as_array          (const std::nothrow_t&) const& noexcept {return this->array_.value();}
+    table_type      const& as_table          (const std::nothrow_t&) const& noexcept {return this->table_.value();}
+
+    boolean        & as_boolean        (const std::nothrow_t&) & noexcept {return this->boolean_;}
+    integer        & as_integer        (const std::nothrow_t&) & noexcept {return this->integer_;}
+    floating       & as_floating       (const std::nothrow_t&) & noexcept {return this->floating_;}
+    string         & as_string         (const std::nothrow_t&) & noexcept {return this->string_;}
+    offset_datetime& as_offset_datetime(const std::nothrow_t&) & noexcept {return this->offset_datetime_;}
+    local_datetime & as_local_datetime (const std::nothrow_t&) & noexcept {return this->local_datetime_;}
+    local_date     & as_local_date     (const std::nothrow_t&) & noexcept {return this->local_date_;}
+    local_time     & as_local_time     (const std::nothrow_t&) & noexcept {return this->local_time_;}
+    array_type     & as_array          (const std::nothrow_t&) & noexcept {return this->array_.value();}
+    table_type     & as_table          (const std::nothrow_t&) & noexcept {return this->table_.value();}
+
+    boolean        && as_boolean        (const std::nothrow_t&) && noexcept {return std::move(this->boolean_);}
+    integer        && as_integer        (const std::nothrow_t&) && noexcept {return std::move(this->integer_);}
+    floating       && as_floating       (const std::nothrow_t&) && noexcept {return std::move(this->floating_);}
+    string         && as_string         (const std::nothrow_t&) && noexcept {return std::move(this->string_);}
+    offset_datetime&& as_offset_datetime(const std::nothrow_t&) && noexcept {return std::move(this->offset_datetime_);}
+    local_datetime && as_local_datetime (const std::nothrow_t&) && noexcept {return std::move(this->local_datetime_);}
+    local_date     && as_local_date     (const std::nothrow_t&) && noexcept {return std::move(this->local_date_);}
+    local_time     && as_local_time     (const std::nothrow_t&) && noexcept {return std::move(this->local_time_);}
+    array_type     && as_array          (const std::nothrow_t&) && noexcept {return std::move(this->array_.value());}
+    table_type     && as_table          (const std::nothrow_t&) && noexcept {return std::move(this->table_.value());}
+
+    // ========================================================================
+    // throw version
+    // ------------------------------------------------------------------------
+    // const reference {{{
+
+    boolean const& as_boolean() const&
+    {
+        if(this->type_ != value_t::boolean)
+        {
+            detail::throw_bad_cast<value_t::boolean>(
+                    "toml::value::as_boolean(): ", this->type_, *this);
+        }
+        return this->boolean_;
+    }
+    integer const& as_integer() const&
+    {
+        if(this->type_ != value_t::integer)
+        {
+            detail::throw_bad_cast<value_t::integer>(
+                    "toml::value::as_integer(): ", this->type_, *this);
+        }
+        return this->integer_;
+    }
+    floating const& as_floating() const&
+    {
+        if(this->type_ != value_t::floating)
+        {
+            detail::throw_bad_cast<value_t::floating>(
+                    "toml::value::as_floating(): ", this->type_, *this);
+        }
+        return this->floating_;
+    }
+    string const& as_string() const&
+    {
+        if(this->type_ != value_t::string)
+        {
+            detail::throw_bad_cast<value_t::string>(
+                    "toml::value::as_string(): ", this->type_, *this);
+        }
+        return this->string_;
+    }
+    offset_datetime const& as_offset_datetime() const&
+    {
+        if(this->type_ != value_t::offset_datetime)
+        {
+            detail::throw_bad_cast<value_t::offset_datetime>(
+                    "toml::value::as_offset_datetime(): ", this->type_, *this);
+        }
+        return this->offset_datetime_;
+    }
+    local_datetime const& as_local_datetime() const&
+    {
+        if(this->type_ != value_t::local_datetime)
+        {
+            detail::throw_bad_cast<value_t::local_datetime>(
+                    "toml::value::as_local_datetime(): ", this->type_, *this);
+        }
+        return this->local_datetime_;
+    }
+    local_date const& as_local_date() const&
+    {
+        if(this->type_ != value_t::local_date)
+        {
+            detail::throw_bad_cast<value_t::local_date>(
+                    "toml::value::as_local_date(): ", this->type_, *this);
+        }
+        return this->local_date_;
+    }
+    local_time const& as_local_time() const&
+    {
+        if(this->type_ != value_t::local_time)
+        {
+            detail::throw_bad_cast<value_t::local_time>(
+                    "toml::value::as_local_time(): ", this->type_, *this);
+        }
+        return this->local_time_;
+    }
+    array_type const& as_array() const&
+    {
+        if(this->type_ != value_t::array)
+        {
+            detail::throw_bad_cast<value_t::array>(
+                    "toml::value::as_array(): ", this->type_, *this);
+        }
+        return this->array_.value();
+    }
+    table_type const& as_table() const&
+    {
+        if(this->type_ != value_t::table)
+        {
+            detail::throw_bad_cast<value_t::table>(
+                    "toml::value::as_table(): ", this->type_, *this);
+        }
+        return this->table_.value();
+    }
+    // }}}
+    // ------------------------------------------------------------------------
+    // nonconst reference {{{
+
+    boolean & as_boolean() &
+    {
+        if(this->type_ != value_t::boolean)
+        {
+            detail::throw_bad_cast<value_t::boolean>(
+                    "toml::value::as_boolean(): ", this->type_, *this);
+        }
+        return this->boolean_;
+    }
+    integer & as_integer() &
+    {
+        if(this->type_ != value_t::integer)
+        {
+            detail::throw_bad_cast<value_t::integer>(
+                    "toml::value::as_integer(): ", this->type_, *this);
+        }
+        return this->integer_;
+    }
+    floating & as_floating() &
+    {
+        if(this->type_ != value_t::floating)
+        {
+            detail::throw_bad_cast<value_t::floating>(
+                    "toml::value::as_floating(): ", this->type_, *this);
+        }
+        return this->floating_;
+    }
+    string & as_string() &
+    {
+        if(this->type_ != value_t::string)
+        {
+            detail::throw_bad_cast<value_t::string>(
+                    "toml::value::as_string(): ", this->type_, *this);
+        }
+        return this->string_;
+    }
+    offset_datetime & as_offset_datetime() &
+    {
+        if(this->type_ != value_t::offset_datetime)
+        {
+            detail::throw_bad_cast<value_t::offset_datetime>(
+                    "toml::value::as_offset_datetime(): ", this->type_, *this);
+        }
+        return this->offset_datetime_;
+    }
+    local_datetime & as_local_datetime() &
+    {
+        if(this->type_ != value_t::local_datetime)
+        {
+            detail::throw_bad_cast<value_t::local_datetime>(
+                    "toml::value::as_local_datetime(): ", this->type_, *this);
+        }
+        return this->local_datetime_;
+    }
+    local_date & as_local_date() &
+    {
+        if(this->type_ != value_t::local_date)
+        {
+            detail::throw_bad_cast<value_t::local_date>(
+                    "toml::value::as_local_date(): ", this->type_, *this);
+        }
+        return this->local_date_;
+    }
+    local_time & as_local_time() &
+    {
+        if(this->type_ != value_t::local_time)
+        {
+            detail::throw_bad_cast<value_t::local_time>(
+                    "toml::value::as_local_time(): ", this->type_, *this);
+        }
+        return this->local_time_;
+    }
+    array_type & as_array() &
+    {
+        if(this->type_ != value_t::array)
+        {
+            detail::throw_bad_cast<value_t::array>(
+                    "toml::value::as_array(): ", this->type_, *this);
+        }
+        return this->array_.value();
+    }
+    table_type & as_table() &
+    {
+        if(this->type_ != value_t::table)
+        {
+            detail::throw_bad_cast<value_t::table>(
+                    "toml::value::as_table(): ", this->type_, *this);
+        }
+        return this->table_.value();
+    }
+
+    // }}}
+    // ------------------------------------------------------------------------
+    // rvalue reference {{{
+
+    boolean && as_boolean() &&
+    {
+        if(this->type_ != value_t::boolean)
+        {
+            detail::throw_bad_cast<value_t::boolean>(
+                    "toml::value::as_boolean(): ", this->type_, *this);
+        }
+        return std::move(this->boolean_);
+    }
+    integer && as_integer() &&
+    {
+        if(this->type_ != value_t::integer)
+        {
+            detail::throw_bad_cast<value_t::integer>(
+                    "toml::value::as_integer(): ", this->type_, *this);
+        }
+        return std::move(this->integer_);
+    }
+    floating && as_floating() &&
+    {
+        if(this->type_ != value_t::floating)
+        {
+            detail::throw_bad_cast<value_t::floating>(
+                    "toml::value::as_floating(): ", this->type_, *this);
+        }
+        return std::move(this->floating_);
+    }
+    string && as_string() &&
+    {
+        if(this->type_ != value_t::string)
+        {
+            detail::throw_bad_cast<value_t::string>(
+                    "toml::value::as_string(): ", this->type_, *this);
+        }
+        return std::move(this->string_);
+    }
+    offset_datetime && as_offset_datetime() &&
+    {
+        if(this->type_ != value_t::offset_datetime)
+        {
+            detail::throw_bad_cast<value_t::offset_datetime>(
+                    "toml::value::as_offset_datetime(): ", this->type_, *this);
+        }
+        return std::move(this->offset_datetime_);
+    }
+    local_datetime && as_local_datetime() &&
+    {
+        if(this->type_ != value_t::local_datetime)
+        {
+            detail::throw_bad_cast<value_t::local_datetime>(
+                    "toml::value::as_local_datetime(): ", this->type_, *this);
+        }
+        return std::move(this->local_datetime_);
+    }
+    local_date && as_local_date() &&
+    {
+        if(this->type_ != value_t::local_date)
+        {
+            detail::throw_bad_cast<value_t::local_date>(
+                    "toml::value::as_local_date(): ", this->type_, *this);
+        }
+        return std::move(this->local_date_);
+    }
+    local_time && as_local_time() &&
+    {
+        if(this->type_ != value_t::local_time)
+        {
+            detail::throw_bad_cast<value_t::local_time>(
+                    "toml::value::as_local_time(): ", this->type_, *this);
+        }
+        return std::move(this->local_time_);
+    }
+    array_type && as_array() &&
+    {
+        if(this->type_ != value_t::array)
+        {
+            detail::throw_bad_cast<value_t::array>(
+                    "toml::value::as_array(): ", this->type_, *this);
+        }
+        return std::move(this->array_.value());
+    }
+    table_type && as_table() &&
+    {
+        if(this->type_ != value_t::table)
+        {
+            detail::throw_bad_cast<value_t::table>(
+                    "toml::value::as_table(): ", this->type_, *this);
+        }
+        return std::move(this->table_.value());
+    }
+    // }}}
+
+    // accessors =============================================================
+    //
+    // may throw type_error or out_of_range
+    //
+    value_type&       at(const key& k)
+    {
+        if(!this->is_table())
+        {
+            detail::throw_bad_cast<value_t::table>(
+                "toml::value::at(key): ", this->type_, *this);
+        }
+        if(this->as_table(std::nothrow).count(k) == 0)
+        {
+            detail::throw_key_not_found_error(*this, k);
+        }
+        return this->as_table(std::nothrow).at(k);
+    }
+    value_type const& at(const key& k) const
+    {
+        if(!this->is_table())
+        {
+            detail::throw_bad_cast<value_t::table>(
+                "toml::value::at(key): ", this->type_, *this);
+        }
+        if(this->as_table(std::nothrow).count(k) == 0)
+        {
+            detail::throw_key_not_found_error(*this, k);
+        }
+        return this->as_table(std::nothrow).at(k);
+    }
+    value_type&       operator[](const key& k)
+    {
+        if(this->is_uninitialized())
+        {
+            *this = table_type{};
+        }
+        else if(!this->is_table()) // initialized, but not a table
+        {
+            detail::throw_bad_cast<value_t::table>(
+                "toml::value::operator[](key): ", this->type_, *this);
+        }
+        return this->as_table(std::nothrow)[k];
+    }
+
+    value_type&       at(const std::size_t idx)
+    {
+        if(!this->is_array())
+        {
+            detail::throw_bad_cast<value_t::array>(
+                "toml::value::at(idx): ", this->type_, *this);
+        }
+        if(this->as_array(std::nothrow).size() <= idx)
+        {
+            throw std::out_of_range(detail::format_underline(
+                "toml::value::at(idx): no element corresponding to the index", {
+                    {this->location(), concat_to_string("the length is ",
+                        this->as_array(std::nothrow).size(),
+                        ", and the specified index is ", idx)}
+                }));
+        }
+        return this->as_array().at(idx);
+    }
+    value_type const& at(const std::size_t idx) const
+    {
+        if(!this->is_array())
+        {
+            detail::throw_bad_cast<value_t::array>(
+                "toml::value::at(idx): ", this->type_, *this);
+        }
+        if(this->as_array(std::nothrow).size() <= idx)
+        {
+            throw std::out_of_range(detail::format_underline(
+                "toml::value::at(idx): no element corresponding to the index", {
+                    {this->location(), concat_to_string("the length is ",
+                        this->as_array(std::nothrow).size(),
+                        ", and the specified index is ", idx)}
+                }));
+        }
+        return this->as_array(std::nothrow).at(idx);
+    }
+
+    value_type&       operator[](const std::size_t idx) noexcept
+    {
+        // no check...
+        return this->as_array(std::nothrow)[idx];
+    }
+    value_type const& operator[](const std::size_t idx) const noexcept
+    {
+        // no check...
+        return this->as_array(std::nothrow)[idx];
+    }
+
+    void push_back(const value_type& x)
+    {
+        if(!this->is_array())
+        {
+            detail::throw_bad_cast<value_t::array>(
+                "toml::value::push_back(value): ", this->type_, *this);
+        }
+        this->as_array(std::nothrow).push_back(x);
+        return;
+    }
+    void push_back(value_type&& x)
+    {
+        if(!this->is_array())
+        {
+            detail::throw_bad_cast<value_t::array>(
+                "toml::value::push_back(value): ", this->type_, *this);
+        }
+        this->as_array(std::nothrow).push_back(std::move(x));
+        return;
+    }
+
+    template<typename ... Ts>
+    value_type& emplace_back(Ts&& ... args)
+    {
+        if(!this->is_array())
+        {
+            detail::throw_bad_cast<value_t::array>(
+                "toml::value::emplace_back(...): ", this->type_, *this);
+        }
+        this->as_array(std::nothrow).emplace_back(std::forward<Ts>(args) ...);
+        return this->as_array(std::nothrow).back();
+    }
+
+    std::size_t size() const
+    {
+        switch(this->type_)
+        {
+            case value_t::array:
+            {
+                return this->as_array(std::nothrow).size();
+            }
+            case value_t::table:
+            {
+                return this->as_table(std::nothrow).size();
+            }
+            case value_t::string:
+            {
+                return this->as_string(std::nothrow).str.size();
+            }
+            default:
+            {
+                throw type_error(detail::format_underline(
+                    "toml::value::size(): bad_cast to container types", {
+                        {this->location(),
+                         concat_to_string("the actual type is ", this->type_)}
+                    }), this->location());
+            }
+        }
+    }
+
+    std::size_t count(const key_type& k) const
+    {
+        if(!this->is_table())
+        {
+            detail::throw_bad_cast<value_t::table>(
+                "toml::value::count(key): ", this->type_, *this);
+        }
+        return this->as_table(std::nothrow).count(k);
+    }
+
+    bool contains(const key_type& k) const
+    {
+        if(!this->is_table())
+        {
+            detail::throw_bad_cast<value_t::table>(
+                "toml::value::contains(key): ", this->type_, *this);
+        }
+        return (this->as_table(std::nothrow).count(k) != 0);
+    }
+
+    source_location location() const
+    {
+        return source_location(this->region_info_.get());
+    }
+
+    comment_type const& comments() const noexcept {return this->comments_;}
+    comment_type&       comments()       noexcept {return this->comments_;}
+
+  private:
+
+    void cleanup() noexcept
+    {
+        switch(this->type_)
+        {
+            case value_t::string : {string_.~string();       return;}
+            case value_t::array  : {array_.~array_storage(); return;}
+            case value_t::table  : {table_.~table_storage(); return;}
+            default              : return;
+        }
+    }
+
+    // for error messages
+    template<typename Value>
+    friend region_base const* detail::get_region(const Value& v);
+
+    template<typename Value>
+    friend void detail::change_region(Value& v, detail::region reg);
+
+  private:
+
+    using array_storage = detail::storage<array_type>;
+    using table_storage = detail::storage<table_type>;
+
+    value_t type_;
+    union
+    {
+        boolean         boolean_;
+        integer         integer_;
+        floating        floating_;
+        string          string_;
+        offset_datetime offset_datetime_;
+        local_datetime  local_datetime_;
+        local_date      local_date_;
+        local_time      local_time_;
+        array_storage   array_;
+        table_storage   table_;
+    };
+    std::shared_ptr<region_base> region_info_;
+    comment_type                 comments_;
+};
+
+// default toml::value and default array/table.
+// TOML11_DEFAULT_COMMENT_STRATEGY is defined in comments.hpp
+using value = basic_value<TOML11_DEFAULT_COMMENT_STRATEGY, std::unordered_map, std::vector>;
+using array = typename value::array_type;
+using table = typename value::table_type;
+
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+inline bool
+operator==(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs)
+{
+    if(lhs.type()     != rhs.type())     {return false;}
+    if(lhs.comments() != rhs.comments()) {return false;}
+
+    switch(lhs.type())
+    {
+        case value_t::boolean  :
+        {
+            return lhs.as_boolean() == rhs.as_boolean();
+        }
+        case value_t::integer  :
+        {
+            return lhs.as_integer() == rhs.as_integer();
+        }
+        case value_t::floating :
+        {
+            return lhs.as_floating() == rhs.as_floating();
+        }
+        case value_t::string   :
+        {
+            return lhs.as_string() == rhs.as_string();
+        }
+        case value_t::offset_datetime:
+        {
+            return lhs.as_offset_datetime() == rhs.as_offset_datetime();
+        }
+        case value_t::local_datetime:
+        {
+            return lhs.as_local_datetime() == rhs.as_local_datetime();
+        }
+        case value_t::local_date:
+        {
+            return lhs.as_local_date() == rhs.as_local_date();
+        }
+        case value_t::local_time:
+        {
+            return lhs.as_local_time() == rhs.as_local_time();
+        }
+        case value_t::array    :
+        {
+            return lhs.as_array() == rhs.as_array();
+        }
+        case value_t::table    :
+        {
+            return lhs.as_table() == rhs.as_table();
+        }
+        case value_t::empty    : {return true; }
+        default:                 {return false;}
+    }
+}
+
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+inline bool operator!=(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs)
+{
+    return !(lhs == rhs);
+}
+
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+typename std::enable_if<detail::conjunction<
+    detail::is_comparable<typename basic_value<C, T, A>::array_type>,
+    detail::is_comparable<typename basic_value<C, T, A>::table_type>
+    >::value, bool>::type
+operator<(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs)
+{
+    if(lhs.type() != rhs.type()){return (lhs.type() < rhs.type());}
+    switch(lhs.type())
+    {
+        case value_t::boolean  :
+        {
+            return lhs.as_boolean() <  rhs.as_boolean() ||
+                  (lhs.as_boolean() == rhs.as_boolean() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::integer  :
+        {
+            return lhs.as_integer() <  rhs.as_integer() ||
+                  (lhs.as_integer() == rhs.as_integer() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::floating :
+        {
+            return lhs.as_floating() <  rhs.as_floating() ||
+                  (lhs.as_floating() == rhs.as_floating() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::string   :
+        {
+            return lhs.as_string() <  rhs.as_string() ||
+                  (lhs.as_string() == rhs.as_string() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::offset_datetime:
+        {
+            return lhs.as_offset_datetime() <  rhs.as_offset_datetime() ||
+                  (lhs.as_offset_datetime() == rhs.as_offset_datetime() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::local_datetime:
+        {
+            return lhs.as_local_datetime() <  rhs.as_local_datetime() ||
+                  (lhs.as_local_datetime() == rhs.as_local_datetime() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::local_date:
+        {
+            return lhs.as_local_date() <  rhs.as_local_date() ||
+                  (lhs.as_local_date() == rhs.as_local_date() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::local_time:
+        {
+            return lhs.as_local_time() <  rhs.as_local_time() ||
+                  (lhs.as_local_time() == rhs.as_local_time() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::array    :
+        {
+            return lhs.as_array() <  rhs.as_array() ||
+                  (lhs.as_array() == rhs.as_array() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::table    :
+        {
+            return lhs.as_table() <  rhs.as_table() ||
+                  (lhs.as_table() == rhs.as_table() &&
+                   lhs.comments() < rhs.comments());
+        }
+        case value_t::empty    :
+        {
+            return lhs.comments() < rhs.comments();
+        }
+        default:
+        {
+            return lhs.comments() < rhs.comments();
+        }
+    }
+}
+
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+typename std::enable_if<detail::conjunction<
+    detail::is_comparable<typename basic_value<C, T, A>::array_type>,
+    detail::is_comparable<typename basic_value<C, T, A>::table_type>
+    >::value, bool>::type
+operator<=(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs)
+{
+    return (lhs < rhs) || (lhs == rhs);
+}
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+typename std::enable_if<detail::conjunction<
+    detail::is_comparable<typename basic_value<C, T, A>::array_type>,
+    detail::is_comparable<typename basic_value<C, T, A>::table_type>
+    >::value, bool>::type
+operator>(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs)
+{
+    return !(lhs <= rhs);
+}
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+typename std::enable_if<detail::conjunction<
+    detail::is_comparable<typename basic_value<C, T, A>::array_type>,
+    detail::is_comparable<typename basic_value<C, T, A>::table_type>
+    >::value, bool>::type
+operator>=(const basic_value<C, T, A>& lhs, const basic_value<C, T, A>& rhs)
+{
+    return !(lhs < rhs);
+}
+
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+inline std::string format_error(const std::string& err_msg,
+        const basic_value<C, T, A>& v, const std::string& comment,
+        std::vector<std::string> hints = {},
+        const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
+{
+    return detail::format_underline(err_msg, {{v.location(), comment}},
+                                    std::move(hints), colorize);
+}
+
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+inline std::string format_error(const std::string& err_msg,
+        const toml::basic_value<C, T, A>& v1, const std::string& comment1,
+        const toml::basic_value<C, T, A>& v2, const std::string& comment2,
+        std::vector<std::string> hints = {},
+        const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
+{
+    return detail::format_underline(err_msg, {
+            {v1.location(), comment1}, {v2.location(), comment2}
+        }, std::move(hints), colorize);
+}
+
+template<typename C, template<typename ...> class T, template<typename ...> class A>
+inline std::string format_error(const std::string& err_msg,
+        const toml::basic_value<C, T, A>& v1, const std::string& comment1,
+        const toml::basic_value<C, T, A>& v2, const std::string& comment2,
+        const toml::basic_value<C, T, A>& v3, const std::string& comment3,
+        std::vector<std::string> hints = {},
+        const bool colorize = TOML11_ERROR_MESSAGE_COLORIZED)
+{
+    return detail::format_underline(err_msg, {{v1.location(), comment1},
+            {v2.location(), comment2}, {v3.location(), comment3}
+        }, std::move(hints), colorize);
+}
+
+template<typename Visitor, typename C,
+         template<typename ...> class T, template<typename ...> class A>
+detail::return_type_of_t<Visitor, const toml::boolean&>
+visit(Visitor&& visitor, const toml::basic_value<C, T, A>& v)
+{
+    switch(v.type())
+    {
+        case value_t::boolean        : {return visitor(v.as_boolean        ());}
+        case value_t::integer        : {return visitor(v.as_integer        ());}
+        case value_t::floating       : {return visitor(v.as_floating       ());}
+        case value_t::string         : {return visitor(v.as_string         ());}
+        case value_t::offset_datetime: {return visitor(v.as_offset_datetime());}
+        case value_t::local_datetime : {return visitor(v.as_local_datetime ());}
+        case value_t::local_date     : {return visitor(v.as_local_date     ());}
+        case value_t::local_time     : {return visitor(v.as_local_time     ());}
+        case value_t::array          : {return visitor(v.as_array          ());}
+        case value_t::table          : {return visitor(v.as_table          ());}
+        case value_t::empty          : break;
+        default: break;
+    }
+    throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
+            "does not have any valid basic_value.", v, "here"));
+}
+
+template<typename Visitor, typename C,
+         template<typename ...> class T, template<typename ...> class A>
+detail::return_type_of_t<Visitor, toml::boolean&>
+visit(Visitor&& visitor, toml::basic_value<C, T, A>& v)
+{
+    switch(v.type())
+    {
+        case value_t::boolean        : {return visitor(v.as_boolean        ());}
+        case value_t::integer        : {return visitor(v.as_integer        ());}
+        case value_t::floating       : {return visitor(v.as_floating       ());}
+        case value_t::string         : {return visitor(v.as_string         ());}
+        case value_t::offset_datetime: {return visitor(v.as_offset_datetime());}
+        case value_t::local_datetime : {return visitor(v.as_local_datetime ());}
+        case value_t::local_date     : {return visitor(v.as_local_date     ());}
+        case value_t::local_time     : {return visitor(v.as_local_time     ());}
+        case value_t::array          : {return visitor(v.as_array          ());}
+        case value_t::table          : {return visitor(v.as_table          ());}
+        case value_t::empty          : break;
+        default: break;
+    }
+    throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
+            "does not have any valid basic_value.", v, "here"));
+}
+
+template<typename Visitor, typename C,
+         template<typename ...> class T, template<typename ...> class A>
+detail::return_type_of_t<Visitor, toml::boolean&&>
+visit(Visitor&& visitor, toml::basic_value<C, T, A>&& v)
+{
+    switch(v.type())
+    {
+        case value_t::boolean        : {return visitor(std::move(v.as_boolean        ()));}
+        case value_t::integer        : {return visitor(std::move(v.as_integer        ()));}
+        case value_t::floating       : {return visitor(std::move(v.as_floating       ()));}
+        case value_t::string         : {return visitor(std::move(v.as_string         ()));}
+        case value_t::offset_datetime: {return visitor(std::move(v.as_offset_datetime()));}
+        case value_t::local_datetime : {return visitor(std::move(v.as_local_datetime ()));}
+        case value_t::local_date     : {return visitor(std::move(v.as_local_date     ()));}
+        case value_t::local_time     : {return visitor(std::move(v.as_local_time     ()));}
+        case value_t::array          : {return visitor(std::move(v.as_array          ()));}
+        case value_t::table          : {return visitor(std::move(v.as_table          ()));}
+        case value_t::empty          : break;
+        default: break;
+    }
+    throw std::runtime_error(format_error("[error] toml::visit: toml::basic_value "
+            "does not have any valid basic_value.", v, "here"));
+}
+
+}// toml
+#endif// TOML11_VALUE
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/dep/toml11/toml/version.hpp	Wed Jun 12 05:25:41 2024 -0400
@@ -0,0 +1,42 @@
+#ifndef TOML11_VERSION_HPP
+#define TOML11_VERSION_HPP
+
+// This file checks C++ version.
+
+#ifndef __cplusplus
+#    error "__cplusplus is not defined"
+#endif
+
+// Since MSVC does not define `__cplusplus` correctly unless you pass
+// `/Zc:__cplusplus` when compiling, the workaround macros are added.
+// Those enables you to define version manually or to use MSVC specific
+// version macro automatically.
+//
+// The value of `__cplusplus` macro is defined in the C++ standard spec, but
+// MSVC ignores the value, maybe because of backward compatibility. Instead,
+// MSVC defines _MSVC_LANG that has the same value as __cplusplus defined in
+// the C++ standard. First we check the manual version definition, and then
+// we check if _MSVC_LANG is defined. If neither, use normal `__cplusplus`.
+//
+// FYI: https://docs.microsoft.com/en-us/cpp/build/reference/zc-cplusplus?view=msvc-170
+//      https://docs.microsoft.com/en-us/cpp/preprocessor/predefined-macros?view=msvc-170
+//
+#if   defined(TOML11_ENFORCE_CXX11)
+#  define TOML11_CPLUSPLUS_STANDARD_VERSION 201103L
+#elif defined(TOML11_ENFORCE_CXX14)
+#  define TOML11_CPLUSPLUS_STANDARD_VERSION 201402L
+#elif defined(TOML11_ENFORCE_CXX17)
+#  define TOML11_CPLUSPLUS_STANDARD_VERSION 201703L
+#elif defined(TOML11_ENFORCE_CXX20)
+#  define TOML11_CPLUSPLUS_STANDARD_VERSION 202002L
+#elif defined(_MSVC_LANG) && defined(_MSC_VER) && 1910 <= _MSC_VER
+#  define TOML11_CPLUSPLUS_STANDARD_VERSION _MSVC_LANG
+#else
+#  define TOML11_CPLUSPLUS_STANDARD_VERSION __cplusplus
+#endif
+
+#if TOML11_CPLUSPLUS_STANDARD_VERSION < 201103L && _MSC_VER < 1900
+#    error "toml11 requires C++11 or later."
+#endif
+
+#endif// TOML11_VERSION_HPP
--- a/include/core/config.h	Wed Jun 12 04:07:10 2024 -0400
+++ b/include/core/config.h	Wed Jun 12 05:25:41 2024 -0400
@@ -70,6 +70,6 @@
 constexpr std::string_view CONFIG_DIR = "minori";
 #endif
 
-constexpr std::string_view CONFIG_NAME = "config.ini";
+constexpr std::string_view CONFIG_NAME = "config.toml";
 
 #endif // MINORI_CORE_CONFIG_H_
--- a/include/core/ini.h	Wed Jun 12 04:07:10 2024 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,21 +0,0 @@
-#ifndef MINORI_CORE_INI_H_
-#define MINORI_CORE_INI_H_
-
-#define MINI_CASE_SENSITIVE
-#include "core/strings.h"
-#include "mini/ini.h"
-#include <string>
-
-namespace INI {
-
-std::string GetIniString(const mINI::INIStructure& ini, const std::string& section, const std::string& key, const std::string& def);
-bool GetIniBool(const mINI::INIStructure& ini, const std::string& section, const std::string& key, bool def);
-
-template<typename T>
-T GetIniInteger(const mINI::INIStructure& ini, const std::string& section, const std::string& key, T def) {
-	return Strings::ToInt<T>(GetIniString(ini, section, key, ""), def);
-}
-
-} // namespace INI
-
-#endif
--- a/src/core/config.cc	Wed Jun 12 04:07:10 2024 -0400
+++ b/src/core/config.cc	Wed Jun 12 05:25:41 2024 -0400
@@ -1,11 +1,6 @@
-/**
- * config.cpp:
- * parses the config... lol
- **/
 #include "core/config.h"
 #include "core/anime.h"
 #include "core/filesystem.h"
-#include "core/ini.h"
 #include "core/json.h"
 #include "core/strings.h"
 #include "gui/translate/anime.h"
@@ -20,59 +15,60 @@
 #include <fstream>
 #include <limits.h>
 
+#include <toml11/toml.hpp>
+
 #include <QFile>
 #include <QTextStream>
 
 #include <iostream>
 
-/* I'll use an INI-based config file instead of using an
- * XML file like Taiga.
- *
- * It technically isn't to spec, because I'm making these case-sensitive.
- * Boohoo.
- */
+/* NOTE: This config file is prone to breakage, as Minori is alpha software and
+ * as such nothing is constant. */
 
 int Config::Load() {
 	std::filesystem::path cfg_path = Filesystem::GetConfigPath();
 
-	mINI::INIFile file(cfg_path.u8string());
-	mINI::INIStructure ini;
-	file.read(ini);
+	std::ifstream ifs(cfg_path, std::ios_base::binary);
+	if (!ifs.good())
+		return 0;
 
-	service = Translate::ToService(INI::GetIniString(ini, "General", "Service", "None"));
+	toml::value data;
 
-	anime_list.score_format =
-	    Translate::ToScoreFormat(INI::GetIniString(ini, "Anime List", "Score format", "POINT_100"));
-	anime_list.language =
-	    Translate::ToLanguage(INI::GetIniString(ini, "Anime List", "Title language", "Romaji"));
-	anime_list.display_aired_episodes = INI::GetIniBool(ini, "Anime List", "Display only aired episodes", true);
-	anime_list.display_available_episodes =
-	    INI::GetIniBool(ini, "Anime List", "Display only available episodes in library", true);
-	anime_list.highlight_anime_if_available =
-	    INI::GetIniBool(ini, "Anime List", "Highlight anime if available", true);
+	try {
+		data = toml::parse(ifs);
+	} catch (const std::exception& ex) {
+		std::cerr << "config: failed to parse toml with error " << ex.what() << std::endl;
+		return 0;
+	}
+
+	service = Translate::ToService(toml::find_or(data, "General", "Service", "None"));
+	locale.RefreshAvailableLocales();
+	locale.SetActiveLocale(QLocale(Strings::ToQString(toml::find_or(data, "General", "Locale", "en_US"))));
+
 
-	if (anime_list.highlight_anime_if_available) // sanity check
-		anime_list.highlighted_anime_above_others =
-		    INI::GetIniBool(ini, "Anime List", "Display highlighted anime above others", false);
-	else
-		anime_list.highlighted_anime_above_others = false;
-
-	auth.anilist.auth_token = INI::GetIniString(ini, "Authentication/AniList", "Auth Token", "");
-	auth.anilist.user_id = INI::GetIniInteger<int>(ini, "Authentication/AniList", "User ID", 0);
+	anime_list.score_format = Translate::ToScoreFormat(toml::find_or(data, "Anime List", "Score format", "100-point"));
+	anime_list.language = Translate::ToLanguage(toml::find_or(data, "Anime List", "Title language", "Romaji"));
+	anime_list.display_aired_episodes = toml::find_or<bool>(data, "Anime List", "Display only aired episodes", true);
+	anime_list.display_available_episodes = toml::find_or<bool>(data, "Anime List", "Display only available episodes in library", true);
+	anime_list.highlight_anime_if_available = toml::find_or<bool>(data, "Anime List", "Highlight anime if available", true);
+	anime_list.highlighted_anime_above_others =
+		(anime_list.highlight_anime_if_available)
+		? toml::find_or<bool>(data, "Anime List", "Display highlighted anime above others", false)
+		: false;
 
-	auth.kitsu.access_token = INI::GetIniString(ini, "Authentication/Kitsu", "Access Token", "");
-	auth.kitsu.access_token_expiration = INI::GetIniInteger<Time::Timestamp>(ini, "Authentication/Kitsu", "Access Token Expiration", 0);
-	auth.kitsu.refresh_token = INI::GetIniString(ini, "Authentication/Kitsu", "Refresh Token", "");
-	auth.kitsu.user_id = INI::GetIniString(ini, "Authentication/Kitsu", "User ID", "");
+	auth.anilist.auth_token = toml::find_or(data, "Authentication/AniList", "Auth Token", "");
+	auth.anilist.user_id = toml::find_or<int>(data, "Authentication/AniList", "User ID", 0);
 
-	torrents.feed_link = INI::GetIniString(ini, "Torrents", "RSS feed",
-	                                       "https://www.tokyotosho.info/rss.php?filter=1,11&zwnj=0");
+	auth.kitsu.access_token = toml::find_or(data, "Authentication/Kitsu", "Access Token", "");
+	auth.kitsu.access_token_expiration = toml::find_or(data, "Authentication/Kitsu", "Access Token Expiration", 0LL);
+	auth.kitsu.refresh_token = toml::find_or(data, "Authentication/Kitsu", "Refresh Token", "");
+	auth.kitsu.user_id = toml::find_or(data, "Authentication/Kitsu", "User ID", "");
 
-	recognition.detect_media_players = INI::GetIniBool(ini, "Recognition", "Detect media players", true);
+	torrents.feed_link = toml::find_or(data, "Torrents", "RSS feed", "https://www.tokyotosho.info/rss.php?filter=1,11&zwnj=0");
 
-	/* lots of dumb logic to import the player data */
+	recognition.detect_media_players = toml::find_or(data, "Recognition", "Detect media players", true);
+
 	{
-		/* load the player data */
 		QFile f(":/players.anisthesia");
 		if (!f.exists())
 			return false;
@@ -94,28 +90,26 @@
 		switch (player.type) {
 			default:
 			case animone::PlayerType::Default:
-				enabled = INI::GetIniBool(ini, "Recognition/Players", player.name, true);
+				enabled = toml::find_or<bool>(data, "Recognition/Players", player.name, true);
 				break;
 			case animone::PlayerType::WebBrowser:
-				enabled = INI::GetIniBool(ini, "Recognition/Browsers", player.name, true);
+				enabled = toml::find_or<bool>(data, "Recognition/Browsers", player.name, true);
 				break;
 		}
 	}
 
-	locale.RefreshAvailableLocales();
-	locale.SetActiveLocale(
-	    QLocale(Strings::ToQString(INI::GetIniString(ini, "General", "Locale", "en_US"))));
+
+	theme.SetTheme(Translate::ToTheme(toml::find_or(data, "Appearance", "Theme", "Default")));
 
-	theme.SetTheme(Translate::ToTheme(INI::GetIniString(ini, "Appearance", "Theme", "Default")));
-
-	{
-		std::vector<std::string> v = Strings::Split(INI::GetIniString(ini, "Library", "Folders", ""), ";");
+	if (data.contains("Library") && data["Library"].contains("Folders")) {
+		const toml::value& folders = toml::find(data, "Library", "Folders");
+		std::vector<std::string> v = toml::get_or<std::vector<std::string>>(folders, {});
 		for (const auto& s : v)
 			if (!library.paths.count(s))
 				library.paths.insert(s);
 	}
 
-	library.real_time_monitor = INI::GetIniBool(ini, "Library", "Real-time monitor", true);
+	library.real_time_monitor = toml::find_or(data, "Library", "Real-time monitor", true);
 
 	return 0;
 }
@@ -124,42 +118,45 @@
 	std::filesystem::path cfg_path = Filesystem::GetConfigPath();
 	Filesystem::CreateDirectories(cfg_path);
 
-	mINI::INIFile file(cfg_path.string());
-	mINI::INIStructure ini;
-
-	ini["General"]["Service"] = Translate::ToString(service);
-	ini["General"]["Locale"] = Strings::ToUtf8String(locale.GetLocale().name());
-
-	ini["Anime List"]["Score format"] = Translate::ToString(anime_list.score_format);
-	ini["Anime List"]["Title language"] = Translate::ToString(anime_list.language);
-	ini["Anime List"]["Display only aired episodes"] = Strings::ToUtf8String(anime_list.display_aired_episodes);
-	ini["Anime List"]["Display only available episodes in library"] = Strings::ToUtf8String(anime_list.display_available_episodes);
-	ini["Anime List"]["Highlight anime if available"] = Strings::ToUtf8String(anime_list.highlight_anime_if_available);
-	ini["Anime List"]["Display highlighted anime above others"] = Strings::ToUtf8String(anime_list.highlighted_anime_above_others);
+	std::ofstream file(cfg_path);
+	if (!file.good())
+		return 0;
 
-	ini["Authentication/AniList"]["Auth Token"] = auth.anilist.auth_token;
-	ini["Authentication/AniList"]["User ID"] = Strings::ToUtf8String(auth.anilist.user_id);
+	toml::value data;
 
-	ini["Authentication/Kitsu"]["Access Token"] = auth.kitsu.access_token;
-	ini["Authentication/Kitsu"]["Access Token Expiration"] = Strings::ToUtf8String(auth.kitsu.access_token_expiration);
-	ini["Authentication/Kitsu"]["Refresh Token"] = auth.kitsu.refresh_token;
-	ini["Authentication/Kitsu"]["User ID"] = auth.kitsu.user_id;
-
-	ini["Appearance"]["Theme"] = Translate::ToString(theme.GetTheme());
-
-	ini["Torrents"]["RSS feed"] = torrents.feed_link;
-
-	ini["Recognition"]["Detect media players"] = Strings::ToUtf8String(recognition.detect_media_players);
+	data["Library"]["Folders"] = library.paths;
+	data["Library"]["Real-time monitor"] = library.real_time_monitor;
 
 	for (const auto& [enabled, player] : recognition.players) {
 		const std::string section = (player.type == animone::PlayerType::WebBrowser) ? "Recognition/Players" : "Recognition/Browsers";
-		ini[section][player.name] = Strings::ToUtf8String(enabled);
+		data[section][player.name] = enabled;
 	}
 
-	ini["Library"]["Folders"] = Strings::Implode(library.paths, ";");
-	ini["Library"]["Real-time monitor"] = Strings::ToUtf8String(library.real_time_monitor);
+	data["Recognition"]["Detect media players"] = recognition.detect_media_players;
+
+	data["Torrents"]["RSS feed"] = torrents.feed_link;
+
+	data["Authentication/Kitsu"]["Access Token"] = auth.kitsu.access_token;
+	data["Authentication/Kitsu"]["Access Token Expiration"] = auth.kitsu.access_token_expiration;
+	data["Authentication/Kitsu"]["Refresh Token"] = auth.kitsu.refresh_token;
+	data["Authentication/Kitsu"]["User ID"] = auth.kitsu.user_id;
+
+	data["Authentication/AniList"]["Auth Token"] = auth.anilist.auth_token;
+	data["Authentication/AniList"]["User ID"] = auth.anilist.user_id;
 
-	file.write(ini);
+	data["Anime List"]["Score format"] = Translate::ToString(anime_list.score_format);
+	data["Anime List"]["Title language"] = Translate::ToString(anime_list.language);
+	data["Anime List"]["Display only aired episodes"] = anime_list.display_aired_episodes;
+	data["Anime List"]["Display only available episodes in library"] = anime_list.display_available_episodes;
+	data["Anime List"]["Highlight anime if available"] = anime_list.highlight_anime_if_available;
+	data["Anime List"]["Display highlighted anime above others"] = anime_list.highlighted_anime_above_others;
+
+	data["Appearance"]["Theme"] = Translate::ToString(theme.GetTheme());
+
+	data["General"]["Service"] = Translate::ToString(service);
+	data["General"]["Locale"] = Strings::ToUtf8String(locale.GetLocale().name());
+
+	file << std::setw(0) << data;
 
 	return 0;
 }
--- a/src/core/ini.cc	Wed Jun 12 04:07:10 2024 -0400
+++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
@@ -1,16 +0,0 @@
-#include "core/ini.h"
-
-namespace INI {
-
-std::string GetIniString(const mINI::INIStructure& ini, const std::string& section, const std::string& key, const std::string& def) {
-	if (!ini.has(section) || !ini.get(section).has(key))
-		return def;
-
-	return ini.get(section).get(key);
-}
-
-bool GetIniBool(const mINI::INIStructure& ini, const std::string& section, const std::string& key, bool def) {
-	return Strings::ToBool(GetIniString(ini, section, key, ""), def);
-}
-
-}
--- a/src/gui/dialog/about.cc	Wed Jun 12 04:07:10 2024 -0400
+++ b/src/gui/dialog/about.cc	Wed Jun 12 05:25:41 2024 -0400
@@ -76,8 +76,6 @@
 	    Strings::ToQString(pugixml_version.to_string()) +
 	    "</a>"
 	    ", "
-	    "<a href=\"https://github.com/pulzed/mINI\">mINI v0.9.14</a>"
-	    ", "
 	    "<a href=\"https://github.com/Neargye/semver\">semver v" +
 	    Strings::ToQString(semver_version.to_string()) +
 	    "</a>"