// Copyright {Jagger Software Limited} 2003 #if !defined CONTAINER_LINE_VIEW_INCLUDED || \ defined CONTAINER_LINE_VIEW_TEMPLATE_INCLUDED #error "container/line_view-template.hpp" #included directly #endif #define CONTAINER_LINE_VIEW_TEMPLATE_INCLUDED #include "array/end_of.hpp" #include #include namespace container // line_view - 'tor { template line_view::line_view(iterator begin, iterator end) : source(begin, end) { line_starts.push_back(0); while (begin != end) { static const char eol[] = "\r\n"; begin = std::find_first_of(begin, end, eol, array::end_of(eol)); if (begin != end && *begin++ == '\r' && begin != end && *begin == '\n') { ++begin; } line_starts.push_back(distance_to(begin)); } } } namespace container // limits { template iterator line_view::begin() const { return source.begin; } template iterator line_view::end() const { return source.end; } } namespace container // iterator --> line/row/col { template range_view line_view::to_line(iterator at) const { return (*this)[line_number(at)]; } template size_t line_view::line_number(iterator at) const { return iterator_to_line_number(at); } template size_t line_view::column_number(iterator at) const { const iterator line_start = line_number_to_line_start(line_number(at) - 1); return ::std::distance(line_start, at) + 1; } } namespace container // line# -> line { template size_t line_view::last_line_number() const { return line_starts.size() - 1; } template range_view line_view::operator[](size_t at) const { range_check(at); return make_range_view(line_number_to_line_start(at - 1), line_number_to_line_start(at)); } } namespace container // implementation { template size_t line_view::distance_to(iterator at) const { return ::std::distance(source.begin, at); } template size_t line_view::iterator_to_line_number(iterator position) const { const size_t offset = distance_to(position); for (size_t at = 1; at != line_starts.size(); ++at) { if (offset < line_starts[at]) { return at; } } throw ::std::out_of_range("container::line_view<>::iterator"); } template iterator line_view::line_number_to_line_start(size_t at) const { return begin() + line_starts[at]; } } namespace container // validation { template void line_view::range_check(size_t at) const { if (at < 1 || at > last_line_number()) // [1, last_line_number()] { throw ::std::out_of_range("container::line_view<>::line#"); } } } namespace container // convenience { template line_view make_line_view(iterator begin, iterator end) { return line_view(begin, end); } }