use a strongly typed int LineCount for line counts

This commit is contained in:
Maxime Coste 2012-08-22 23:33:52 +02:00
parent c6e8080426
commit 0d8cce2728
12 changed files with 161 additions and 66 deletions

View File

@ -66,15 +66,10 @@ BufferCoord Buffer::line_and_column_at(const BufferIterator& iterator) const
return iterator.m_coord;
}
BufferPos Buffer::line_at(const BufferIterator& iterator) const
{
return iterator.line();
}
BufferSize Buffer::line_length(BufferPos line) const
BufferSize Buffer::line_length(LineCount line) const
{
assert(line < line_count());
BufferPos end = (line < m_lines.size() - 1) ?
BufferPos end = (line < line_count() - 1) ?
m_lines[line + 1].start : character_count();
return end - m_lines[line].start;
}
@ -86,7 +81,7 @@ BufferCoord Buffer::clamp(const BufferCoord& line_and_column,
return BufferCoord();
BufferCoord result(line_and_column.line, line_and_column.column);
result.line = Kakoune::clamp<int>(0, m_lines.size() - 1, result.line);
result.line = Kakoune::clamp(0_line, line_count() - 1, result.line);
int max_col = std::max(0, line_length(result.line) - (avoid_eol ? 2 : 1));
result.column = Kakoune::clamp<int>(0, max_col, result.column);
return result;
@ -97,35 +92,35 @@ BufferIterator Buffer::iterator_at_line_begin(const BufferIterator& iterator) co
return BufferIterator(*this, { iterator.line(), 0 });
}
BufferIterator Buffer::iterator_at_line_begin(size_t line) const
BufferIterator Buffer::iterator_at_line_begin(LineCount line) const
{
return BufferIterator(*this, clamp({ (int)line, 0 }));
return BufferIterator(*this, clamp({ line, 0 }));
}
BufferIterator Buffer::iterator_at_line_end(const BufferIterator& iterator) const
{
BufferPos line = iterator.line();
LineCount line = iterator.line();
assert(line_length(line) > 0);
return ++BufferIterator(*this, { line, line_length(line) - 1 });
}
BufferIterator Buffer::iterator_at_line_end(size_t line) const
BufferIterator Buffer::iterator_at_line_end(LineCount line) const
{
line = std::min(line, (size_t)line_count()-1);
line = std::min(line, line_count()-1);
assert(line_length(line) > 0);
return ++BufferIterator(*this, { (int)line, line_length(line) - 1 });
return ++BufferIterator(*this, { line, line_length(line) - 1 });
}
BufferIterator Buffer::begin() const
{
return BufferIterator(*this, { 0, 0 });
return BufferIterator(*this, { 0_line, 0 });
}
BufferIterator Buffer::end() const
{
if (m_lines.empty())
return BufferIterator(*this, { 0, 0 });
return BufferIterator(*this, { (int)line_count()-1, (int)m_lines.back().length() });
return BufferIterator(*this, { 0_line, 0 });
return BufferIterator(*this, { line_count()-1, (int)m_lines.back().length() });
}
BufferSize Buffer::character_count() const
@ -135,15 +130,15 @@ BufferSize Buffer::character_count() const
return m_lines.back().start + m_lines.back().length();
}
BufferSize Buffer::line_count() const
LineCount Buffer::line_count() const
{
return m_lines.size();
return LineCount(m_lines.size());
}
String Buffer::string(const BufferIterator& begin, const BufferIterator& end) const
{
String res;
for (BufferPos line = begin.line(); line <= end.line(); ++line)
for (LineCount line = begin.line(); line <= end.line(); ++line)
{
size_t start = 0;
if (line == begin.line())
@ -253,7 +248,7 @@ void Buffer::do_insert(const BufferIterator& pos, const String& content)
BufferSize offset = pos.offset();
// all following lines advanced by length
for (size_t i = pos.line()+1; i < line_count(); ++i)
for (LineCount i = pos.line()+1; i < line_count(); ++i)
m_lines[i].start += content.length();
BufferIterator begin_it;
@ -282,7 +277,7 @@ void Buffer::do_insert(const BufferIterator& pos, const String& content)
String prefix = m_lines[pos.line()].content.substr(0, pos.column());
String suffix = m_lines[pos.line()].content.substr(pos.column());
auto line_it = m_lines.begin() + pos.line();
auto line_it = m_lines.begin() + (int)pos.line();
line_it = m_lines.erase(line_it);
int start = 0;
@ -313,7 +308,8 @@ void Buffer::do_insert(const BufferIterator& pos, const String& content)
--line_it;
begin_it = pos;
end_it = BufferIterator(*this, { int(line_it - m_lines.begin()), int(line_it->length() - suffix.length()) });
end_it = BufferIterator(*this, { LineCount(line_it - m_lines.begin()),
int(line_it->length() - suffix.length()) });
}
check_invariant();
@ -331,11 +327,11 @@ void Buffer::do_erase(const BufferIterator& pos, BufferSize length)
String suffix = m_lines[end.line()].content.substr(end.column());
Line new_line = { m_lines[pos.line()].start, prefix + suffix };
m_lines.erase(m_lines.begin() + pos.line(), m_lines.begin() + end.line() + 1);
m_lines.erase(m_lines.begin() + (int)pos.line(), m_lines.begin() + (int)end.line() + 1);
if (new_line.length())
m_lines.insert(m_lines.begin() + pos.line(), std::move(new_line));
m_lines.insert(m_lines.begin() + (int)pos.line(), std::move(new_line));
for (size_t i = pos.line()+1; i < line_count(); ++i)
for (LineCount i = pos.line()+1; i < line_count(); ++i)
m_lines[i].start -= length;
check_invariant();

View File

@ -9,6 +9,7 @@
#include "option_manager.hh"
#include "hook_manager.hh"
#include "string.hh"
#include "units.hh"
namespace Kakoune
{
@ -21,7 +22,7 @@ typedef int BufferSize;
struct BufferCoord : LineAndColumn<BufferCoord>
{
BufferCoord(int line = 0, int column = 0)
BufferCoord(LineCount line = 0, int column = 0)
: LineAndColumn(line, column) {}
template<typename T>
@ -72,7 +73,7 @@ public:
const Buffer& buffer() const;
const BufferCoord& coord() const { return m_coord; }
BufferSize line() const { return m_coord.line; }
LineCount line() const { return m_coord.line; }
BufferSize column() const { return m_coord.column; }
private:
@ -130,7 +131,7 @@ public:
BufferIterator begin() const;
BufferIterator end() const;
BufferSize character_count() const;
BufferSize line_count() const;
LineCount line_count() const;
// returns an iterator at given coordinates. line_and_column is
// clamped according to avoid_eol.
@ -162,16 +163,17 @@ public:
// iterator is on
BufferIterator iterator_at_line_begin(const BufferIterator& iterator) const;
// the same but taking a line number instead of an iterator
BufferIterator iterator_at_line_begin(size_t line) const;
BufferIterator iterator_at_line_begin(LineCount line) const;
// returns an iterator pointing to the character after the last of the
// line iterator is on (which is the first of the next line if iterator is
// not on the last one)
BufferIterator iterator_at_line_end(const BufferIterator& iterator) const;
// the same but taking a line number instead of an iterator
BufferIterator iterator_at_line_end(size_t line) const;
BufferIterator iterator_at_line_end(LineCount line) const;
const String& line_content(size_t l) const { return m_lines[l].content; }
const String& line_content(LineCount line) const
{ return m_lines[line].content; }
OptionManager& option_manager() { return m_option_manager; }
const OptionManager& option_manager() const { return m_option_manager; }
@ -190,13 +192,21 @@ private:
size_t length() const { return content.length(); }
};
std::vector<Line> m_lines;
struct LineList : std::vector<Line>
{
public:
Line& operator[](LineCount line)
{ return std::vector<Line>::operator[]((int)line); }
const Line& operator[](LineCount line) const
{ return std::vector<Line>::operator[]((int)line); }
};
LineList m_lines;
void do_insert(const BufferIterator& pos, const String& content);
void do_erase(const BufferIterator& pos, BufferSize length);
BufferPos line_at(const BufferIterator& iterator) const;
BufferSize line_length(BufferPos line) const;
BufferSize line_length(LineCount line) const;
String m_name;
const Type m_type;

View File

@ -117,7 +117,8 @@ inline Character BufferIterator::operator*() const
inline BufferSize BufferIterator::offset() const
{
assert(m_buffer);
return line() == 0 ? column() : m_buffer->m_lines[line()].start + column();
return line() == 0 ? column()
: m_buffer->m_lines[line()].start + column();
}
inline BufferSize BufferIterator::operator-(const BufferIterator& iterator) const
@ -132,12 +133,12 @@ inline BufferIterator BufferIterator::operator+(BufferSize size) const
if (size >= 0)
{
BufferSize o = std::min(m_buffer->character_count(), offset() + size);
for (int i = line() + 1; i < m_buffer->line_count(); ++i)
for (LineCount i = line() + 1; i < m_buffer->line_count(); ++i)
{
if (m_buffer->m_lines[i].start > o)
return BufferIterator(*m_buffer, { i-1, o - m_buffer->m_lines[i-1].start });
}
int last_line = std::max(0, m_buffer->line_count() - 1);
LineCount last_line = std::max(0_line, m_buffer->line_count() - 1);
return BufferIterator(*m_buffer, { last_line, o - m_buffer->m_lines[last_line].start });
}
return operator-(-size);
@ -149,7 +150,7 @@ inline BufferIterator BufferIterator::operator-(BufferSize size) const
if (size >= 0)
{
BufferSize o = std::max(0, offset() - size);
for (int i = line(); i >= 0; --i)
for (LineCount i = line(); i >= 0; --i)
{
if (m_buffer->m_lines[i].start <= o)
return BufferIterator(*m_buffer, { i, o - m_buffer->m_lines[i].start });

View File

@ -259,7 +259,7 @@ void edit(const CommandParameters& params, Context& context)
int column = param_count > 2 ?
std::max(0, str_to_int(parser[2]) - 1) : 0;
window.select(window.buffer().iterator_at({line, column}));
window.select(window.buffer().iterator_at({LineCount(line), column}));
window.center_selection();
}

View File

@ -12,7 +12,7 @@ namespace Kakoune
struct DisplayCoord : LineAndColumn<DisplayCoord>
{
DisplayCoord(int line = 0, int column = 0)
DisplayCoord(LineCount line = 0, int column = 0)
: LineAndColumn(line, column) {}
template<typename T>
@ -123,9 +123,9 @@ public:
using iterator = AtomList::iterator;
using const_iterator = AtomList::const_iterator;
explicit DisplayLine(size_t buffer_line) : m_buffer_line(buffer_line) {}
explicit DisplayLine(LineCount buffer_line) : m_buffer_line(buffer_line) {}
size_t buffer_line() const { return m_buffer_line; }
LineCount buffer_line() const { return m_buffer_line; }
iterator begin() { return m_atoms.begin(); }
iterator end() { return m_atoms.end(); }
@ -140,8 +140,8 @@ public:
void push_back(DisplayAtom atom) { m_atoms.push_back(std::move(atom)); }
private:
size_t m_buffer_line;
AtomList m_atoms;
LineCount m_buffer_line;
AtomList m_atoms;
};
using BufferRange = std::pair<BufferIterator, BufferIterator>;

View File

@ -173,7 +173,7 @@ void write_buffer_to_file(const Buffer& buffer, const String& filename)
if (buffer.option_manager()["BOM"].as_string() == "utf-8")
::write(fd, "\xEF\xBB\xBF", 3);
for (size_t i = 0; i < buffer.line_count(); ++i)
for (LineCount i = 0; i < buffer.line_count(); ++i)
{
// end of lines are written according to eolformat but always
// stored as \n

View File

@ -213,9 +213,9 @@ void expand_tabulations(Window& window, DisplayBuffer& display_buffer)
void show_line_numbers(Window& window, DisplayBuffer& display_buffer)
{
int last_line = window.buffer().line_count();
LineCount last_line = window.buffer().line_count();
int digit_count = 0;
for (int c = last_line; c > 0; c /= 10)
for (LineCount c = last_line; c > 0; c /= 10)
++digit_count;
char format[] = "%?d ";
@ -224,7 +224,7 @@ void show_line_numbers(Window& window, DisplayBuffer& display_buffer)
for (auto& line : display_buffer.lines())
{
char buffer[10];
snprintf(buffer, 10, format, line.buffer_line() + 1);
snprintf(buffer, 10, format, (int)line.buffer_line() + 1);
DisplayAtom atom = DisplayAtom(AtomContent(buffer));
atom.fg_color = Color::Black;
atom.bg_color = Color::White;

View File

@ -1,16 +1,18 @@
#ifndef line_and_column_hh_INCLUDED
#define line_and_column_hh_INCLUDED
#include "units.hh"
namespace Kakoune
{
template<typename EffectiveType>
struct LineAndColumn
{
int line;
LineCount line;
int column;
LineAndColumn(int line = 0, int column = 0)
LineAndColumn(LineCount line = 0, int column = 0)
: line(line), column(column) {}
EffectiveType operator+(const EffectiveType& other) const

View File

@ -344,15 +344,15 @@ Repeated<T> repeated(T func) { return Repeated<T>(func); }
std::unordered_map<Key, std::function<void (Context& context)>> keymap =
{
{ { Key::Modifiers::None, 'h' }, [](Context& context) { context.editor().move_selections(BufferCoord(0, -std::max(context.numeric_param(),1))); } },
{ { Key::Modifiers::None, 'j' }, [](Context& context) { context.editor().move_selections(BufferCoord( std::max(context.numeric_param(),1), 0)); } },
{ { Key::Modifiers::None, 'k' }, [](Context& context) { context.editor().move_selections(BufferCoord(-std::max(context.numeric_param(),1), 0)); } },
{ { Key::Modifiers::None, 'l' }, [](Context& context) { context.editor().move_selections(BufferCoord(0, std::max(context.numeric_param(),1))); } },
{ { Key::Modifiers::None, 'h' }, [](Context& context) { context.editor().move_selections({ 0, -std::max(context.numeric_param(),1) }); } },
{ { Key::Modifiers::None, 'j' }, [](Context& context) { context.editor().move_selections({ std::max(context.numeric_param(),1), 0 }); } },
{ { Key::Modifiers::None, 'k' }, [](Context& context) { context.editor().move_selections({ -std::max(context.numeric_param(),1), 0 }); } },
{ { Key::Modifiers::None, 'l' }, [](Context& context) { context.editor().move_selections({ 0, std::max(context.numeric_param(),1) }); } },
{ { Key::Modifiers::None, 'H' }, [](Context& context) { context.editor().move_selections(BufferCoord(0, -std::max(context.numeric_param(),1)), true); } },
{ { Key::Modifiers::None, 'J' }, [](Context& context) { context.editor().move_selections(BufferCoord( std::max(context.numeric_param(),1), 0), true); } },
{ { Key::Modifiers::None, 'K' }, [](Context& context) { context.editor().move_selections(BufferCoord(-std::max(context.numeric_param(),1), 0), true); } },
{ { Key::Modifiers::None, 'L' }, [](Context& context) { context.editor().move_selections(BufferCoord(0, std::max(context.numeric_param(),1)), true); } },
{ { Key::Modifiers::None, 'H' }, [](Context& context) { context.editor().move_selections({ 0, -std::max(context.numeric_param(),1) }, true); } },
{ { Key::Modifiers::None, 'J' }, [](Context& context) { context.editor().move_selections({ std::max(context.numeric_param(),1), 0 }, true); } },
{ { Key::Modifiers::None, 'K' }, [](Context& context) { context.editor().move_selections({ -std::max(context.numeric_param(),1), 0 }, true); } },
{ { Key::Modifiers::None, 'L' }, [](Context& context) { context.editor().move_selections({ 0, std::max(context.numeric_param(),1) }, true); } },
{ { Key::Modifiers::None, 't' }, [](Context& context) { context.editor().select(std::bind(select_to, _1, context.client().get_key().key, context.numeric_param(), false)); } },
{ { Key::Modifiers::None, 'f' }, [](Context& context) { context.editor().select(std::bind(select_to, _1, context.client().get_key().key, context.numeric_param(), true)); } },

View File

@ -93,7 +93,7 @@ void NCursesClient::draw_window(Window& window)
getmaxyx(stdscr, max_y, max_x);
max_y -= 1;
window.set_dimensions(DisplayCoord(max_y, max_x));
window.set_dimensions(DisplayCoord(LineCount(max_y), max_x));
window.update_display_buffer();
int line_index = 0;

88
src/units.hh Normal file
View File

@ -0,0 +1,88 @@
#ifndef units_hh_INCLUDED
#define units_hh_INCLUDED
namespace Kakoune
{
template<typename RealType, typename ValueType = int>
class StronglyTypedInteger
{
public:
explicit StronglyTypedInteger(ValueType value)
: m_value(value) {}
RealType operator+(const RealType& other) const
{ return RealType(m_value + other.m_value); }
RealType operator-(const RealType& other) const
{ return RealType(m_value - other.m_value); }
RealType operator*(const RealType& other) const
{ return RealType(m_value * other.m_value); }
RealType operator/(const RealType& other) const
{ return RealType(m_value / other.m_value); }
RealType& operator+=(const RealType& other)
{ m_value += other.m_value; return static_cast<RealType&>(*this); }
RealType& operator-=(const RealType& other)
{ m_value -= other.m_value; return static_cast<RealType&>(*this); }
RealType& operator*=(const RealType& other)
{ m_value *= other.m_value; return static_cast<RealType&>(*this); }
RealType& operator/=(const RealType& other)
{ m_value /= other.m_value; return static_cast<RealType&>(*this); }
RealType& operator++()
{ ++m_value; return static_cast<RealType&>(*this); }
RealType& operator--()
{ --m_value; return static_cast<RealType&>(*this); }
RealType operator++(int)
{ RealType backup(*this); ++m_value; return backup; }
RealType operator--(int)
{ RealType backup(*this); --m_value; return backup; }
RealType operator-() { return RealType(-m_value); }
bool operator==(const RealType& other) const
{ return m_value == other.m_value; }
bool operator!=(const RealType& other) const
{ return m_value != other.m_value; }
bool operator<(const RealType& other) const
{ return m_value < other.m_value; }
bool operator<=(const RealType& other) const
{ return m_value <= other.m_value; }
bool operator>(const RealType& other) const
{ return m_value > other.m_value; }
bool operator>=(const RealType& other) const
{ return m_value >= other.m_value; }
explicit operator ValueType() const { return m_value; }
private:
ValueType m_value;
};
struct LineCount : public StronglyTypedInteger<LineCount, int>
{
LineCount(int value) : StronglyTypedInteger<LineCount>(value) {}
};
inline LineCount operator"" _line(unsigned long long int value)
{
return LineCount(value);
}
}
#endif // units_hh_INCLUDED

View File

@ -13,8 +13,6 @@ namespace Kakoune
Window::Window(Buffer& buffer)
: Editor(buffer),
m_position(0, 0),
m_dimensions(0, 0),
m_hook_manager(buffer.hook_manager()),
m_option_manager(buffer.option_manager())
{
@ -38,7 +36,7 @@ Window::~Window()
void Window::center_selection()
{
BufferIterator cursor = selections().back().last();
m_position.line = std::max(0, cursor.line() - m_dimensions.line/2);
m_position.line = std::max(0_line, cursor.line() - m_dimensions.line/2_line);
}
void Window::update_display_buffer()
@ -48,9 +46,9 @@ void Window::update_display_buffer()
DisplayBuffer::LineList& lines = m_display_buffer.lines();
lines.clear();
for (auto line = 0; line < m_dimensions.line; ++line)
for (LineCount line = 0; line < m_dimensions.line; ++line)
{
auto buffer_line = m_position.line + line;
LineCount buffer_line = m_position.line + line;
if (buffer_line >= buffer().line_count())
break;
BufferIterator pos = buffer().iterator_at({ buffer_line, m_position.column });
@ -138,7 +136,7 @@ String Window::status_line() const
oss << buffer().name();
if (buffer().is_modified())
oss << " [+]";
oss << " -- " << cursor.line+1 << "," << cursor.column+1
oss << " -- " << (int)cursor.line+1 << "," << cursor.column+1
<< " -- " << selections().size() << " sel -- ";
if (is_editing())
oss << "[Insert]";