1 /* -*- Mode: C++; tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 4 -*- */
2 /*
3  * This Source Code Form is subject to the terms of the Mozilla Public
4  * License, v. 2.0. If a copy of the MPL was not distributed with this
5  * file, You can obtain one at http://mozilla.org/MPL/2.0/.
6  */
7 
8 #ifndef INCLUDED_ORCUS_SPREADSHEET_PIVOT_HPP
9 #define INCLUDED_ORCUS_SPREADSHEET_PIVOT_HPP
10 
11 #include "orcus/env.hpp"
12 #include "orcus/pstring.hpp"
13 #include "orcus/types.hpp"
14 #include "orcus/spreadsheet/types.hpp"
15 
16 #include <memory>
17 #include <vector>
18 #include <limits>
19 
20 #include <boost/optional.hpp>
21 
22 namespace ixion {
23 
24 struct abs_range_t;
25 
26 }
27 
28 namespace orcus {
29 
30 class string_pool;
31 
32 namespace spreadsheet {
33 
34 class document;
35 
36 using pivot_cache_indices_t = std::vector<size_t>;
37 
38 struct ORCUS_SPM_DLLPUBLIC pivot_cache_record_value_t
39 {
40     enum class value_type
41     {
42         unknown = 0,
43         boolean,
44         date_time,
45         character,
46         numeric,
47         blank,
48         error,
49         shared_item_index
50     };
51 
52     value_type type;
53 
54     union
55     {
56         bool boolean;
57 
58         struct
59         {
60             // This must point to an interned string instance. May not be
61             // null-terminated.
62             const char* p;
63 
64             size_t n; // Length of the string value.
65 
66         } character;
67 
68         struct
69         {
70             int year;
71             int month;
72             int day;
73             int hour;
74             int minute;
75             double second;
76 
77         } date_time;
78 
79         double numeric;
80 
81         size_t shared_item_index;
82 
83         // TODO : add error value.
84 
85     } value;
86 
87     pivot_cache_record_value_t();
88     pivot_cache_record_value_t(const char* cp, size_t cn);
89     pivot_cache_record_value_t(double v);
90     pivot_cache_record_value_t(size_t index);
91 
92     bool operator== (const pivot_cache_record_value_t& other) const;
93     bool operator!= (const pivot_cache_record_value_t& other) const;
94 };
95 
96 using pivot_cache_record_t = std::vector<pivot_cache_record_value_t>;
97 
98 struct ORCUS_SPM_DLLPUBLIC pivot_cache_item_t
99 {
100     enum class item_type
101     {
102         unknown = 0, boolean, date_time, character, numeric, blank, error
103     };
104 
105     item_type type;
106 
107     union
108     {
109         struct
110         {
111             // This must point to an interned string instance. May not be
112             // null-terminated.
113             const char* p;
114 
115             size_t n; // Length of the string value.
116 
117         } character;
118 
119         struct
120         {
121             int year;
122             int month;
123             int day;
124             int hour;
125             int minute;
126             double second;
127 
128         } date_time;
129 
130         double numeric;
131 
132         error_value_t error;
133 
134         bool boolean;
135 
136     } value;
137 
138     pivot_cache_item_t();
139     pivot_cache_item_t(const char* cp, size_t cn);
140     pivot_cache_item_t(double numeric);
141     pivot_cache_item_t(bool boolean);
142     pivot_cache_item_t(const date_time_t& date_time);
143     pivot_cache_item_t(error_value_t error);
144 
145     pivot_cache_item_t(const pivot_cache_item_t& other);
146     pivot_cache_item_t(pivot_cache_item_t&& other);
147 
148     bool operator< (const pivot_cache_item_t& other) const;
149     bool operator== (const pivot_cache_item_t& other) const;
150 
151     pivot_cache_item_t& operator= (pivot_cache_item_t other);
152 
153     void swap(pivot_cache_item_t& other);
154 };
155 
156 using pivot_cache_items_t = std::vector<pivot_cache_item_t>;
157 
158 /**
159  * Group data for a pivot cache field.
160  */
161 struct ORCUS_SPM_DLLPUBLIC pivot_cache_group_data_t
162 {
163     struct ORCUS_SPM_DLLPUBLIC range_grouping_type
164     {
165         pivot_cache_group_by_t group_by = pivot_cache_group_by_t::range;
166 
167         bool auto_start = true;
168         bool auto_end   = true;
169 
170         double start    = 0.0;
171         double end      = 0.0;
172         double interval = 1.0;
173 
174         date_time_t start_date;
175         date_time_t end_date;
176 
177         range_grouping_type() = default;
178         range_grouping_type(const range_grouping_type& other) = default;
179     };
180 
181     /**
182      * Mapping of base field member indices to the group field item indices.
183      */
184     pivot_cache_indices_t base_to_group_indices;
185 
186     boost::optional<range_grouping_type> range_grouping;
187 
188     /**
189      * Individual items comprising the group.
190      */
191     pivot_cache_items_t items;
192 
193     /** 0-based index of the base field. */
194     size_t base_field;
195 
196     pivot_cache_group_data_t(size_t _base_field);
197     pivot_cache_group_data_t(const pivot_cache_group_data_t& other);
198     pivot_cache_group_data_t(pivot_cache_group_data_t&& other);
199 
200     pivot_cache_group_data_t() = delete;
201 };
202 
203 struct ORCUS_SPM_DLLPUBLIC pivot_cache_field_t
204 {
205     /**
206      * Field name. It must be interned with the string pool belonging to the
207      * document.
208      */
209     pstring name;
210 
211     pivot_cache_items_t items;
212 
213     boost::optional<double> min_value;
214     boost::optional<double> max_value;
215 
216     boost::optional<date_time_t> min_date;
217     boost::optional<date_time_t> max_date;
218 
219     std::unique_ptr<pivot_cache_group_data_t> group_data;
220 
221     pivot_cache_field_t();
222     pivot_cache_field_t(const pstring& _name);
223     pivot_cache_field_t(const pivot_cache_field_t& other);
224     pivot_cache_field_t(pivot_cache_field_t&& other);
225 };
226 
227 class ORCUS_SPM_DLLPUBLIC pivot_cache
228 {
229     struct impl;
230     std::unique_ptr<impl> mp_impl;
231 
232 public:
233     using fields_type = std::vector<pivot_cache_field_t>;
234     using records_type = std::vector<pivot_cache_record_t>;
235 
236     pivot_cache(pivot_cache_id_t cache_id, string_pool& sp);
237     ~pivot_cache();
238 
239     /**
240      * Bulk-insert all the fields in one step. Note that this will replace any
241      * pre-existing fields if any.
242      *
243      * @param fields field instances to move into storage.
244      */
245     void insert_fields(fields_type fields);
246 
247     void insert_records(records_type record);
248 
249     size_t get_field_count() const;
250 
251     /**
252      * Retrieve a field data by its index.
253      *
254      * @param index index of the field to retrieve.
255      *
256      * @return pointer to the field instance, or nullptr if the index is
257      *         out-of-range.
258      */
259     const pivot_cache_field_t* get_field(size_t index) const;
260 
261     pivot_cache_id_t get_id() const;
262 
263     const records_type& get_all_records() const;
264 };
265 
266 class ORCUS_SPM_DLLPUBLIC pivot_collection
267 {
268     struct impl;
269     std::unique_ptr<impl> mp_impl;
270 
271 public:
272     pivot_collection(document& doc);
273     ~pivot_collection();
274 
275     /**
276      * Insert a new pivot cache associated with a worksheet source.
277      *
278      * @param sheet_name name of the sheet where the source data is.
279      * @param range range of the source data.  Note that the sheet indices are
280      *              not used.
281      * @param cache pivot cache instance to store.
282      */
283     void insert_worksheet_cache(
284         const pstring& sheet_name, const ixion::abs_range_t& range, std::unique_ptr<pivot_cache>&& cache);
285 
286     /**
287      * Insert a new pivot cache associated with a table name.
288      *
289      * @param table_name source table name.
290      * @param cache pivot cache instance to store.
291      */
292     void insert_worksheet_cache(const pstring& table_name, std::unique_ptr<pivot_cache>&& cache);
293 
294     /**
295      * Count the number of pivot caches currently stored.
296      *
297      * @return number of pivot caches currently stored in the document.
298      */
299     size_t get_cache_count() const;
300 
301     const pivot_cache* get_cache(
302         const pstring& sheet_name, const ixion::abs_range_t& range) const;
303 
304     pivot_cache* get_cache(pivot_cache_id_t cache_id);
305 
306     const pivot_cache* get_cache(pivot_cache_id_t cache_id) const;
307 };
308 
309 }}
310 
311 #endif
312 
313 /* vim:set shiftwidth=4 softtabstop=4 expandtab: */
314