From 0d8cce272831cd896d0e69d7c86cc9afc521eb11 Mon Sep 17 00:00:00 2001 From: Maxime Coste Date: Wed, 22 Aug 2012 23:33:52 +0200 Subject: [PATCH] use a strongly typed int LineCount for line counts --- src/buffer.cc | 48 ++++++++++----------- src/buffer.hh | 28 ++++++++---- src/buffer_iterator.inl.hh | 9 ++-- src/commands.cc | 2 +- src/display_buffer.hh | 10 ++--- src/file.cc | 2 +- src/highlighters.cc | 6 +-- src/line_and_column.hh | 6 ++- src/main.cc | 16 +++---- src/ncurses.cc | 2 +- src/units.hh | 88 ++++++++++++++++++++++++++++++++++++++ src/window.cc | 10 ++--- 12 files changed, 161 insertions(+), 66 deletions(-) create mode 100644 src/units.hh diff --git a/src/buffer.cc b/src/buffer.cc index aeff8400..398f7460 100644 --- a/src/buffer.cc +++ b/src/buffer.cc @@ -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(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(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(); diff --git a/src/buffer.hh b/src/buffer.hh index 83bdcf22..971c731f 100644 --- a/src/buffer.hh +++ b/src/buffer.hh @@ -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(int line = 0, int column = 0) + BufferCoord(LineCount line = 0, int column = 0) : LineAndColumn(line, column) {} template @@ -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 m_lines; + struct LineList : std::vector + { + public: + Line& operator[](LineCount line) + { return std::vector::operator[]((int)line); } + + const Line& operator[](LineCount line) const + { return std::vector::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; diff --git a/src/buffer_iterator.inl.hh b/src/buffer_iterator.inl.hh index eb9d5bcb..b91734dc 100644 --- a/src/buffer_iterator.inl.hh +++ b/src/buffer_iterator.inl.hh @@ -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 }); diff --git a/src/commands.cc b/src/commands.cc index c17dd0a9..0b73b164 100644 --- a/src/commands.cc +++ b/src/commands.cc @@ -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(); } diff --git a/src/display_buffer.hh b/src/display_buffer.hh index f0a2bc1a..f48807c4 100644 --- a/src/display_buffer.hh +++ b/src/display_buffer.hh @@ -12,7 +12,7 @@ namespace Kakoune struct DisplayCoord : LineAndColumn { - DisplayCoord(int line = 0, int column = 0) + DisplayCoord(LineCount line = 0, int column = 0) : LineAndColumn(line, column) {} template @@ -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; diff --git a/src/file.cc b/src/file.cc index 33c543a3..ec6a4f67 100644 --- a/src/file.cc +++ b/src/file.cc @@ -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 diff --git a/src/highlighters.cc b/src/highlighters.cc index 3313eaa8..92de5c08 100644 --- a/src/highlighters.cc +++ b/src/highlighters.cc @@ -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; diff --git a/src/line_and_column.hh b/src/line_and_column.hh index bc19becf..3e03d1b9 100644 --- a/src/line_and_column.hh +++ b/src/line_and_column.hh @@ -1,16 +1,18 @@ #ifndef line_and_column_hh_INCLUDED #define line_and_column_hh_INCLUDED +#include "units.hh" + namespace Kakoune { template 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 diff --git a/src/main.cc b/src/main.cc index 34952491..dd24571c 100644 --- a/src/main.cc +++ b/src/main.cc @@ -344,15 +344,15 @@ Repeated repeated(T func) { return Repeated(func); } std::unordered_map> 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)); } }, diff --git a/src/ncurses.cc b/src/ncurses.cc index f85eb408..b18e048e 100644 --- a/src/ncurses.cc +++ b/src/ncurses.cc @@ -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; diff --git a/src/units.hh b/src/units.hh new file mode 100644 index 00000000..8a1180de --- /dev/null +++ b/src/units.hh @@ -0,0 +1,88 @@ +#ifndef units_hh_INCLUDED +#define units_hh_INCLUDED + +namespace Kakoune +{ + +template +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(*this); } + + RealType& operator-=(const RealType& other) + { m_value -= other.m_value; return static_cast(*this); } + + RealType& operator*=(const RealType& other) + { m_value *= other.m_value; return static_cast(*this); } + + RealType& operator/=(const RealType& other) + { m_value /= other.m_value; return static_cast(*this); } + + RealType& operator++() + { ++m_value; return static_cast(*this); } + + RealType& operator--() + { --m_value; return static_cast(*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 value) : StronglyTypedInteger(value) {} +}; + +inline LineCount operator"" _line(unsigned long long int value) +{ + return LineCount(value); +} + +} + +#endif // units_hh_INCLUDED + diff --git a/src/window.cc b/src/window.cc index c5ee5c1a..cc60d1f1 100644 --- a/src/window.cc +++ b/src/window.cc @@ -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]";