From 1474c8ab8294ddf4428dbf30cf9c01d3bf8a769f Mon Sep 17 00:00:00 2001 From: Thomas Fussell Date: Thu, 3 Nov 2016 19:26:11 -0400 Subject: [PATCH] begin trying to garbage collect cell formats --- include/xlnt/styles/format.hpp | 1 + source/cell/cell.cpp | 2 +- source/cell/tests/test_cell.hpp | 12 +++++ source/detail/stylesheet.hpp | 92 ++++++++++++++++++++++----------- source/styles/format.cpp | 1 + source/workbook/workbook.cpp | 11 ++++ 6 files changed, 88 insertions(+), 31 deletions(-) diff --git a/include/xlnt/styles/format.hpp b/include/xlnt/styles/format.hpp index f609c235..1bc184dd 100644 --- a/include/xlnt/styles/format.hpp +++ b/include/xlnt/styles/format.hpp @@ -32,6 +32,7 @@ namespace xlnt { class alignment; class border; +class cell; class fill; class font; class number_format; diff --git a/source/cell/cell.cpp b/source/cell/cell.cpp index 0bcd539b..feda50cd 100644 --- a/source/cell/cell.cpp +++ b/source/cell/cell.cpp @@ -781,7 +781,7 @@ void cell::set_font(const font &font_) { auto &format = duplicate_format(); format.font(font_, true); - d_->format_id_ = format.id(); + d_->format_id_ = format.id(); } void cell::set_number_format(const number_format &number_format_) diff --git a/source/cell/tests/test_cell.hpp b/source/cell/tests/test_cell.hpp index c3f1c4a4..276183c4 100644 --- a/source/cell/tests/test_cell.hpp +++ b/source/cell/tests/test_cell.hpp @@ -18,6 +18,18 @@ public: wb_guess_types.set_guess_types(true); } + void test_temp() + { + xlnt::workbook wb; + auto ws = wb.get_active_sheet(); + auto cell = ws.get_cell("A1"); + cell.set_value(3.141592); + cell.set_font(xlnt::font().bold(true)); + cell.set_font(xlnt::font().size(20)); + wb.save("a.xlsx"); + wb.load("a.xlsx"); + } + void test_infer_numeric() { auto ws = wb_guess_types.create_sheet(); diff --git a/source/detail/stylesheet.hpp b/source/detail/stylesheet.hpp index b9bb9bc6..674a0a9a 100644 --- a/source/detail/stylesheet.hpp +++ b/source/detail/stylesheet.hpp @@ -29,9 +29,13 @@ #include #include +#include #include #include #include +#include +#include +#include namespace xlnt { namespace detail { @@ -46,41 +50,17 @@ struct stylesheet { format_impls.push_back(format_impl()); auto &impl = format_impls.back(); + impl.parent = this; impl.id = format_impls.size() - 1; + impl.border_id = 0; + impl.fill_id = 0; + impl.font_id = 0; + impl.number_format_id = 0; + formats.push_back(format(&impl)); auto &format = formats.back(); - if (!alignments.empty()) - { - format.alignment(alignments.front(), false); - } - - if (!borders.empty()) - { - format.border(borders.front(), false); - } - - if (!fills.empty()) - { - format.fill(fills.front(), false); - } - - if (!fonts.empty()) - { - format.font(fonts.front(), false); - } - - if (!number_formats.empty()) - { - format.number_format(number_formats.front(), false); - } - - if (!protections.empty()) - { - format.protection(protections.front(), false); - } - return format; } @@ -214,6 +194,58 @@ struct stylesheet colors.clear(); } + format_impl *deduplicate(format_impl *f) + { + std::unordered_map reference_counts; + + for (auto ws : *parent) + { + auto dimension = ws.calculate_dimension(); + + for (auto row = dimension.get_top_left().get_row(); row <= dimension.get_bottom_right().get_row(); row++) + { + for (auto column = dimension.get_top_left().get_column(); column <= dimension.get_bottom_right().get_column(); column++) + { + if (ws.has_cell(cell_reference(column, row))) + { + auto cell = ws.get_cell(cell_reference(column, row)); + + if (cell.has_format()) + { + reference_counts[formats.at(cell.get_format().id()).d_]++; + } + } + } + } + } + + auto result = f; + + for (auto &impl : format_impls) + { + if (reference_counts[&impl] == 0 && &impl != f) + { + result = &impl; + break; + } + } + + /* + if (result != f) + { + auto impl_iter = std::find_if(format_impls.begin(), format_impls.end(), + [=](const format_impl &impl) { return &impl == f; }); + auto index = std::distance(format_impls.begin(), impl_iter); + formats.erase(formats.begin() + index); + format_impls.erase(impl_iter); + } + */ + + return f; + } + + workbook *parent; + std::list format_impls; std::vector formats; diff --git a/source/styles/format.cpp b/source/styles/format.cpp index 1bfb5cb7..f6f2e0b0 100644 --- a/source/styles/format.cpp +++ b/source/styles/format.cpp @@ -123,6 +123,7 @@ void format::font(const xlnt::font &new_font, bool applied) { font_id(d_->parent->add_font(new_font)); base_format::font(new_font, applied); + d_ = d_->parent->deduplicate(d_); } xlnt::number_format &format::number_format() diff --git a/source/workbook/workbook.cpp b/source/workbook/workbook.cpp index de13debf..e79fc2e5 100644 --- a/source/workbook/workbook.cpp +++ b/source/workbook/workbook.cpp @@ -343,6 +343,10 @@ workbook::workbook() workbook::workbook(detail::workbook_impl *impl) : d_(impl) { + if (impl != nullptr) + { + d_->stylesheet_.parent = this; + } } void workbook::register_app_properties_in_manifest() @@ -913,6 +917,8 @@ void swap(workbook &left, workbook &right) { ws.set_parent(left); } + + left.d_->stylesheet_.parent = &left; } if (right.d_ != nullptr) @@ -921,12 +927,15 @@ void swap(workbook &left, workbook &right) { ws.set_parent(right); } + + right.d_->stylesheet_.parent = &right; } } workbook &workbook::operator=(workbook other) { swap(*this, other); + d_->stylesheet_.parent = this; return *this; } @@ -943,6 +952,8 @@ workbook::workbook(const workbook &other) : workbook() { ws.set_parent(*this); } + + d_->stylesheet_.parent = this; } workbook::~workbook()