Skip to content

Commit

Permalink
optimize shared strings and handle formula strings correctly
Browse files Browse the repository at this point in the history
  • Loading branch information
tfussell committed May 10, 2017
1 parent b851d1c commit d2be054
Show file tree
Hide file tree
Showing 10 changed files with 216 additions and 198 deletions.
24 changes: 14 additions & 10 deletions include/xlnt/cell/cell_type.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -37,18 +37,22 @@ namespace xlnt {
/// </summary>
enum class XLNT_API cell_type
{
/// no value. note: this is different from an empty string value or 0 numeric value
null,
/// number
numeric,
/// string
string,
/// value is a formula
formula,
/// no value
empty,
/// value is TRUE or FALSE
boolean,
/// value is an ISO 8601 formatted date
date,
/// value is a known error code such as \#VALUE!
error,
/// value is TRUE or FALSE
boolean
/// value is a string stored in the cell
inline_string,
/// value is a number
number,
/// value is a string shared with other cells to save space
shared_string,
/// value is the string result of a formula
formula_string
};

} // namespace xlnt
4 changes: 2 additions & 2 deletions include/xlnt/workbook/workbook.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -699,9 +699,9 @@ class XLNT_API workbook
/// Append a shared string to the shared string collection in this workbook.
/// This should not generally be called unless you know what you're doing.
/// If allow_duplicates is false and the string is already in the collection,
/// it will not be added.
/// it will not be added. Returns the index of the added string.
/// </summary>
void add_shared_string(const rich_text &shared, bool allow_duplicates = false);
std::size_t add_shared_string(const rich_text &shared, bool allow_duplicates = false);

/// <summary>
/// Returns a reference to the shared strings being used by cells
Expand Down
106 changes: 50 additions & 56 deletions source/cell/cell.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -194,12 +194,12 @@ cell::cell(detail::cell_impl *d)

bool cell::garbage_collectible() const
{
return !(data_type() != type::null || is_merged() || has_formula() || has_format());
return !(has_value() || is_merged() || has_formula() || has_format());
}

void cell::value(std::nullptr_t)
{
d_->type_ = type::null;
clear_value();
}

void cell::value(bool boolean_value)
Expand All @@ -211,82 +211,56 @@ void cell::value(bool boolean_value)
void cell::value(int int_value)
{
d_->value_numeric_ = static_cast<long double>(int_value);
d_->type_ = type::numeric;
d_->type_ = type::number;
}

void cell::value(unsigned int int_value)
{
d_->value_numeric_ = static_cast<long double>(int_value);
d_->type_ = type::numeric;
d_->type_ = type::number;
}

void cell::value(long long int int_value)
{
d_->value_numeric_ = static_cast<long double>(int_value);
d_->type_ = type::numeric;
d_->type_ = type::number;
}

void cell::value(unsigned long long int int_value)
{
d_->value_numeric_ = static_cast<long double>(int_value);
d_->type_ = type::numeric;
d_->type_ = type::number;
}

void cell::value(float float_value)
{
d_->value_numeric_ = static_cast<long double>(float_value);
d_->type_ = type::numeric;
d_->type_ = type::number;
}

void cell::value(double float_value)
{
d_->value_numeric_ = static_cast<long double>(float_value);
d_->type_ = type::numeric;
d_->type_ = type::number;
}

void cell::value(long double d)
{
d_->value_numeric_ = d;
d_->type_ = type::numeric;
d_->type_ = type::number;
}

void cell::value(const std::string &s)
{
auto checked = check_string(s);

if (checked.size() > 1 && checked.front() == '=')
{
d_->type_ = type::formula;
formula(checked);
}
else if (cell::error_codes().find(checked) != cell::error_codes().end())
{
error(checked);
}
else
{
d_->type_ = type::string;
d_->value_text_.plain_text(checked);

if (checked.size() > 0)
{
workbook().add_shared_string(d_->value_text_);
}
}
value(rich_text(check_string(s)));
}

void cell::value(const rich_text &text)
{
if (text.runs().size() == 1 && !text.runs().front().second.is_set())
{
value(text.plain_text());
}
else
{
d_->type_ = type::string;
d_->value_text_ = text;
workbook().add_shared_string(text);
}
check_string(text.plain_text());

d_->type_ = type::shared_string;
d_->value_numeric_ = static_cast<long double>(workbook().add_shared_string(text));
}

void cell::value(const char *c)
Expand All @@ -306,28 +280,28 @@ void cell::value(const cell c)

void cell::value(const date &d)
{
d_->type_ = type::numeric;
d_->type_ = type::number;
d_->value_numeric_ = d.to_number(base_date());
number_format(number_format::date_yyyymmdd2());
}

void cell::value(const datetime &d)
{
d_->type_ = type::numeric;
d_->type_ = type::number;
d_->value_numeric_ = d.to_number(base_date());
number_format(number_format::date_datetime());
}

void cell::value(const time &t)
{
d_->type_ = type::numeric;
d_->type_ = type::number;
d_->value_numeric_ = t.to_number();
number_format(number_format::date_time6());
}

void cell::value(const timedelta &t)
{
d_->type_ = type::numeric;
d_->type_ = type::number;
d_->value_numeric_ = t.to_number();
number_format(xlnt::number_format("[hh]:mm:ss"));
}
Expand All @@ -354,7 +328,7 @@ bool cell::is_merged() const

bool cell::is_date() const
{
return data_type() == type::numeric && has_format() && number_format().is_date_format();
return data_type() == type::number && has_format() && number_format().is_date_format();
}

cell_reference cell::reference() const
Expand Down Expand Up @@ -429,6 +403,8 @@ void cell::formula(const std::string &formula)
{
d_->formula_ = formula;
}

data_type(type::number);

worksheet().register_calc_chain_in_manifest();
}
Expand Down Expand Up @@ -551,7 +527,7 @@ void cell::clear_value()
{
d_->value_numeric_ = 0;
d_->value_text_.clear();
d_->type_ = cell::type::null;
d_->type_ = cell::type::empty;
clear_formula();
}

Expand Down Expand Up @@ -666,18 +642,23 @@ void cell::protection(const class protection &protection_)
template <>
XLNT_API std::string cell::value() const
{
return d_->value_text_.plain_text();
return value<rich_text>().plain_text();
}

template <>
XLNT_API rich_text cell::value() const
{
if (data_type() == cell::type::shared_string)
{
return workbook().shared_strings().at(static_cast<std::size_t>(d_->value_numeric_));
}

return d_->value_text_;
}

bool cell::has_value() const
{
return d_->type_ != cell::type::null;
return d_->type_ != cell::type::empty;
}

std::string cell::to_string() const
Expand All @@ -686,12 +667,13 @@ std::string cell::to_string() const

switch (data_type())
{
case cell::type::null:
case cell::type::empty:
return "";
case cell::type::numeric:
case cell::type::number:
return nf.format(value<long double>(), base_date());
case cell::type::string:
case cell::type::formula:
case cell::type::inline_string:
case cell::type::shared_string:
case cell::type::formula_string:
case cell::type::error:
return nf.format(value<std::string>());
case cell::type::boolean:
Expand Down Expand Up @@ -731,8 +713,20 @@ void cell::value(const std::string &value_string, bool infer_type)
{
value(value_string);

if (!infer_type)
if (!infer_type || value_string.empty())
{
return;
}

if (value_string.front() == '=' && value_string.size() > 1)
{
formula(value_string);
return;
}

if (value_string.front() == '#' && value_string.size() > 1)
{
error(value_string);
return;
}

Expand All @@ -741,7 +735,7 @@ void cell::value(const std::string &value_string, bool infer_type)
if (percentage.first)
{
d_->value_numeric_ = percentage.second;
d_->type_ = cell::type::numeric;
d_->type_ = cell::type::number;
number_format(xlnt::number_format::percentage());
}
else
Expand All @@ -750,7 +744,7 @@ void cell::value(const std::string &value_string, bool infer_type)

if (time.first)
{
d_->type_ = cell::type::numeric;
d_->type_ = cell::type::number;
number_format(number_format::date_time6());
d_->value_numeric_ = time.second.to_number();
}
Expand All @@ -761,7 +755,7 @@ void cell::value(const std::string &value_string, bool infer_type)
if (numeric.first)
{
d_->value_numeric_ = numeric.second;
d_->type_ = cell::type::numeric;
d_->type_ = cell::type::number;
}
}
}
Expand Down
7 changes: 6 additions & 1 deletion source/detail/implementations/cell_impl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,12 @@ namespace xlnt {
namespace detail {

cell_impl::cell_impl()
: type_(cell_type::null), parent_(nullptr), column_(1), row_(1), is_merged_(false), value_numeric_(0)
: type_(cell_type::empty),
parent_(nullptr),
column_(1),
row_(1),
is_merged_(false),
value_numeric_(0)
{
}

Expand Down
19 changes: 11 additions & 8 deletions source/detail/serialization/xlsx_consumer.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1407,8 +1407,6 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)
read_namespaces();

xlnt::range_reference full_range;

const auto &shared_strings = target_.shared_strings();
auto &manifest = target_.manifest();

const auto workbook_rel = manifest.relationship(path("/"), relationship_type::office_document);
Expand Down Expand Up @@ -1699,15 +1697,20 @@ void xlsx_consumer::read_worksheet(const std::string &rel_id)

if (has_value)
{
if (type == "inlineStr" || type == "str")
if (type == "str")
{
cell.d_->value_text_ = value_string;
cell.data_type(cell::type::formula_string);
}
else if (type == "inlineStr")
{
cell.value(value_string);
cell.d_->value_text_ = value_string;
cell.data_type(cell::type::inline_string);
}
else if (type == "s" && !has_formula)
else if (type == "s")
{
auto shared_string_index = static_cast<std::size_t>(std::stoull(value_string));
auto shared_string = shared_strings.at(shared_string_index);
cell.value(shared_string);
cell.d_->value_numeric_ = std::stold(value_string);
cell.data_type(cell::type::shared_string);
}
else if (type == "b") // boolean
{
Expand Down
Loading

0 comments on commit d2be054

Please sign in to comment.