Move plugin init code
[gnumeric.git] / src / go-data-cache.c
blob8fb3cd7600104bfe8d71c10d834283c8f4a16ba1
1 /*
2 * go-data-cache.h : The definition of a content for a data slicer
4 * Copyright (C) 2008 Jody Goldberg (jody@gnome.org)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public License as
8 * published by the Free Software Foundation; either version 2 of the
9 * License, or (at your option) version 3.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301
19 * USA
22 #include <gnumeric-config.h>
23 #include <go-data-cache-impl.h>
24 #include <go-data-cache-source.h>
25 #include <go-data-cache-field-impl.h>
27 #include <gsf/gsf-impl-utils.h>
28 #include <glib/gi18n-lib.h>
29 #include <string.h>
31 #define GO_DATA_CACHE_CLASS(k) (G_TYPE_CHECK_CLASS_CAST ((k), GO_DATA_CACHE_TYPE, GODataCacheClass))
32 #define IS_GO_DATA_CACHE_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), GO_DATA_CACHE_TYPE))
33 #define GO_DATA_CACHE_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), GO_DATA_CACHE_TYPE, GODataCacheClass))
35 enum {
36 PROP_0,
37 PROP_REFRESHED_BY, /* char * */
38 PROP_REFRESHED_ON, /* GOVal * */
39 PROP_REFRESH_UPGRADES, /* bool */
40 PROP_XL_REFRESH_VER, /* unsigned int */
41 PROP_XL_CREATED_VER /* unsigned int */
44 /*****************************************************************/
46 static void
47 go_data_cache_records_set_size (GODataCache *cache, unsigned int n)
49 int expand;
51 g_return_if_fail (cache->record_size > 0);
52 g_return_if_fail (n < G_MAXUINT / cache->record_size);
54 expand = n - cache->records_allocated;
55 if (0 == expand)
56 return;
58 cache->records = g_realloc (cache->records, n * cache->record_size);
59 if (expand > 0)
60 memset (cache->records + cache->records_allocated * cache->record_size, 0,
61 expand * cache->record_size);
62 cache->records_allocated = n;
65 static guint8 *
66 go_data_cache_records_fetch_index (GODataCache *cache, unsigned i)
68 if (cache->records_allocated <= i) {
69 go_data_cache_records_set_size (cache, i+128);
70 if (cache->records_allocated <= i)
71 return NULL;
74 if (cache->records_len <= i)
75 cache->records_len = i + 1;
77 return go_data_cache_records_index (cache, i);
80 static void
81 go_data_cache_records_init (GODataCache *cache, unsigned int n, unsigned int record_size)
83 cache->record_size = record_size;
84 cache->records_len = 0;
85 go_data_cache_records_set_size (cache, n);
88 /*****************************************************************/
90 static GObjectClass *parent_klass;
91 static void
92 go_data_cache_init (GODataCache *cache)
94 cache->fields = g_ptr_array_new ();
95 cache->data_source = NULL;
96 cache->records = NULL;
97 cache->records_len = cache->records_allocated = 0;
99 cache->refreshed_by = NULL;
100 cache->refreshed_on = NULL;
101 cache->refresh_upgrades = TRUE;
103 cache->XL_created_ver = 1;
104 cache->XL_refresh_ver = 1;
107 static void
108 go_data_cache_finalize (GObject *obj)
110 GODataCache *cache = (GODataCache *)obj;
111 unsigned i;
113 if (NULL != cache->records) {
114 for (i = cache->fields->len ; i-- > 0 ; ) {
115 GODataCacheField const *f = g_ptr_array_index (cache->fields, i);
116 if (GO_DATA_CACHE_FIELD_TYPE_INLINE == f->ref_type) {
117 unsigned j;
118 for (j = cache->records_len ; j-- > 0 ; ) {
119 GOVal *v;
120 gpointer p = go_data_cache_records_index (cache, j) + f->offset;
121 memcpy (&v, p, sizeof (v));
122 go_val_free (v);
126 g_free (cache->records);
127 cache->records = NULL;
128 cache->records_len = cache->records_allocated = 0;
131 for (i = cache->fields->len ; i-- > 0 ; )
132 g_object_unref (g_ptr_array_index (cache->fields, i));
133 g_ptr_array_free (cache->fields, TRUE);
134 cache->fields = NULL;
136 if (NULL != cache->data_source) {
137 g_object_unref (cache->data_source);
138 cache->data_source = NULL;
141 g_free (cache->refreshed_by);
142 go_val_free (cache->refreshed_on);
144 (parent_klass->finalize) (obj);
147 static void
148 go_data_cache_set_property (GObject *obj, guint property_id,
149 GValue const *value, GParamSpec *pspec)
151 GODataCache *cache = (GODataCache *)obj;
153 switch (property_id) {
154 case PROP_REFRESHED_BY:
155 g_free (cache->refreshed_by);
156 cache->refreshed_by = g_value_dup_string (value);
157 break;
158 case PROP_REFRESHED_ON:
159 go_val_free (cache->refreshed_on);
160 cache->refreshed_on = g_value_dup_boxed (value);
161 break;
162 case PROP_REFRESH_UPGRADES : cache->refresh_upgrades = g_value_get_boolean (value); break;
163 case PROP_XL_REFRESH_VER : cache->XL_refresh_ver = g_value_get_uint (value); break;
164 case PROP_XL_CREATED_VER : cache->XL_created_ver = g_value_get_uint (value); break;
166 default:
167 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
171 static void
172 go_data_cache_get_property (GObject *obj, guint property_id,
173 GValue *value, GParamSpec *pspec)
175 GODataCache const *cache = (GODataCache const *)obj;
176 switch (property_id) {
177 case PROP_REFRESHED_BY : g_value_set_string (value, cache->refreshed_by); break;
178 case PROP_REFRESHED_ON : g_value_set_boxed (value, cache->refreshed_on); break;
179 case PROP_REFRESH_UPGRADES : g_value_set_boolean (value, cache->refresh_upgrades); break;
180 case PROP_XL_REFRESH_VER : g_value_set_uint (value, cache->XL_refresh_ver); break;
181 case PROP_XL_CREATED_VER : g_value_set_uint (value, cache->XL_created_ver); break;
182 default:
183 G_OBJECT_WARN_INVALID_PROPERTY_ID (obj, property_id, pspec);
187 static void
188 go_data_cache_class_init (GODataCacheClass *klass)
190 GObjectClass *gobject_class = (GObjectClass *)klass;
191 gobject_class->set_property = go_data_cache_set_property;
192 gobject_class->get_property = go_data_cache_get_property;
193 gobject_class->finalize = go_data_cache_finalize;
195 g_object_class_install_property (gobject_class, PROP_REFRESHED_BY,
196 g_param_spec_string ("refreshed-by", NULL, NULL, NULL,
197 GSF_PARAM_STATIC | G_PARAM_READWRITE));
198 g_object_class_install_property (gobject_class, PROP_REFRESHED_ON,
199 g_param_spec_boxed ("refreshed-on", NULL, NULL,
200 GO_VAL_TYPE, GSF_PARAM_STATIC | G_PARAM_READWRITE));
201 g_object_class_install_property (gobject_class, PROP_REFRESH_UPGRADES,
202 g_param_spec_boolean ("refresh-upgrades", NULL, NULL,
203 TRUE, GSF_PARAM_STATIC | G_PARAM_READWRITE));
204 g_object_class_install_property (gobject_class, PROP_XL_REFRESH_VER,
205 g_param_spec_uint ("refresh-version", NULL, NULL,
206 0, G_MAXUINT, 1, GSF_PARAM_STATIC | G_PARAM_READWRITE));
207 g_object_class_install_property (gobject_class, PROP_XL_CREATED_VER,
208 g_param_spec_uint ("created-version", NULL, NULL,
209 0, G_MAXUINT, 1, GSF_PARAM_STATIC | G_PARAM_READWRITE));
211 parent_klass = g_type_class_peek_parent (klass);
214 GSF_CLASS (GODataCache, go_data_cache,
215 go_data_cache_class_init, go_data_cache_init,
216 G_TYPE_OBJECT)
218 GODataCacheSource *
219 go_data_cache_get_source (GODataCache const *cache)
221 g_return_val_if_fail (IS_GO_DATA_CACHE (cache), NULL);
222 return cache->data_source;
226 * go_data_cache_set_source:
227 * @cache: #GODataCache
228 * @src: #GODataCacheSource
230 * Absorbs the reference to @src.
232 void
233 go_data_cache_set_source (GODataCache *cache, GODataCacheSource *src)
235 g_return_if_fail (IS_GO_DATA_CACHE (cache));
236 g_return_if_fail (NULL == src || IS_GO_DATA_CACHE_SOURCE (src));
238 if (cache->data_source)
239 g_object_unref (cache->data_source);
240 cache->data_source = src;
243 void
244 go_data_cache_add_field (GODataCache *cache, GODataCacheField *field)
246 g_return_if_fail (IS_GO_DATA_CACHE (cache));
247 g_return_if_fail (IS_GO_DATA_CACHE_FIELD (field));
248 g_return_if_fail (field->indx < 0);
249 g_return_if_fail (field->cache == NULL);
250 g_return_if_fail (NULL == cache->records);
252 field->indx = cache->fields->len;
253 field->cache = cache;
254 g_ptr_array_add (cache->fields, field);
258 * go_data_cache_import_start:
259 * @cache:#GODataCache
260 * @n: num records
262 * Validate the field setup and initialize the storage.
264 void
265 go_data_cache_import_start (GODataCache *cache, unsigned int n)
267 GODataCacheField *f;
268 unsigned int i, offset = 0;
270 g_return_if_fail (IS_GO_DATA_CACHE (cache));
271 g_return_if_fail (NULL == cache->records);
273 for (i = 0 ; i < cache->fields->len ; i++) {
274 f = g_ptr_array_index (cache->fields, i);
275 f->offset = offset;
276 if (NULL == f->indexed || 0 == f->indexed->len) {
277 if (NULL != f->grouped &&
278 f->group_parent >= 0 && f->group_parent != f->indx)
279 f->ref_type = GO_DATA_CACHE_FIELD_TYPE_NONE;
280 else {
281 offset += sizeof (GOVal *);
282 f->ref_type = GO_DATA_CACHE_FIELD_TYPE_INLINE;
284 } else if (f->indexed->len < ((1<<8) - 1)) {
285 offset += sizeof (guint8);
286 f->ref_type = GO_DATA_CACHE_FIELD_TYPE_INDEXED_I8;
287 } else if (f->indexed->len < ((1<<16) - 1)) {
288 offset += sizeof (guint16);
289 f->ref_type = GO_DATA_CACHE_FIELD_TYPE_INDEXED_I16;
290 } else {
291 offset += sizeof (guint32);
292 f->ref_type = GO_DATA_CACHE_FIELD_TYPE_INDEXED_I32;
296 for (i = 0 ; i < cache->fields->len ; i++) {
297 f = g_ptr_array_index (cache->fields, i);
298 if (f->group_parent >= 0) {
299 GODataCacheField *base = g_ptr_array_index (cache->fields, f->group_parent);
300 g_return_if_fail (base->ref_type != GO_DATA_CACHE_FIELD_TYPE_NONE);
301 f->offset = base->offset;
304 go_data_cache_records_init (cache, n, offset);
307 void
308 go_data_cache_dump_value (GOVal const *v)
310 if (NULL == v) {
311 g_print ("<MISSING>");
312 } else {
313 GOFormat const *fmt = go_val_get_fmt (v);
315 if (NULL != fmt) {
316 char *str = format_value (fmt, v, -1, NULL);
317 g_print ("'%s'", str);
318 g_free (str);
319 } else
320 g_print ("'%s'", value_peek_string (v));
324 void
325 go_data_cache_set_val (GODataCache *cache,
326 int field, unsigned int record_num, GOVal *v)
328 GODataCacheField *f;
329 gpointer p;
331 g_return_if_fail (IS_GO_DATA_CACHE (cache));
332 g_return_if_fail (NULL != cache->records);
333 g_return_if_fail (0 <= field && (unsigned int )field < cache->fields->len);
335 f = g_ptr_array_index (cache->fields, field);
337 #ifdef GO_DEBUG_SLICERS
338 g_print ("\t[%d] ", field);
339 go_data_cache_dump_value (v);
340 #endif
342 p = go_data_cache_records_fetch_index (cache, record_num) + f->offset;
343 switch (f->ref_type) {
344 case GO_DATA_CACHE_FIELD_TYPE_NONE:
345 g_warning ("attempt to set a value for grouped/calculated field #%d : '%s'",
346 f->indx, f->name->str);
347 return;
349 case GO_DATA_CACHE_FIELD_TYPE_INLINE:
350 memcpy (p, &v, sizeof (v));
351 return;
353 case GO_DATA_CACHE_FIELD_TYPE_INDEXED_I8 : *((guint8 *)p) = 0; break;
354 case GO_DATA_CACHE_FIELD_TYPE_INDEXED_I16 : *((guint16 *)p) = 0; break;
355 case GO_DATA_CACHE_FIELD_TYPE_INDEXED_I32 : *((guint32 *)p) = 0; break;
357 default:
358 g_warning ("unknown field type %d", f->ref_type);
360 go_val_free (v);
361 g_warning ("Attempt to store a value in an indexed field");
364 void
365 go_data_cache_set_index (GODataCache *cache,
366 int field, unsigned int record_num, unsigned int idx)
368 GODataCacheField *f;
369 gpointer p;
371 g_return_if_fail (IS_GO_DATA_CACHE (cache));
372 g_return_if_fail (NULL != cache->records);
373 g_return_if_fail (0 <= field && (unsigned int )field < cache->fields->len);
375 f = g_ptr_array_index (cache->fields, field);
377 g_return_if_fail (NULL != f->indexed);
378 g_return_if_fail (idx < f->indexed->len);
380 #ifdef GO_DEBUG_SLICERS
381 g_print ("\t(%d) %d=", field, idx);
382 go_data_cache_dump_value (cache, g_ptr_array_index (f->indexed, idx));
383 #endif
385 p = go_data_cache_records_fetch_index (cache, record_num) + f->offset;
386 switch (f->ref_type) {
387 case GO_DATA_CACHE_FIELD_TYPE_NONE:
388 g_warning ("attempt to get value from grouped/calculated field #%d : '%s'",
389 f->indx, f->name->str);
390 return;
391 case GO_DATA_CACHE_FIELD_TYPE_INLINE: {
392 GOVal *v = go_val_new_empty ();
393 memcpy (p, &v, sizeof (v));
394 break;
396 case GO_DATA_CACHE_FIELD_TYPE_INDEXED_I8 : *((guint8 *)p) = idx+1; break;
397 case GO_DATA_CACHE_FIELD_TYPE_INDEXED_I16 : *((guint16 *)p) = idx+1; break;
398 case GO_DATA_CACHE_FIELD_TYPE_INDEXED_I32 : *((guint32 *)p) = idx+1; break;
400 default:
401 g_warning ("unknown field type %d", f->ref_type);
406 * go_data_cache_import_done:
407 * @cache: #GODataCache
408 * @actual_records: count
410 * Tidy up after an import, and tighten up the amount of memory used to store
411 * the records.
413 void
414 go_data_cache_import_done (GODataCache *cache, unsigned int actual_records)
416 g_return_if_fail (IS_GO_DATA_CACHE (cache));
418 if (actual_records < cache->records_allocated)
419 go_data_cache_records_set_size (cache, actual_records);
422 unsigned int
423 go_data_cache_num_items (GODataCache const *cache)
425 g_return_val_if_fail (IS_GO_DATA_CACHE (cache), 0);
426 return cache->records_allocated;
429 unsigned int
430 go_data_cache_num_fields (GODataCache const *cache)
432 g_return_val_if_fail (IS_GO_DATA_CACHE (cache), 0);
433 return cache->fields->len;
435 GODataCacheField *
436 go_data_cache_get_field (GODataCache const *cache, int i)
438 g_return_val_if_fail (IS_GO_DATA_CACHE (cache), NULL);
439 g_return_val_if_fail (0 <= i && (unsigned int)i < cache->fields->len, NULL);
440 return g_ptr_array_index (cache->fields, i);
444 go_data_cache_get_index (GODataCache const *cache,
445 GODataCacheField const *field, unsigned int record_num)
447 gpointer p;
449 g_return_val_if_fail (IS_GO_DATA_CACHE (cache), -1);
451 p = go_data_cache_records_index (cache, record_num) + field->offset;
452 switch (field->ref_type) {
453 case GO_DATA_CACHE_FIELD_TYPE_NONE : break;
454 case GO_DATA_CACHE_FIELD_TYPE_INLINE : break;
455 case GO_DATA_CACHE_FIELD_TYPE_INDEXED_I8 : return *(guint8 *)p - 1;
456 case GO_DATA_CACHE_FIELD_TYPE_INDEXED_I16 : return *(guint16 *)p - 1;
457 case GO_DATA_CACHE_FIELD_TYPE_INDEXED_I32 : return *(guint32 *)p - 1;
458 default:
459 g_warning ("unknown field type %d", field->ref_type);
461 return -1;
464 typedef struct {
465 GODataCache const *cache;
466 GArray const *field_order;
467 } GODataCacheCompare;
468 static gint
469 cb_go_data_cache_cmp (int const *a, int const * b,
470 GODataCacheCompare const *info)
472 GODataCacheField const *f, *base;
473 GOVal const *va, *vb;
474 gpointer pa, pb;
475 unsigned int idxa, idxb, i;
476 unsigned int const n = info->field_order->len;
477 int res;
479 for (i = 0 ; i < n ; i++) {
480 f = g_ptr_array_index (info->cache->fields, g_array_index (info->field_order, unsigned int, i));
481 base = (f->group_parent < 0) ? f : g_ptr_array_index (info->cache->fields, f->group_parent);
482 pa = go_data_cache_records_index (info->cache, *a) + base->offset;
483 pb = go_data_cache_records_index (info->cache, *b) + base->offset;
484 if (base->ref_type != GO_DATA_CACHE_FIELD_TYPE_INLINE) {
485 switch (base->ref_type) {
486 case GO_DATA_CACHE_FIELD_TYPE_INDEXED_I8 :
487 idxa = *(guint8 *)pa;
488 idxb = *(guint8 *)pb;
489 break;
490 case GO_DATA_CACHE_FIELD_TYPE_INDEXED_I16:
491 idxa = *(guint16 *)pa;
492 idxb = *(guint16 *)pb;
493 break;
494 case GO_DATA_CACHE_FIELD_TYPE_INDEXED_I32:
495 idxa = *(guint32 *)pa;
496 idxb = *(guint32 *)pb;
497 break;
498 default:
499 g_assert_not_reached ();
501 #warning TODO : compare indicies directly, and pre-order the indexed values
502 va = (idxa > 0) ? g_ptr_array_index (base->indexed, idxa-1) : NULL;
503 vb = (idxb > 0) ? g_ptr_array_index (base->indexed, idxb-1) : NULL;
504 } else {
505 va = *((GOVal **)pa);
506 vb = *((GOVal **)pb);
509 if (f->bucketer.type != GO_VAL_BUCKET_NONE)
510 res = go_val_bucketer_apply (&f->bucketer, va) - go_val_bucketer_apply (&f->bucketer, vb);
511 else
512 res = go_val_cmp (&va, &vb);
513 if (res != 0)
514 return res;
516 return 0;
520 * go_data_cache_permute:
521 * @cache: #GODataCache
522 * @field_order: #GArray of unsigned int
523 * @permutation: #GArray of unsigned int that will be re-ordered according to the fields.
526 void
527 go_data_cache_permute (GODataCache const *cache,
528 GArray const *field_order,
529 GArray *permutation)
531 GODataCacheCompare info;
533 g_return_if_fail (IS_GO_DATA_CACHE (cache));
534 g_return_if_fail (field_order);
535 g_return_if_fail (permutation);
537 info.cache = cache;
538 info.field_order = field_order;
539 g_array_sort_with_data (permutation,
540 (GCompareDataFunc) cb_go_data_cache_cmp, &info);
543 void
544 go_data_cache_dump (GODataCache *cache,
545 GArray const *field_order,
546 GArray const *permutation)
548 GODataCacheField const *f, *base;
549 unsigned int iter, i, j, idx, num_fields;
550 gboolean index_val;
551 gpointer p;
552 GOVal *v;
554 g_return_if_fail (IS_GO_DATA_CACHE (cache));
556 num_fields = field_order ? field_order->len : cache->fields->len;
557 for (iter = 0 ; iter < cache->records_len ; iter++) {
559 if (NULL == permutation)
560 i = iter;
561 else if ((i = g_array_index (permutation, unsigned int, iter)) >= 0)
562 g_print ("[%d]", i);
563 else
564 break;
565 g_print ("%d)", iter + 1);
567 for (j = 0 ; j < num_fields ; j++) {
568 f = g_ptr_array_index (cache->fields, field_order ? g_array_index (field_order, unsigned int, j) :j);
569 base = (f->group_parent < 0) ? f : g_ptr_array_index (cache->fields, f->group_parent);
570 p = go_data_cache_records_index (cache, i) + base->offset;
571 index_val = TRUE;
572 switch (base->ref_type) {
573 case GO_DATA_CACHE_FIELD_TYPE_NONE:
574 continue;
575 case GO_DATA_CACHE_FIELD_TYPE_INLINE:
576 memcpy (&v, p, sizeof (v));
577 index_val = FALSE;
578 break;
579 case GO_DATA_CACHE_FIELD_TYPE_INDEXED_I8 : idx = *(guint8 *)p; break;
580 case GO_DATA_CACHE_FIELD_TYPE_INDEXED_I16 : idx = *(guint16 *)p; break;
581 case GO_DATA_CACHE_FIELD_TYPE_INDEXED_I32 : idx = *(guint32 *)p; break;
583 default:
584 g_warning ("unknown field type %d", base->ref_type);
585 continue;
588 if (index_val) {
589 if (idx-- == 0)
590 continue;
591 g_return_if_fail (base->indexed != NULL && idx < base->indexed->len);
593 v = g_ptr_array_index (base->indexed, idx);
594 g_print ("\t(%d) %d=", j, idx);
595 } else
596 g_print ("\t[%d] ", j);
598 if (f->bucketer.type != GO_VAL_BUCKET_NONE) {
599 int res = go_val_bucketer_apply (&f->bucketer, v);
600 go_data_cache_dump_value (g_ptr_array_index (f->grouped, res));
602 go_data_cache_dump_value (v);
604 g_print ("\n");