Commit 0915864b authored by Kohei Yoshida's avatar Kohei Yoshida

Implement fill_down_cells() in model_context.

For now, filling down of formula cells is not supported.

This addresses #15.
parent 1f72b58b
Pipeline #50854577 passed with stage
in 3 minutes and 48 seconds
......@@ -59,6 +59,13 @@ private:
error_type m_type;
};
class IXION_DLLPUBLIC not_implemented_error : public general_error
{
public:
explicit not_implemented_error(const std::string& msg);
virtual ~not_implemented_error() throw();
};
}
#endif
......
......@@ -124,6 +124,16 @@ public:
void set_string_cell(const abs_address_t& addr, const char* p, size_t n);
void set_string_cell(const abs_address_t& addr, string_id_t identifier);
/**
* Duplicate the value of the source cell to one or more cells located
* immediately below it.
*
* @param src position of the source cell to copy the value from.
* @param n_dst number of cells below to copy the value to. It must be at
* least one.
*/
void fill_down_cells(const abs_address_t& src, size_t n_dst);
/**
* Set a formula cell at a specified address.
*
......
......@@ -48,6 +48,15 @@ model_context_error::error_type model_context_error::get_error_type() const
return m_type;
}
not_implemented_error::not_implemented_error(const std::string& msg)
{
std::ostringstream os;
os << "not_implemented_error: " << msg;
set_message(os.str());
}
not_implemented_error::~not_implemented_error() {}
}
/* vim:set shiftwidth=4 softtabstop=4 expandtab: */
......@@ -1400,6 +1400,53 @@ void test_model_context_iterator_vertical_range()
assert(check_model_iterator_output(iter, checks));
}
void test_model_context_fill_down()
{
nullptr_t empty = nullptr;
model_context cxt;
cxt.append_sheet(IXION_ASCII("test"), 100, 10);
cxt.set_cell_values(0, {
{ "numeric", "bool", "string", "empty" },
{ 12.3, true, "foo", empty },
{ empty, empty, empty, 1.1 },
{ empty, empty, empty, 1.1 },
{ empty, empty, empty, 1.1 },
{ empty, empty, empty, 1.1 },
{ empty, empty, empty, 1.1 },
});
abs_address_t pos(0, 1, 0);
cxt.fill_down_cells(pos, 2);
assert(cxt.get_numeric_value(abs_address_t(0, 1, 0)) == 12.3);
assert(cxt.get_numeric_value(abs_address_t(0, 2, 0)) == 12.3);
assert(cxt.get_numeric_value(abs_address_t(0, 3, 0)) == 12.3);
assert(cxt.is_empty(abs_address_t(0, 4, 0)));
pos.column = 1;
cxt.fill_down_cells(pos, 1);
assert(cxt.get_boolean_value(abs_address_t(0, 1, 1)) == true);
assert(cxt.get_boolean_value(abs_address_t(0, 2, 1)) == true);
assert(cxt.is_empty(abs_address_t(0, 3, 1)));
pos.column = 2;
string_id_t s_foo = cxt.get_string_identifier(pos);
const std::string* p = cxt.get_string(s_foo);
assert(p && *p == "foo");
cxt.fill_down_cells(pos, 3);
assert(cxt.get_string_identifier(abs_address_t(0, 2, 2)) == s_foo);
assert(cxt.get_string_identifier(abs_address_t(0, 3, 2)) == s_foo);
assert(cxt.get_string_identifier(abs_address_t(0, 4, 2)) == s_foo);
assert(cxt.is_empty(abs_address_t(0, 5, 2)));
pos.column = 3;
cxt.fill_down_cells(pos, 2);
assert(cxt.is_empty(pos));
assert(cxt.is_empty(abs_address_t(0, 2, 3)));
assert(cxt.is_empty(abs_address_t(0, 3, 3)));
assert(cxt.get_numeric_value(abs_address_t(0, 4, 3)) == 1.1);
}
void test_volatile_function()
{
cout << "test volatile function" << endl;
......@@ -1503,6 +1550,7 @@ int main()
test_model_context_iterator_horizontal_range();
test_model_context_iterator_vertical();
test_model_context_iterator_vertical_range();
test_model_context_fill_down();
test_volatile_function();
return EXIT_SUCCESS;
......
......@@ -111,6 +111,7 @@ public:
void set_boolean_cell(const abs_address_t& addr, bool val);
void set_string_cell(const abs_address_t& addr, const char* p, size_t n);
void set_string_cell(const abs_address_t& addr, string_id_t identifier);
void fill_down_cells(const abs_address_t& src, size_t n_dst);
void set_formula_cell(const abs_address_t& addr, formula_tokens_t tokens);
void set_formula_cell(const abs_address_t& addr, const formula_tokens_store_ptr_t& tokens);
void set_grouped_formula_cells(const abs_range_t& group_range, formula_tokens_t tokens);
......@@ -611,6 +612,61 @@ void model_context_impl::set_string_cell(const abs_address_t& addr, const char*
pos_hint = col_store.set(pos_hint, addr.row, str_id);
}
void model_context_impl::fill_down_cells(const abs_address_t& src, size_t n_dst)
{
if (!n_dst)
// Destination cell length is 0. Nothing to copy to.
return;
worksheet& sheet = m_sheets.at(src.sheet);
column_store_t& col_store = sheet.at(src.column);
column_store_t::iterator& pos_hint = sheet.get_pos_hint(src.column);
column_store_t::const_position_type pos = col_store.position(pos_hint, src.row);
auto it = pos.first; // block iterator
switch (it->type)
{
case element_type_numeric:
{
double v = col_store.get<numeric_element_block>(pos);
std::vector<double> vs(n_dst, v);
pos_hint = col_store.set(pos_hint, src.row+1, vs.begin(), vs.end());
break;
}
case element_type_boolean:
{
bool b = col_store.get<boolean_element_block>(pos);
std::deque<bool> vs(n_dst, b);
pos_hint = col_store.set(pos_hint, src.row+1, vs.begin(), vs.end());
break;
}
case element_type_string:
{
string_id_t sid = col_store.get<string_element_block>(pos);
std::vector<string_id_t> vs(n_dst, sid);
pos_hint = col_store.set(pos_hint, src.row+1, vs.begin(), vs.end());
break;
}
case element_type_empty:
{
size_t start_pos = src.row + 1;
size_t end_pos = start_pos + n_dst - 1;
pos_hint = col_store.set_empty(pos_hint, start_pos, end_pos);
break;
}
case element_type_formula:
// TODO : support this.
throw not_implemented_error("filling down of a formula cell is not yet supported.");
default:
{
std::ostringstream os;
os << __FUNCTION__ << ": unhandled block type (" << it->type << ")";
throw general_error(os.str());
}
}
}
void model_context_impl::set_string_cell(const abs_address_t& addr, string_id_t identifier)
{
worksheet& sheet = m_sheets.at(addr.sheet);
......@@ -1021,6 +1077,11 @@ void model_context::set_string_cell(const abs_address_t& addr, const char* p, si
mp_impl->set_string_cell(addr, p, n);
}
void model_context::fill_down_cells(const abs_address_t& src, size_t n_dst)
{
mp_impl->fill_down_cells(src, n_dst);
}
void model_context::set_string_cell(const abs_address_t& addr, string_id_t identifier)
{
mp_impl->set_string_cell(addr, identifier);
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment