diff --git a/toml/region.hpp b/toml/region.hpp new file mode 100644 index 0000000..e9ced53 --- /dev/null +++ b/toml/region.hpp @@ -0,0 +1,136 @@ +#ifndef TOML11_REGION_H +#define TOML11_REGION_H +#include +#include +#include +#include + +namespace toml +{ +namespace detail +{ + +// location in a container, normally in a file content. +// shared_ptr points the resource that the iter points. +// it can be used not only for resource handling, but also error message. +template +struct location +{ + using const_iterator = typename Container::const_iterator; + + location(Container cont) + : source(std::make_shared(std::move(cont))), + iter(source->begin()) + {} + location(const location&) = default; + location(location&&) = default; + location& operator=(const location&) = default; + location& operator=(location&&) = default; + ~location() = default; + + std::shared_ptr source; + const_iterator iter; +}; + +// region in a container, normally in a file content. +// shared_ptr points the resource that the iter points. +// combinators returns this. +// it can be used not only for resource handling, but also error message. +template +struct region +{ + using const_iterator = typename Container::const_iterator; + + region(const location& loc) + : first(loc.iter), last(loc.iter), source(loc.source) + {} + region(location&& loc) + : first(loc.iter), last(loc.iter), source(std::move(loc.source)) + {} + + region(const region&) = default; + region(region&&) = default; + region& operator=(const region&) = default; + region& operator=(region&&) = default; + ~region() = default; + + const_iterator first, last; + std::shared_ptr source; +}; + +// to show a better error message. +template +std::string +format_underline(const region& reg, const std::string& msg) +{ + using const_iterator = typename region::const_iterator; + using reverse_iterator = std::reverse_iterator; + const auto line_begin = std::find( + reverse_iterator(reg.first), + reverse_iterator(reg.source->cbegin()), + '\n').base(); + const auto line_end = std::find(reg.last, reg.source->cend(), '\n'); + + const auto line_number = std::to_string( + 1 + std::count(reg.source->cbegin(), reg.first, '\n')); + + std::string retval; + retval += ' '; + retval += line_number; + retval += " | "; + retval += std::string(line_begin, line_end); + retval += '\n'; + retval += std::string(line_number.size() + 1, ' '); + retval += " | "; + retval += std::string(std::distance(line_begin, reg.first), ' '); + retval += std::string(std::distance(reg.first, reg.last), '~'); + retval += ' '; + retval += msg; + return retval; +} + +// to show a better error message. +template +std::string format_underline(const region& reg, + typename Container::const_iterator pos, + const std::string& msg) +{ + using const_iterator = typename region::const_iterator; + using reverse_iterator = std::reverse_iterator; + const auto line_begin = std::find( + reverse_iterator(reg.first), + reverse_iterator(reg.source->cbegin()), + '\n').base(); + const auto line_end = std::find(reg.last, reg.source->cend(), '\n'); + + const auto line_number = std::to_string( + 1 + std::count(reg.source->cbegin(), reg.first, '\n')); + + std::string retval; + retval += ' '; + retval += line_number; + retval += " | "; + retval += std::string(line_begin, line_end); + retval += '\n'; + retval += std::string(line_number.size() + 1, ' '); + retval += " | "; + retval += std::string(std::distance(line_begin, reg.first), ' '); + + if(std::distance(reg.first, std::prev(pos)) > 0) + { + retval += std::string(std::distance(reg.first, std::prev(pos)), '-'); + } + retval += '^'; + if(std::distance(pos, reg.last) > 0) + { + retval += std::string(std::distance(std::next(pos), reg.last), '-'); + } + + retval += ' '; + retval += msg; + return retval; +} + +} // detail +} // toml +#endif// TOML11_REGION_H