summaryrefslogtreecommitdiffstats
path: root/src/libixion/address.cpp
diff options
context:
space:
mode:
Diffstat (limited to '')
-rw-r--r--src/libixion/address.cpp568
1 files changed, 568 insertions, 0 deletions
diff --git a/src/libixion/address.cpp b/src/libixion/address.cpp
new file mode 100644
index 0000000..2b9b82c
--- /dev/null
+++ b/src/libixion/address.cpp
@@ -0,0 +1,568 @@
+/* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
+/*
+ * This Source Code Form is subject to the terms of the Mozilla Public
+ * License, v. 2.0. If a copy of the MPL was not distributed with this
+ * file, You can obtain one at http://mozilla.org/MPL/2.0/.
+ */
+
+#include "ixion/address.hpp"
+
+#include <sstream>
+#include <limits>
+
+namespace ixion {
+
+static const row_t row_max = std::numeric_limits<row_t>::max();
+static const col_t column_max = std::numeric_limits<col_t>::max();
+
+const row_t row_unset = row_max - 9;
+const row_t row_upper_bound = row_max - 10;
+
+const col_t column_unset = column_max - 9;
+const col_t column_upper_bound = column_max / 26 - 26;
+
+abs_address_t::abs_address_t() : sheet(0), row(0), column(0) {}
+abs_address_t::abs_address_t(init_invalid) : sheet(-1), row(-1), column(-1) {}
+
+abs_address_t::abs_address_t(sheet_t _sheet, row_t _row, col_t _column) :
+ sheet(_sheet), row(_row), column(_column) {}
+
+abs_address_t::abs_address_t(const abs_address_t& r) :
+ sheet(r.sheet), row(r.row), column(r.column) {}
+
+bool abs_address_t::valid() const
+{
+ return sheet >= 0 && row >= 0 && column >= 0 && row <= row_unset && column <= column_unset;
+}
+
+std::string abs_address_t::get_name() const
+{
+ std::ostringstream os;
+ os << "(sheet=" << sheet << "; row=" << row << "; column=" << column << ")";
+ return os.str();
+}
+
+std::size_t abs_address_t::hash::operator()(const abs_address_t& addr) const
+{
+ return addr.sheet + addr.row + addr.column;
+}
+
+bool operator== (const abs_address_t& left, const abs_address_t& right)
+{
+ return left.sheet == right.sheet &&
+ left.row == right.row &&
+ left.column == right.column;
+}
+
+bool operator!= (const abs_address_t& left, const abs_address_t& right)
+{
+ return !operator==(left, right);
+}
+
+bool operator< (const abs_address_t& left, const abs_address_t& right)
+{
+ if (left.sheet != right.sheet)
+ return left.sheet < right.sheet;
+
+ if (left.row != right.row)
+ return left.row < right.row;
+
+ return left.column < right.column;
+}
+
+address_t::address_t() :
+ sheet(0), row(0), column(0), abs_sheet(true), abs_row(true), abs_column(true) {}
+
+address_t::address_t(sheet_t _sheet, row_t _row, col_t _column, bool _abs_sheet, bool _abs_row, bool _abs_column) :
+ sheet(_sheet), row(_row), column(_column),
+ abs_sheet(_abs_sheet), abs_row(_abs_row), abs_column(_abs_column) {}
+
+address_t::address_t(const address_t& r) :
+ sheet(r.sheet), row(r.row), column(r.column),
+ abs_sheet(r.abs_sheet), abs_row(r.abs_row), abs_column(r.abs_column) {}
+
+address_t::address_t(const abs_address_t& r) :
+ sheet(r.sheet), row(r.row), column(r.column),
+ abs_sheet(true), abs_row(true), abs_column(true) {}
+
+bool address_t::valid() const
+{
+ if (abs_sheet)
+ {
+ if (sheet < 0)
+ return false;
+ }
+
+ if (row > row_unset)
+ return false;
+
+ if (abs_row)
+ {
+ if (row < 0)
+ return false;
+ }
+ else
+ {
+ if (row < -row_upper_bound)
+ return false;
+ }
+
+ if (column > column_unset)
+ return false;
+
+ if (abs_column)
+ {
+ if (column < 0)
+ return false;
+ }
+ else
+ {
+ if (column < -column_upper_bound)
+ return false;
+ }
+
+ return true;
+}
+
+abs_address_t address_t::to_abs(const abs_address_t& origin) const
+{
+ abs_address_t abs_addr;
+ abs_addr.sheet = sheet;
+ abs_addr.row = row;
+ abs_addr.column = column;
+
+ if (!is_valid_sheet(origin.sheet))
+ // If the origin sheet is invalid, then any sheet position relative to that should be invalid.
+ abs_addr.sheet = origin.sheet;
+ else if (!abs_sheet)
+ abs_addr.sheet += origin.sheet;
+
+ if (!abs_row && row <= row_upper_bound)
+ abs_addr.row += origin.row;
+
+ if (!abs_column && column <= column_upper_bound)
+ abs_addr.column += origin.column;
+
+ return abs_addr;
+}
+
+std::string address_t::get_name() const
+{
+ std::ostringstream os;
+ os << "(row=" << row << " [";
+ if (abs_row)
+ os << "abs";
+ else
+ os << "rel";
+ os << "]; column=" << column << " [";
+ if (abs_column)
+ os << "abs";
+ else
+ os << "rel";
+ os << "])";
+ return os.str();
+}
+
+void address_t::set_absolute(bool abs)
+{
+ abs_sheet = abs;
+ abs_row = abs;
+ abs_column = abs;
+}
+
+std::size_t address_t::hash::operator()(const address_t& addr) const
+{
+ return 0;
+}
+
+bool operator== (const address_t& left, const address_t& right)
+{
+ return left.sheet == right.sheet &&
+ left.row == right.row &&
+ left.column == right.column &&
+ left.abs_sheet == right.abs_sheet &&
+ left.abs_row == right.abs_row &&
+ left.abs_column == right.abs_column;
+}
+
+bool operator!=(const address_t& left, const address_t& right)
+{
+ return !operator==(left, right);
+}
+
+bool operator< (const address_t& left, const address_t& right)
+{
+ // Not sure how to compare absolute and relative addresses, but let's make
+ // absolute address always greater than relative one until we find a
+ // better way.
+
+ if (left.abs_sheet != right.abs_sheet)
+ return left.abs_sheet < right.abs_sheet;
+
+ if (left.abs_row != right.abs_row)
+ return left.abs_row < right.abs_row;
+
+ if (left.abs_column != right.abs_column)
+ return left.abs_column < right.abs_column;
+
+ if (left.sheet != right.sheet)
+ return left.sheet < right.sheet;
+
+ if (left.row != right.row)
+ return left.row < right.row;
+
+ return left.column < right.column;
+}
+
+abs_rc_address_t::abs_rc_address_t() : row(0), column(0)
+{
+}
+
+abs_rc_address_t::abs_rc_address_t(init_invalid) :
+ row(-1), column(-1) {}
+
+abs_rc_address_t::abs_rc_address_t(row_t _row, col_t _column) :
+ row(_row), column(_column) {}
+
+abs_rc_address_t::abs_rc_address_t(const abs_rc_address_t& r) :
+ row(r.row), column(r.column) {}
+
+abs_rc_address_t::abs_rc_address_t(const abs_address_t& r) :
+ row(r.row), column(r.column) {}
+
+bool abs_rc_address_t::valid() const
+{
+ return row >= 0 && column >= 0 && row <= row_unset && column <= column_unset;
+}
+
+std::size_t abs_rc_address_t::hash::operator() (const abs_rc_address_t& addr) const
+{
+ size_t hv = addr.column;
+ hv <<= 16;
+ hv += addr.row;
+ return hv;
+}
+
+bool operator== (const abs_rc_address_t& left, const abs_rc_address_t& right)
+{
+ return left.row == right.row && left.column == right.column;
+}
+
+bool operator!= (const abs_rc_address_t& left, const abs_rc_address_t& right)
+{
+ return !operator==(left, right);
+}
+
+bool operator< (const abs_rc_address_t& left, const abs_rc_address_t& right)
+{
+ if (left.row != right.row)
+ return left.row < right.row;
+
+ return left.column < right.column;
+}
+
+rc_address_t::rc_address_t() :
+ row(0), column(0), abs_row(true), abs_column(true) {}
+
+rc_address_t::rc_address_t(row_t _row, col_t _column, bool _abs_row, bool _abs_column) :
+ row(_row), column(_column), abs_row(_abs_row), abs_column(_abs_column) {}
+
+rc_address_t::rc_address_t(const rc_address_t& r) :
+ row(r.row), column(r.column), abs_row(r.abs_row), abs_column(r.abs_column) {}
+
+std::size_t rc_address_t::hash::operator()(const rc_address_t& addr) const
+{
+ std::size_t hv = addr.column;
+ hv <<= 16;
+ hv += addr.row;
+ return hv;
+}
+
+abs_range_t::abs_range_t() {}
+abs_range_t::abs_range_t(init_invalid) :
+ first(abs_address_t::invalid), last(abs_address_t::invalid) {}
+
+abs_range_t::abs_range_t(sheet_t _sheet, row_t _row, col_t _col) :
+ first(_sheet, _row, _col), last(_sheet, _row, _col) {}
+
+abs_range_t::abs_range_t(sheet_t _sheet, row_t _row, col_t _col, row_t _row_span, col_t _col_span) :
+ first(_sheet, _row, _col), last(_sheet, _row + _row_span - 1, _col + _col_span - 1)
+{
+ if (_row_span < 1 || _col_span < 1)
+ {
+ std::ostringstream os;
+ os << "abs_range_t: invalid span (row=" << _row_span << "; col=" << _col_span << ")";
+ throw std::range_error(os.str());
+ }
+}
+
+abs_range_t::abs_range_t(const abs_address_t& addr, row_t row_span, col_t col_span) :
+ first(addr), last(addr)
+{
+ if (row_span > 0)
+ last.row += row_span - 1;
+ if (col_span > 0)
+ last.column += col_span - 1;
+}
+
+abs_range_t::abs_range_t(const abs_address_t& addr) :
+ first(addr), last(addr) {}
+
+std::size_t abs_range_t::hash::operator() (const abs_range_t& range) const
+{
+ abs_address_t::hash adr_hash;
+ return adr_hash(range.first) + 65536*adr_hash(range.last);
+}
+
+bool abs_range_t::valid() const
+{
+ return first.valid() && last.valid() &&
+ first.sheet <= last.sheet &&
+ first.column <= last.column &&
+ first.row <= last.row;
+}
+
+void abs_range_t::set_all_columns()
+{
+ first.column = column_unset;
+ last.column = column_unset;
+}
+
+void abs_range_t::set_all_rows()
+{
+ first.row = row_unset;
+ last.row = row_unset;
+}
+
+bool abs_range_t::all_columns() const
+{
+ return first.column == column_unset && last.column == column_unset;
+}
+
+bool abs_range_t::all_rows() const
+{
+ return first.row == row_unset && last.row == row_unset;
+}
+
+bool abs_range_t::contains(const abs_address_t& addr) const
+{
+ return first.sheet <= addr.sheet && addr.sheet <= last.sheet &&
+ first.row <= addr.row && addr.row <= last.row &&
+ first.column <= addr.column && addr.column <= last.column;
+}
+
+void abs_range_t::reorder()
+{
+ if (first.sheet > last.sheet)
+ std::swap(first.sheet, last.sheet);
+
+ if (first.row > last.row)
+ std::swap(first.row, last.row);
+
+ if (first.column > last.column)
+ std::swap(first.column, last.column);
+}
+
+bool operator==(const abs_range_t& left, const abs_range_t& right)
+{
+ return left.first == right.first && left.last == right.last;
+}
+
+bool operator!=(const abs_range_t& left, const abs_range_t& right)
+{
+ return !operator==(left, right);
+}
+
+bool operator<(const abs_range_t& left, const abs_range_t& right)
+{
+ if (left.first != right.first)
+ return left.first < right.first;
+ return left.last < right.last;
+}
+
+abs_rc_range_t::abs_rc_range_t() {}
+abs_rc_range_t::abs_rc_range_t(init_invalid) :
+ first(abs_rc_address_t::invalid), last(abs_rc_address_t::invalid) {}
+
+abs_rc_range_t::abs_rc_range_t(const abs_rc_range_t& other) :
+ first(other.first), last(other.last) {}
+
+abs_rc_range_t::abs_rc_range_t(const abs_range_t& other) :
+ first(other.first), last(other.last) {}
+
+size_t abs_rc_range_t::hash::operator() (const abs_rc_range_t& range) const
+{
+ abs_rc_address_t::hash adr_hash;
+ return adr_hash(range.first) + 65536*adr_hash(range.last);
+}
+
+bool abs_rc_range_t::valid() const
+{
+ if (!first.valid() || !last.valid())
+ return false;
+
+ if (first.row != row_unset && last.row != row_unset)
+ {
+ if (first.row > last.row)
+ return false;
+ }
+
+ if (first.column != column_unset && last.column != column_unset)
+ {
+ if (first.column > last.column)
+ return false;
+ }
+
+ return true;
+}
+
+void abs_rc_range_t::set_all_columns()
+{
+ first.column = column_unset;
+ last.column = column_unset;
+}
+
+void abs_rc_range_t::set_all_rows()
+{
+ first.row = row_unset;
+ last.row = row_unset;
+}
+
+bool abs_rc_range_t::all_columns() const
+{
+ return first.column == column_unset && last.column == column_unset;
+}
+
+bool abs_rc_range_t::all_rows() const
+{
+ return first.row == row_unset && last.row == row_unset;
+}
+
+bool abs_rc_range_t::contains(const abs_rc_address_t& addr) const
+{
+ return first.row <= addr.row && addr.row <= last.row &&
+ first.column <= addr.column && addr.column <= last.column;
+}
+
+bool operator==(const abs_rc_range_t& left, const abs_rc_range_t& right)
+{
+ return left.first == right.first && left.last == right.last;
+}
+
+bool operator!=(const abs_rc_range_t& left, const abs_rc_range_t& right)
+{
+ return !operator==(left, right);
+}
+
+bool operator<(const abs_rc_range_t& left, const abs_rc_range_t& right)
+{
+ if (left.first != right.first)
+ return left.first < right.first;
+ return left.last < right.last;
+}
+
+range_t::range_t() {}
+range_t::range_t(const address_t& _first, const address_t& _last) :
+ first(_first), last(_last) {}
+
+range_t::range_t(const range_t& r) : first(r.first), last(r.last) {}
+range_t::range_t(const abs_range_t& r) : first(r.first), last(r.last) {}
+
+bool range_t::valid() const
+{
+ return first.valid() && last.valid();
+}
+
+void range_t::set_all_columns()
+{
+ first.column = column_unset;
+ last.column = column_unset;
+}
+
+void range_t::set_all_rows()
+{
+ first.row = row_unset;
+ last.row = row_unset;
+}
+
+bool range_t::all_columns() const
+{
+ return first.column == column_unset && last.column == column_unset;
+}
+
+bool range_t::all_rows() const
+{
+ return first.row == row_unset && last.row == row_unset;
+}
+
+abs_range_t range_t::to_abs(const abs_address_t& origin) const
+{
+ abs_range_t ret;
+ ret.first = first.to_abs(origin);
+ ret.last = last.to_abs(origin);
+ return ret;
+}
+
+void range_t::set_absolute(bool abs)
+{
+ first.set_absolute(abs);
+ last.set_absolute(abs);
+}
+
+std::size_t range_t::hash::operator() (const range_t& range) const
+{
+ address_t::hash adr_hash;
+ return adr_hash(range.first) + 65536*adr_hash(range.last);
+}
+
+bool operator==(const range_t& left, const range_t& right)
+{
+ return left.first == right.first && left.last == right.last;
+}
+
+bool operator!=(const range_t& left, const range_t& right)
+{
+ return !operator==(left, right);
+}
+
+std::ostream& operator<<(std::ostream& os, const abs_address_t& addr)
+{
+ os << "(sheet:" << addr.sheet << "; row:" << addr.row << "; column:" << addr.column << ")";
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os, const abs_rc_address_t& addr)
+{
+ os << "(row:" << addr.row << "; column:" << addr.column << ")";
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os, const address_t& addr)
+{
+ os << "(sheet:" << addr.sheet << " " << (addr.abs_sheet?"abs":"rel")
+ << "; row:" << addr.row << " " << (addr.abs_row?"abs":"rel")
+ <<"; column:" << addr.column << " " << (addr.abs_column?"abs":"rel") << ")";
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os, const abs_range_t& range)
+{
+ os << range.first << "-" << range.last;
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os, const abs_rc_range_t& range)
+{
+ os << range.first << "-" << range.last;
+ return os;
+}
+
+std::ostream& operator<<(std::ostream& os, const range_t& range)
+{
+ os << range.first << "-" << range.last;
+ return os;
+}
+
+}
+
+/* vim:set shiftwidth=4 softtabstop=4 expandtab: */