led_ctrl/include/toml11/impl/region_impl.hpp
2025-06-05 01:03:12 +00:00

251 lines
7.9 KiB
C++

#ifndef TOML11_REGION_IMPL_HPP
#define TOML11_REGION_IMPL_HPP
#include "../fwd/region_fwd.hpp"
#include "../utility.hpp"
#include "../version.hpp"
#include <algorithm>
#include <iterator>
#include <string>
#include <sstream>
#include <vector>
#include <cassert>
namespace toml
{
inline namespace TOML11_INLINE_VERSION_NAMESPACE
{
namespace detail
{
// a value defined in [first, last).
// Those source must be the same. Instread, `region` does not make sense.
TOML11_INLINE region::region(const location& first, const location& last)
: source_(first.source()), source_name_(first.source_name()),
length_(last.get_location() - first.get_location()),
first_(first.get_location()),
first_line_(first.line_number()),
first_column_(first.column_number()),
last_(last.get_location()),
last_line_(last.line_number()),
last_column_(last.column_number())
{
assert(first.source() == last.source());
assert(first.source_name() == last.source_name());
}
// shorthand of [loc, loc+1)
TOML11_INLINE region::region(const location& loc)
: source_(loc.source()), source_name_(loc.source_name()), length_(0),
first_line_(0), first_column_(0), last_line_(0), last_column_(0)
{
// if the file ends with LF, the resulting region points no char.
if(loc.eof())
{
if(loc.get_location() == 0)
{
this->length_ = 0;
this->first_ = 0;
this->first_line_ = 0;
this->first_column_ = 0;
this->last_ = 0;
this->last_line_ = 0;
this->last_column_ = 0;
}
else
{
const auto first = prev(loc);
this->first_ = first.get_location();
this->first_line_ = first.line_number();
this->first_column_ = first.column_number();
this->last_ = loc.get_location();
this->last_line_ = loc.line_number();
this->last_column_ = loc.column_number();
this->length_ = 1;
}
}
else
{
this->first_ = loc.get_location();
this->first_line_ = loc.line_number();
this->first_column_ = loc.column_number();
this->last_ = loc.get_location() + 1;
this->last_line_ = loc.line_number();
this->last_column_ = loc.column_number() + 1;
this->length_ = 1;
}
}
TOML11_INLINE region::char_type region::at(std::size_t i) const
{
if(this->last_ <= this->first_ + i)
{
throw std::out_of_range("range::at: index " + std::to_string(i) +
" exceeds length " + std::to_string(this->length_));
}
const auto iter = std::next(this->source_->cbegin(),
static_cast<difference_type>(this->first_ + i));
return *iter;
}
TOML11_INLINE region::const_iterator region::begin() const noexcept
{
return std::next(this->source_->cbegin(),
static_cast<difference_type>(this->first_));
}
TOML11_INLINE region::const_iterator region::end() const noexcept
{
return std::next(this->source_->cbegin(),
static_cast<difference_type>(this->last_));
}
TOML11_INLINE region::const_iterator region::cbegin() const noexcept
{
return std::next(this->source_->cbegin(),
static_cast<difference_type>(this->first_));
}
TOML11_INLINE region::const_iterator region::cend() const noexcept
{
return std::next(this->source_->cbegin(),
static_cast<difference_type>(this->last_));
}
TOML11_INLINE std::string region::as_string() const
{
if(this->is_ok())
{
const auto begin = std::next(this->source_->cbegin(), static_cast<difference_type>(this->first_));
const auto end = std::next(this->source_->cbegin(), static_cast<difference_type>(this->last_ ));
return ::toml::detail::make_string(begin, end);
}
else
{
return std::string("");
}
}
TOML11_INLINE std::pair<std::string, std::size_t>
region::take_line(const_iterator begin, const_iterator end) const
{
// To omit long line, we cap region by before/after 30 chars
const auto dist_before = std::distance(source_->cbegin(), begin);
const auto dist_after = std::distance(end, source_->cend());
const const_iterator capped_begin = (dist_before <= 30) ? source_->cbegin() : std::prev(begin, 30);
const const_iterator capped_end = (dist_after <= 30) ? source_->cend() : std::next(end, 30);
const auto lf = char_type('\n');
const auto lf_before = std::find(cxx::make_reverse_iterator(begin),
cxx::make_reverse_iterator(capped_begin), lf);
const auto lf_after = std::find(end, capped_end, lf);
auto offset = static_cast<std::size_t>(std::distance(lf_before.base(), begin));
std::string retval = make_string(lf_before.base(), lf_after);
if(lf_before.base() != source_->cbegin() && *lf_before != lf)
{
retval = "... " + retval;
offset += 4;
}
if(lf_after != source_->cend() && *lf_after != lf)
{
retval = retval + " ...";
}
return std::make_pair(retval, offset);
}
TOML11_INLINE std::vector<std::pair<std::string, std::size_t>> region::as_lines() const
{
assert(this->is_ok());
if(this->length_ == 0)
{
return std::vector<std::pair<std::string, std::size_t>>{
std::make_pair("", std::size_t(0))
};
}
// Consider the following toml file
// ```
// array = [
// 1, 2, 3,
// ] # comment
// ```
// and the region represnets
// ```
// [
// 1, 2, 3,
// ]
// ```
// but we want to show the following.
// ```
// array = [
// 1, 2, 3,
// ] # comment
// ```
// So we need to find LFs before `begin` and after `end`.
//
// But, if region ends with LF, it should not include the next line.
// ```
// a = 42
// ^^^- with the last LF
// ```
// So we start from `end-1` when looking for LF.
const auto begin_idx = static_cast<difference_type>(this->first_);
const auto end_idx = static_cast<difference_type>(this->last_) - 1;
// length_ != 0, so begin < end. then begin <= end-1
assert(begin_idx <= end_idx);
const auto begin = std::next(this->source_->cbegin(), begin_idx);
const auto end = std::next(this->source_->cbegin(), end_idx);
assert(this->first_line_number() <= this->last_line_number());
if(this->first_line_number() == this->last_line_number())
{
return std::vector<std::pair<std::string, std::size_t>>{
this->take_line(begin, end)
};
}
// we have multiple lines. `begin` and `end` points different lines.
// that means that there is at least one `LF` between `begin` and `end`.
const auto after_begin = std::distance(begin, this->source_->cend());
const auto before_end = std::distance(this->source_->cbegin(), end);
const_iterator capped_file_end = this->source_->cend();
const_iterator capped_file_begin = this->source_->cbegin();
if(60 < after_begin) {capped_file_end = std::next(begin, 50);}
if(60 < before_end) {capped_file_begin = std::prev(end, 50);}
const auto lf = char_type('\n');
const auto first_line_end = std::find(begin, capped_file_end, lf);
const auto last_line_begin = std::find(capped_file_begin, end, lf);
const auto first_line = this->take_line(begin, first_line_end);
const auto last_line = this->take_line(last_line_begin, end);
if(this->first_line_number() + 1 == this->last_line_number())
{
return std::vector<std::pair<std::string, std::size_t>>{
first_line, last_line
};
}
else
{
return std::vector<std::pair<std::string, std::size_t>>{
first_line, std::make_pair("...", 0), last_line
};
}
}
} // namespace detail
} // TOML11_INLINE_VERSION_NAMESPACE
} // namespace toml
#endif // TOML11_REGION_IMPL_HPP