Move LineRangeSet to line_modification.hh
This commit is contained in:
parent
7dbca46bf0
commit
72bdd7900f
|
@ -4,6 +4,7 @@
|
||||||
#include "face.hh"
|
#include "face.hh"
|
||||||
#include "hash.hh"
|
#include "hash.hh"
|
||||||
#include "coord.hh"
|
#include "coord.hh"
|
||||||
|
#include "range.hh"
|
||||||
#include "string.hh"
|
#include "string.hh"
|
||||||
#include "vector.hh"
|
#include "vector.hh"
|
||||||
#include "hash_map.hh"
|
#include "hash_map.hh"
|
||||||
|
@ -12,18 +13,7 @@ namespace Kakoune
|
||||||
{
|
{
|
||||||
|
|
||||||
class Buffer;
|
class Buffer;
|
||||||
struct BufferRange{ BufferCoord begin, end; };
|
using BufferRange = Range<BufferCoord>;
|
||||||
|
|
||||||
inline bool operator==(const BufferRange& lhs, const BufferRange& rhs)
|
|
||||||
{
|
|
||||||
return lhs.begin == rhs.begin and lhs.end == rhs.end;
|
|
||||||
}
|
|
||||||
|
|
||||||
inline
|
|
||||||
size_t hash_value(const BufferRange& range)
|
|
||||||
{
|
|
||||||
return hash_values(range.begin, range.end);
|
|
||||||
}
|
|
||||||
|
|
||||||
class BufferIterator;
|
class BufferIterator;
|
||||||
// Return a buffer iterator to the coord, tolerating one past end of line coords
|
// Return a buffer iterator to the coord, tolerating one past end of line coords
|
||||||
|
|
|
@ -1638,21 +1638,6 @@ struct RegexMatch
|
||||||
};
|
};
|
||||||
|
|
||||||
using RegexMatchList = Vector<RegexMatch, MemoryDomain::Regions>;
|
using RegexMatchList = Vector<RegexMatch, MemoryDomain::Regions>;
|
||||||
struct LineRange
|
|
||||||
{
|
|
||||||
LineCount begin;
|
|
||||||
LineCount end;
|
|
||||||
|
|
||||||
friend bool operator==(LineRange lhs, LineRange rhs)
|
|
||||||
{
|
|
||||||
return lhs.begin == rhs.begin and lhs.end == rhs.end;
|
|
||||||
}
|
|
||||||
friend bool operator!=(LineRange lhs, LineRange rhs)
|
|
||||||
{
|
|
||||||
return not (lhs == rhs);
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
void append_matches(const Buffer& buffer, LineCount line, RegexMatchList& matches, const Regex& regex, bool capture)
|
void append_matches(const Buffer& buffer, LineCount line, RegexMatchList& matches, const Regex& regex, bool capture)
|
||||||
{
|
{
|
||||||
auto l = buffer[line];
|
auto l = buffer[line];
|
||||||
|
@ -1772,123 +1757,6 @@ struct RegionMatches : UseMemoryDomain<MemoryDomain::Highlight>
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
struct LineRangeSet : private Vector<LineRange, MemoryDomain::Highlight>
|
|
||||||
{
|
|
||||||
using Base = Vector<LineRange, MemoryDomain::Highlight>;
|
|
||||||
using Base::operator[];
|
|
||||||
using Base::begin;
|
|
||||||
using Base::end;
|
|
||||||
|
|
||||||
ConstArrayView<LineRange> view() const { return {data(), data() + size()}; }
|
|
||||||
|
|
||||||
void reset(LineRange range) { Base::operator=({range}); }
|
|
||||||
|
|
||||||
void update(ConstArrayView<LineModification> modifs)
|
|
||||||
{
|
|
||||||
if (modifs.empty())
|
|
||||||
return;
|
|
||||||
|
|
||||||
for (auto it = begin(); it != end(); ++it)
|
|
||||||
{
|
|
||||||
auto modif_beg = std::lower_bound(modifs.begin(), modifs.end(), it->begin,
|
|
||||||
[](const LineModification& c, const LineCount& l)
|
|
||||||
{ return c.old_line + c.num_removed < l; });
|
|
||||||
auto modif_end = std::upper_bound(modifs.begin(), modifs.end(), it->end,
|
|
||||||
[](const LineCount& l, const LineModification& c)
|
|
||||||
{ return l < c.old_line; });
|
|
||||||
|
|
||||||
if (modif_beg == modifs.end())
|
|
||||||
{
|
|
||||||
const auto diff = (modif_beg-1)->diff();
|
|
||||||
it->begin += diff;
|
|
||||||
it->end += diff;
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
const auto diff = modif_beg->new_line - modif_beg->old_line;
|
|
||||||
it->begin += diff;
|
|
||||||
it->end += diff;
|
|
||||||
|
|
||||||
while (modif_beg != modif_end)
|
|
||||||
{
|
|
||||||
auto& m = *modif_beg++;
|
|
||||||
if (m.num_removed > 0)
|
|
||||||
{
|
|
||||||
if (m.new_line < it->begin)
|
|
||||||
it->begin = std::max(m.new_line, it->begin - m.num_removed);
|
|
||||||
it->end = std::max(m.new_line, std::max(it->begin, it->end - m.num_removed));
|
|
||||||
}
|
|
||||||
if (m.num_added > 0)
|
|
||||||
{
|
|
||||||
if (it->begin >= m.new_line)
|
|
||||||
it->begin += m.num_added;
|
|
||||||
else
|
|
||||||
{
|
|
||||||
it = insert(it, {it->begin, m.new_line}) + 1;
|
|
||||||
it->begin = m.new_line + m.num_added;
|
|
||||||
}
|
|
||||||
it->end += m.num_added;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
erase(std::remove_if(begin(), end(), [](auto& r) { return r.begin >= r.end; }), end());
|
|
||||||
}
|
|
||||||
|
|
||||||
template<typename Func>
|
|
||||||
void add_range(LineRange range, Func&& func)
|
|
||||||
{
|
|
||||||
auto it = std::lower_bound(begin(), end(), range.begin,
|
|
||||||
[](LineRange range, LineCount line) { return range.end < line; });
|
|
||||||
if (it == end() or it->begin > range.end)
|
|
||||||
func(range);
|
|
||||||
else
|
|
||||||
{
|
|
||||||
auto pos = range.begin;
|
|
||||||
while (it != end() and it->begin <= range.end)
|
|
||||||
{
|
|
||||||
if (pos < it->begin)
|
|
||||||
func({pos, it->begin});
|
|
||||||
|
|
||||||
range = LineRange{std::min(range.begin, it->begin), std::max(range.end, it->end)};
|
|
||||||
pos = it->end;
|
|
||||||
it = erase(it);
|
|
||||||
}
|
|
||||||
if (pos < range.end)
|
|
||||||
func({pos, range.end});
|
|
||||||
}
|
|
||||||
insert(it, range);
|
|
||||||
}
|
|
||||||
|
|
||||||
void remove_range(LineRange range)
|
|
||||||
{
|
|
||||||
auto inside = [](LineCount line, LineRange range) {
|
|
||||||
return range.begin <= line and line < range.end;
|
|
||||||
};
|
|
||||||
|
|
||||||
auto it = std::lower_bound(begin(), end(), range.begin,
|
|
||||||
[](LineRange range, LineCount line) { return range.end < line; });
|
|
||||||
if (it == end() or it->begin > range.end)
|
|
||||||
return;
|
|
||||||
else while (it != end() and it->begin <= range.end)
|
|
||||||
{
|
|
||||||
if (it->begin < range.begin and range.end <= it->end)
|
|
||||||
{
|
|
||||||
it = insert(it, {it->begin, range.begin}) + 1;
|
|
||||||
it->begin = range.end;
|
|
||||||
}
|
|
||||||
if (inside(it->begin, range))
|
|
||||||
it->begin = range.end;
|
|
||||||
if (inside(it->end, range))
|
|
||||||
it->end = range.begin;
|
|
||||||
|
|
||||||
if (it->end <= it->begin)
|
|
||||||
it = erase(it);
|
|
||||||
else
|
|
||||||
++it;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
struct RegionsHighlighter : public Highlighter
|
struct RegionsHighlighter : public Highlighter
|
||||||
{
|
{
|
||||||
public:
|
public:
|
||||||
|
@ -2387,68 +2255,4 @@ void register_highlighters()
|
||||||
"Define the default region of a regions highlighter" } });
|
"Define the default region of a regions highlighter" } });
|
||||||
}
|
}
|
||||||
|
|
||||||
UnitTest test_line_range_set{[]{
|
|
||||||
auto expect = [](ConstArrayView<LineRange> ranges) {
|
|
||||||
return [it = ranges.begin(), end = ranges.end()](LineRange r) mutable {
|
|
||||||
kak_assert(it != end);
|
|
||||||
kak_assert(r == *it++);
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
{
|
|
||||||
LineRangeSet ranges;
|
|
||||||
ranges.add_range({0, 5}, expect({{0, 5}}));
|
|
||||||
ranges.add_range({10, 15}, expect({{10, 15}}));
|
|
||||||
ranges.add_range({5, 10}, expect({{5, 10}}));
|
|
||||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 15}}));
|
|
||||||
ranges.add_range({5, 10}, expect({}));
|
|
||||||
ranges.remove_range({3, 8});
|
|
||||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 3}, {8, 15}}));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
LineRangeSet ranges;
|
|
||||||
ranges.add_range({0, 7}, expect({{0, 7}}));
|
|
||||||
ranges.add_range({9, 15}, expect({{9, 15}}));
|
|
||||||
ranges.add_range({5, 10}, expect({{7, 9}}));
|
|
||||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 15}}));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
LineRangeSet ranges;
|
|
||||||
ranges.add_range({0, 7}, expect({{0, 7}}));
|
|
||||||
ranges.add_range({11, 15}, expect({{11, 15}}));
|
|
||||||
ranges.add_range({5, 10}, expect({{7, 10}}));
|
|
||||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 10}, {11, 15}}));
|
|
||||||
ranges.remove_range({8, 13});
|
|
||||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 8}, {13, 15}}));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
LineRangeSet ranges;
|
|
||||||
ranges.add_range({0, 5}, expect({{0, 5}}));
|
|
||||||
ranges.add_range({10, 15}, expect({{10, 15}}));
|
|
||||||
ranges.update(ConstArrayView<LineModification>{{3, 3, 3, 1}, {11, 9, 2, 4}});
|
|
||||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 3}, {8, 9}, {13, 15}}));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
LineRangeSet ranges;
|
|
||||||
ranges.add_range({0, 5}, expect({{0, 5}}));
|
|
||||||
ranges.update(ConstArrayView<LineModification>{{2, 2, 2, 0}});
|
|
||||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 3}}));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
LineRangeSet ranges;
|
|
||||||
ranges.add_range({0, 5}, expect({{0, 5}}));
|
|
||||||
ranges.update(ConstArrayView<LineModification>{{2, 2, 0, 2}});
|
|
||||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 2}, {4, 7}}));
|
|
||||||
}
|
|
||||||
{
|
|
||||||
LineRangeSet ranges;
|
|
||||||
ranges.add_range({0, 1}, expect({{0, 1}}));
|
|
||||||
ranges.add_range({5, 10}, expect({{5, 10}}));
|
|
||||||
ranges.add_range({15, 20}, expect({{15, 20}}));
|
|
||||||
ranges.add_range({25, 30}, expect({{25, 30}}));
|
|
||||||
ranges.update(ConstArrayView<LineModification>{{2, 2, 3, 0}});
|
|
||||||
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 1}, {2, 7}, {12, 17}, {22, 27}}));
|
|
||||||
}
|
|
||||||
}};
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -94,6 +94,111 @@ bool operator==(const LineModification& lhs, const LineModification& rhs)
|
||||||
std::tie(rhs.old_line, rhs.new_line, rhs.num_removed, rhs.num_added);
|
std::tie(rhs.old_line, rhs.new_line, rhs.num_removed, rhs.num_added);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void LineRangeSet::update(ConstArrayView<LineModification> modifs)
|
||||||
|
{
|
||||||
|
if (modifs.empty())
|
||||||
|
return;
|
||||||
|
|
||||||
|
for (auto it = begin(); it != end(); ++it)
|
||||||
|
{
|
||||||
|
auto modif_beg = std::lower_bound(modifs.begin(), modifs.end(), it->begin,
|
||||||
|
[](const LineModification& c, const LineCount& l)
|
||||||
|
{ return c.old_line + c.num_removed < l; });
|
||||||
|
auto modif_end = std::upper_bound(modifs.begin(), modifs.end(), it->end,
|
||||||
|
[](const LineCount& l, const LineModification& c)
|
||||||
|
{ return l < c.old_line; });
|
||||||
|
|
||||||
|
if (modif_beg == modifs.end())
|
||||||
|
{
|
||||||
|
const auto diff = (modif_beg-1)->diff();
|
||||||
|
it->begin += diff;
|
||||||
|
it->end += diff;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
|
const auto diff = modif_beg->new_line - modif_beg->old_line;
|
||||||
|
it->begin += diff;
|
||||||
|
it->end += diff;
|
||||||
|
|
||||||
|
while (modif_beg != modif_end)
|
||||||
|
{
|
||||||
|
auto& m = *modif_beg++;
|
||||||
|
if (m.num_removed > 0)
|
||||||
|
{
|
||||||
|
if (m.new_line < it->begin)
|
||||||
|
it->begin = std::max(m.new_line, it->begin - m.num_removed);
|
||||||
|
it->end = std::max(m.new_line, std::max(it->begin, it->end - m.num_removed));
|
||||||
|
}
|
||||||
|
if (m.num_added > 0)
|
||||||
|
{
|
||||||
|
if (it->begin >= m.new_line)
|
||||||
|
it->begin += m.num_added;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
it = insert(it, {it->begin, m.new_line}) + 1;
|
||||||
|
it->begin = m.new_line + m.num_added;
|
||||||
|
}
|
||||||
|
it->end += m.num_added;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
erase(std::remove_if(begin(), end(), [](auto& r) { return r.begin >= r.end; }), end());
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineRangeSet::add_range(LineRange range, std::function<void (LineRange)> on_new_range)
|
||||||
|
{
|
||||||
|
auto it = std::lower_bound(begin(), end(), range.begin,
|
||||||
|
[](LineRange range, LineCount line) { return range.end < line; });
|
||||||
|
if (it == end() or it->begin > range.end)
|
||||||
|
on_new_range(range);
|
||||||
|
else
|
||||||
|
{
|
||||||
|
auto pos = range.begin;
|
||||||
|
while (it != end() and it->begin <= range.end)
|
||||||
|
{
|
||||||
|
if (pos < it->begin)
|
||||||
|
on_new_range({pos, it->begin});
|
||||||
|
|
||||||
|
range = LineRange{std::min(range.begin, it->begin), std::max(range.end, it->end)};
|
||||||
|
pos = it->end;
|
||||||
|
it = erase(it);
|
||||||
|
}
|
||||||
|
if (pos < range.end)
|
||||||
|
on_new_range({pos, range.end});
|
||||||
|
}
|
||||||
|
insert(it, range);
|
||||||
|
}
|
||||||
|
|
||||||
|
void LineRangeSet::remove_range(LineRange range)
|
||||||
|
{
|
||||||
|
auto inside = [](LineCount line, LineRange range) {
|
||||||
|
return range.begin <= line and line < range.end;
|
||||||
|
};
|
||||||
|
|
||||||
|
auto it = std::lower_bound(begin(), end(), range.begin,
|
||||||
|
[](LineRange range, LineCount line) { return range.end < line; });
|
||||||
|
if (it == end() or it->begin > range.end)
|
||||||
|
return;
|
||||||
|
else while (it != end() and it->begin <= range.end)
|
||||||
|
{
|
||||||
|
if (it->begin < range.begin and range.end <= it->end)
|
||||||
|
{
|
||||||
|
it = insert(it, {it->begin, range.begin}) + 1;
|
||||||
|
it->begin = range.end;
|
||||||
|
}
|
||||||
|
if (inside(it->begin, range))
|
||||||
|
it->begin = range.end;
|
||||||
|
if (inside(it->end, range))
|
||||||
|
it->end = range.begin;
|
||||||
|
|
||||||
|
if (it->end <= it->begin)
|
||||||
|
it = erase(it);
|
||||||
|
else
|
||||||
|
++it;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
UnitTest test_line_modifications{[]()
|
UnitTest test_line_modifications{[]()
|
||||||
{
|
{
|
||||||
{
|
{
|
||||||
|
@ -155,4 +260,68 @@ UnitTest test_line_modifications{[]()
|
||||||
}
|
}
|
||||||
}};
|
}};
|
||||||
|
|
||||||
|
UnitTest test_line_range_set{[]{
|
||||||
|
auto expect = [](ConstArrayView<LineRange> ranges) {
|
||||||
|
return [it = ranges.begin(), end = ranges.end()](LineRange r) mutable {
|
||||||
|
kak_assert(it != end);
|
||||||
|
kak_assert(r == *it++);
|
||||||
|
};
|
||||||
|
};
|
||||||
|
|
||||||
|
{
|
||||||
|
LineRangeSet ranges;
|
||||||
|
ranges.add_range({0, 5}, expect({{0, 5}}));
|
||||||
|
ranges.add_range({10, 15}, expect({{10, 15}}));
|
||||||
|
ranges.add_range({5, 10}, expect({{5, 10}}));
|
||||||
|
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 15}}));
|
||||||
|
ranges.add_range({5, 10}, expect({}));
|
||||||
|
ranges.remove_range({3, 8});
|
||||||
|
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 3}, {8, 15}}));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
LineRangeSet ranges;
|
||||||
|
ranges.add_range({0, 7}, expect({{0, 7}}));
|
||||||
|
ranges.add_range({9, 15}, expect({{9, 15}}));
|
||||||
|
ranges.add_range({5, 10}, expect({{7, 9}}));
|
||||||
|
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 15}}));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
LineRangeSet ranges;
|
||||||
|
ranges.add_range({0, 7}, expect({{0, 7}}));
|
||||||
|
ranges.add_range({11, 15}, expect({{11, 15}}));
|
||||||
|
ranges.add_range({5, 10}, expect({{7, 10}}));
|
||||||
|
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 10}, {11, 15}}));
|
||||||
|
ranges.remove_range({8, 13});
|
||||||
|
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 8}, {13, 15}}));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
LineRangeSet ranges;
|
||||||
|
ranges.add_range({0, 5}, expect({{0, 5}}));
|
||||||
|
ranges.add_range({10, 15}, expect({{10, 15}}));
|
||||||
|
ranges.update(ConstArrayView<LineModification>{{3, 3, 3, 1}, {11, 9, 2, 4}});
|
||||||
|
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 3}, {8, 9}, {13, 15}}));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
LineRangeSet ranges;
|
||||||
|
ranges.add_range({0, 5}, expect({{0, 5}}));
|
||||||
|
ranges.update(ConstArrayView<LineModification>{{2, 2, 2, 0}});
|
||||||
|
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 3}}));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
LineRangeSet ranges;
|
||||||
|
ranges.add_range({0, 5}, expect({{0, 5}}));
|
||||||
|
ranges.update(ConstArrayView<LineModification>{{2, 2, 0, 2}});
|
||||||
|
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 2}, {4, 7}}));
|
||||||
|
}
|
||||||
|
{
|
||||||
|
LineRangeSet ranges;
|
||||||
|
ranges.add_range({0, 1}, expect({{0, 1}}));
|
||||||
|
ranges.add_range({5, 10}, expect({{5, 10}}));
|
||||||
|
ranges.add_range({15, 20}, expect({{15, 20}}));
|
||||||
|
ranges.add_range({25, 30}, expect({{25, 30}}));
|
||||||
|
ranges.update(ConstArrayView<LineModification>{{2, 2, 3, 0}});
|
||||||
|
kak_assert((ranges.view() == ConstArrayView<LineRange>{{0, 1}, {2, 7}, {12, 17}, {22, 27}}));
|
||||||
|
}
|
||||||
|
}};
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,8 +1,10 @@
|
||||||
#ifndef line_change_watcher_hh_INCLUDED
|
#ifndef line_change_watcher_hh_INCLUDED
|
||||||
#define line_change_watcher_hh_INCLUDED
|
#define line_change_watcher_hh_INCLUDED
|
||||||
|
|
||||||
|
#include "array_view.hh"
|
||||||
#include "units.hh"
|
#include "units.hh"
|
||||||
#include "utils.hh"
|
#include "utils.hh"
|
||||||
|
#include "range.hh"
|
||||||
#include "vector.hh"
|
#include "vector.hh"
|
||||||
|
|
||||||
namespace Kakoune
|
namespace Kakoune
|
||||||
|
@ -22,6 +24,25 @@ struct LineModification
|
||||||
|
|
||||||
Vector<LineModification> compute_line_modifications(const Buffer& buffer, size_t timestamp);
|
Vector<LineModification> compute_line_modifications(const Buffer& buffer, size_t timestamp);
|
||||||
|
|
||||||
|
using LineRange = Range<LineCount>;
|
||||||
|
|
||||||
|
struct LineRangeSet : private Vector<LineRange, MemoryDomain::Highlight>
|
||||||
|
{
|
||||||
|
using Base = Vector<LineRange, MemoryDomain::Highlight>;
|
||||||
|
using Base::operator[];
|
||||||
|
using Base::begin;
|
||||||
|
using Base::end;
|
||||||
|
|
||||||
|
ConstArrayView<LineRange> view() const { return {data(), data() + size()}; }
|
||||||
|
|
||||||
|
void reset(LineRange range) { Base::operator=({range}); }
|
||||||
|
|
||||||
|
void update(ConstArrayView<LineModification> modifs);
|
||||||
|
void add_range(LineRange range, std::function<void (LineRange)> on_new_range);
|
||||||
|
void remove_range(LineRange range);
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif // line_change_watcher_hh_INCLUDED
|
#endif // line_change_watcher_hh_INCLUDED
|
||||||
|
|
31
src/range.hh
Normal file
31
src/range.hh
Normal file
|
@ -0,0 +1,31 @@
|
||||||
|
#ifndef range_hh_INCLUDED
|
||||||
|
#define range_hh_INCLUDED
|
||||||
|
|
||||||
|
namespace Kakoune
|
||||||
|
{
|
||||||
|
|
||||||
|
template<typename T>
|
||||||
|
struct Range
|
||||||
|
{
|
||||||
|
T begin;
|
||||||
|
T end;
|
||||||
|
|
||||||
|
friend bool operator==(const Range& lhs, const Range& rhs)
|
||||||
|
{
|
||||||
|
return lhs.begin == rhs.begin and lhs.end == rhs.end;
|
||||||
|
}
|
||||||
|
|
||||||
|
friend bool operator!=(const Range& lhs, const Range& rhs)
|
||||||
|
{
|
||||||
|
return not (lhs == rhs);
|
||||||
|
}
|
||||||
|
|
||||||
|
friend size_t hash_value(const Range& range)
|
||||||
|
{
|
||||||
|
return hash_values(range.begin, range.end);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif // range_hh_INCLUDED
|
Loading…
Reference in New Issue
Block a user