1
/* -*- Mode: c; c-basic-offset: 4; indent-tabs-mode: t; tab-width: 8; -*- */
2
/* cairo - a vector graphics library with display and print output
3
 *
4
 * Copyright © 2004 Red Hat, Inc
5
 *
6
 * This library is free software; you can redistribute it and/or
7
 * modify it either under the terms of the GNU Lesser General Public
8
 * License version 2.1 as published by the Free Software Foundation
9
 * (the "LGPL") or, at your option, under the terms of the Mozilla
10
 * Public License Version 1.1 (the "MPL"). If you do not alter this
11
 * notice, a recipient may use your version of this file under either
12
 * the MPL or the LGPL.
13
 *
14
 * You should have received a copy of the LGPL along with this library
15
 * in the file COPYING-LGPL-2.1; if not, write to the Free Software
16
 * Foundation, Inc., 51 Franklin Street, Suite 500, Boston, MA 02110-1335, USA
17
 * You should have received a copy of the MPL along with this library
18
 * in the file COPYING-MPL-1.1
19
 *
20
 * The contents of this file are subject to the Mozilla Public License
21
 * Version 1.1 (the "License"); you may not use this file except in
22
 * compliance with the License. You may obtain a copy of the License at
23
 * http://www.mozilla.org/MPL/
24
 *
25
 * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY
26
 * OF ANY KIND, either express or implied. See the LGPL or the MPL for
27
 * the specific language governing rights and limitations.
28
 *
29
 * The Original Code is the cairo graphics library.
30
 *
31
 * The Initial Developer of the Original Code is University of Southern
32
 * California.
33
 *
34
 * Contributor(s):
35
 *	Kristian Høgsberg <krh@redhat.com>
36
 *	Carl Worth <cworth@cworth.org>
37
 */
38

            
39
#include "cairoint.h"
40
#include "cairo-array-private.h"
41
#include "cairo-error-private.h"
42

            
43
/*< private >
44
 * _cairo_array_init:
45
 *
46
 * Initialize a new #cairo_array_t object to store objects each of size
47
 * @element_size.
48
 *
49
 * The #cairo_array_t object provides grow-by-doubling storage. It
50
 * never interprets the data passed to it, nor does it provide any
51
 * sort of callback mechanism for freeing resources held onto by
52
 * stored objects.
53
 *
54
 * When finished using the array, _cairo_array_fini() should be
55
 * called to free resources allocated during use of the array.
56
 **/
57
void
58
2881782
_cairo_array_init (cairo_array_t *array, unsigned int element_size)
59
{
60
2881782
    array->size = 0;
61
2881782
    array->num_elements = 0;
62
2881782
    array->element_size = element_size;
63
2881782
    array->elements = NULL;
64
2881782
}
65

            
66
/*< private >
67
 * _cairo_array_fini:
68
 * @array: A #cairo_array_t
69
 *
70
 * Free all resources associated with @array. After this call, @array
71
 * should not be used again without a subsequent call to
72
 * _cairo_array_init() again first.
73
 **/
74
void
75
597845
_cairo_array_fini (cairo_array_t *array)
76
{
77
597845
    free (array->elements);
78
597845
}
79

            
80
/*< private >
81
 * _cairo_array_grow_by:
82
 * @array: a #cairo_array_t
83
 *
84
 * Increase the size of @array (if needed) so that there are at least
85
 * @additional free spaces in the array. The actual size of the array
86
 * is always increased by doubling as many times as necessary.
87
 **/
88
cairo_status_t
89
72375
_cairo_array_grow_by (cairo_array_t *array, unsigned int additional)
90
{
91
    char *new_elements;
92
72375
    unsigned int old_size = array->size;
93
72375
    unsigned int required_size = array->num_elements + additional;
94
    unsigned int new_size;
95

            
96
    /* check for integer overflow */
97
72375
    if (required_size > INT_MAX || required_size < array->num_elements)
98
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
99

            
100
    if (CAIRO_INJECT_FAULT ())
101
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
102

            
103
72375
    if (required_size <= old_size)
104
46985
	return CAIRO_STATUS_SUCCESS;
105

            
106
25390
    if (old_size == 0)
107
12498
	new_size = 1;
108
    else
109
12892
	new_size = old_size * 2;
110

            
111
41452
    while (new_size < required_size)
112
16062
	new_size = new_size * 2;
113

            
114
25390
    array->size = new_size;
115
50780
    new_elements = _cairo_realloc_ab (array->elements,
116
25390
			              array->size, array->element_size);
117

            
118
25390
    if (unlikely (new_elements == NULL)) {
119
	array->size = old_size;
120
	return _cairo_error (CAIRO_STATUS_NO_MEMORY);
121
    }
122

            
123
25390
    array->elements = new_elements;
124

            
125
25390
    return CAIRO_STATUS_SUCCESS;
126
}
127

            
128
/*< private >
129
 * _cairo_array_truncate:
130
 * @array: a #cairo_array_t
131
 *
132
 * Truncate size of the array to @num_elements if less than the
133
 * current size. No memory is actually freed. The stored objects
134
 * beyond @num_elements are simply "forgotten".
135
 **/
136
void
137
363
_cairo_array_truncate (cairo_array_t *array, unsigned int num_elements)
138
{
139
363
    if (num_elements < array->num_elements)
140
86
	array->num_elements = num_elements;
141
363
}
142

            
143
/*< private >
144
 * _cairo_array_index:
145
 * @array: a #cairo_array_t
146
 *
147
 * If the resulting value is assigned to a pointer to an object of the same
148
 * element_size as initially passed to _cairo_array_init() then that
149
 * pointer may be used for further direct indexing with []. For
150
 * example:
151
 *
152
 * |[<!-- language="C" -->
153
 *	cairo_array_t array;
154
 *	double *values;
155
 *
156
 *	_cairo_array_init (&array, sizeof(double));
157
 *	... calls to _cairo_array_append() here ...
158
 *
159
 *	values = _cairo_array_index (&array, 0);
160
 *      for (i = 0; i < _cairo_array_num_elements (&array); i++)
161
 *	    ... use values[i] here ...
162
 * ]|
163
 *
164
 * Returns: A pointer to the object stored at @index.
165
 **/
166
void *
167
264019
_cairo_array_index (cairo_array_t *array, unsigned int index)
168
{
169
    /* We allow an index of 0 for the no-elements case.
170
     * This makes for cleaner calling code which will often look like:
171
     *
172
     *    elements = _cairo_array_index (array, 0);
173
     *	  for (i=0; i < num_elements; i++) {
174
     *        ... use elements[i] here ...
175
     *    }
176
     *
177
     * which in the num_elements==0 case gets the NULL pointer here,
178
     * but never dereferences it.
179
     */
180
264019
    if (index == 0 && array->num_elements == 0)
181
6694
	return NULL;
182

            
183
257325
    assert (index < array->num_elements);
184

            
185
257325
    return array->elements + (size_t)index * array->element_size;
186
}
187

            
188
/*< private >
189
 * _cairo_array_index_const:
190
 * @array: a #cairo_array_t
191
 *
192
 * If the resulting value is assigned to a pointer to an object of the same
193
 * element_size as initially passed to _cairo_array_init() then that
194
 * pointer may be used for further direct indexing with []. For
195
 * example:
196
 *
197
 * |[<!-- language="C" --.
198
 *	cairo_array_t array;
199
 *	const double *values;
200
 *
201
 *	_cairo_array_init (&array, sizeof(double));
202
 *	... calls to _cairo_array_append() here ...
203
 *
204
 *	values = _cairo_array_index_const (&array, 0);
205
 *      for (i = 0; i < _cairo_array_num_elements (&array); i++)
206
 *	    ... read values[i] here ...
207
 * ]|
208
 *
209
 * Returns: A pointer to the object stored at @index.
210
 **/
211
const void *
212
128438
_cairo_array_index_const (const cairo_array_t *array, unsigned int index)
213
{
214
    /* We allow an index of 0 for the no-elements case.
215
     * This makes for cleaner calling code which will often look like:
216
     *
217
     *    elements = _cairo_array_index_const (array, 0);
218
     *	  for (i=0; i < num_elements; i++) {
219
     *        ... read elements[i] here ...
220
     *    }
221
     *
222
     * which in the num_elements==0 case gets the NULL pointer here,
223
     * but never dereferences it.
224
     */
225
128438
    if (index == 0 && array->num_elements == 0)
226
	return NULL;
227

            
228
128438
    assert (index < array->num_elements);
229

            
230
128438
    return array->elements + (size_t)index * array->element_size;
231
}
232

            
233
/*< private >
234
 * _cairo_array_copy_element:
235
 * @array: a #cairo_array_t
236
 *
237
 * Copy a single element out of the array from index @index into the
238
 * location pointed to by @dst.
239
 **/
240
void
241
77624
_cairo_array_copy_element (const cairo_array_t *array,
242
			   unsigned int         index,
243
			   void                *dst)
244
{
245
77624
    memcpy (dst, _cairo_array_index_const (array, index), array->element_size);
246
77624
}
247

            
248
/*< private >
249
 * _cairo_array_append:
250
 * @array: a #cairo_array_t
251
 *
252
 * Append a single item onto the array by growing the array by at
253
 * least one element, then copying element_size bytes from @element
254
 * into the array. The address of the resulting object within the
255
 * array can be determined with:
256
 *
257
 * _cairo_array_index (array, _cairo_array_num_elements (array) - 1);
258
 *
259
 * Return value: %CAIRO_STATUS_SUCCESS if successful or
260
 * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
261
 * operation.
262
 **/
263
cairo_status_t
264
15220
_cairo_array_append (cairo_array_t	*array,
265
		     const void		*element)
266
{
267
15220
    return _cairo_array_append_multiple (array, element, 1);
268
}
269

            
270
/*< private >
271
 * _cairo_array_append_multiple:
272
 * @array: a #cairo_array_t
273
 *
274
 * Append one or more items onto the array by growing the array by
275
 * @num_elements, then copying @num_elements * element_size bytes from
276
 * @elements into the array.
277
 *
278
 * Return value: %CAIRO_STATUS_SUCCESS if successful or
279
 * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
280
 * operation.
281
 **/
282
cairo_status_t
283
72265
_cairo_array_append_multiple (cairo_array_t	*array,
284
			      const void	*elements,
285
			      unsigned int	 num_elements)
286
{
287
    cairo_status_t status;
288
    void *dest;
289

            
290
72265
    status = _cairo_array_allocate (array, num_elements, &dest);
291
72265
    if (unlikely (status))
292
	return status;
293

            
294
72265
    memcpy (dest, elements, (size_t)num_elements * array->element_size);
295

            
296
72265
    return CAIRO_STATUS_SUCCESS;
297
}
298

            
299
/*< private >
300
 * _cairo_array_allocate:
301
 * @array: a #cairo_array_t
302
 *
303
 * Allocate space at the end of the array for @num_elements additional
304
 * elements, providing the address of the new memory chunk in
305
 * @elements. This memory will be uninitialized, but will be accounted
306
 * for in the return value of _cairo_array_num_elements().
307
 *
308
 * Return value: %CAIRO_STATUS_SUCCESS if successful or
309
 * %CAIRO_STATUS_NO_MEMORY if insufficient memory is available for the
310
 * operation.
311
 **/
312
cairo_status_t
313
72375
_cairo_array_allocate (cairo_array_t	 *array,
314
		       unsigned int	  num_elements,
315
		       void		**elements)
316
{
317
    cairo_status_t status;
318

            
319
72375
    status = _cairo_array_grow_by (array, num_elements);
320
72375
    if (unlikely (status))
321
	return status;
322

            
323
72375
    assert (array->num_elements + num_elements <= array->size);
324

            
325
72375
    *elements = array->elements + (size_t)array->num_elements * array->element_size;
326

            
327
72375
    array->num_elements += num_elements;
328

            
329
72375
    return CAIRO_STATUS_SUCCESS;
330
}
331

            
332
/*< private >
333
 * _cairo_array_num_elements:
334
 * @array: a #cairo_array_t
335
 *
336
 * This space was left intentionally blank, but gtk-doc filled it.
337
 *
338
 * Returns: The number of elements stored in @array.
339
 **/
340
unsigned int
341
358006
_cairo_array_num_elements (const cairo_array_t *array)
342
{
343
358006
    return array->num_elements;
344
}
345

            
346
/*< private >
347
 * _cairo_array_size:
348
 * @array: a #cairo_array_t
349
 *
350
 * This space was left intentionally blank, but gtk-doc filled it.
351
 *
352
 * Returns: The number of elements for which there is currently space
353
 * allocated in @array.
354
 **/
355
unsigned int
356
_cairo_array_size (const cairo_array_t *array)
357
{
358
    return array->size;
359
}
360

            
361
/*< private >
362
 * _cairo_user_data_array_init:
363
 * @array: a #cairo_user_data_array_t
364
 *
365
 * Initializes a #cairo_user_data_array_t structure for future
366
 * use. After initialization, the array has no keys. Call
367
 * _cairo_user_data_array_fini() to free any allocated memory
368
 * when done using the array.
369
 **/
370
void
371
2870703
_cairo_user_data_array_init (cairo_user_data_array_t *array)
372
{
373
2870703
    _cairo_array_init (array, sizeof (cairo_user_data_slot_t));
374
2870703
}
375

            
376
/*< private >
377
 * _cairo_user_data_array_fini:
378
 * @array: a #cairo_user_data_array_t
379
 *
380
 * Destroys all current keys in the user data array and deallocates
381
 * any memory allocated for the array itself.
382
 **/
383
void
384
588998
_cairo_user_data_array_fini (cairo_user_data_array_t *array)
385
{
386
    unsigned int num_slots;
387

            
388
588998
    num_slots = array->num_elements;
389
588998
    if (num_slots) {
390
	cairo_user_data_slot_t *slots;
391

            
392
4051
	slots = _cairo_array_index (array, 0);
393
8253
	while (num_slots--) {
394
4202
	    cairo_user_data_slot_t *s = &slots[num_slots];
395
4202
	    if (s->user_data != NULL && s->destroy != NULL)
396
584
		s->destroy (s->user_data);
397
	}
398
    }
399

            
400
588998
    _cairo_array_fini (array);
401
588998
}
402

            
403
/*< private >
404
 * _cairo_user_data_array_get_data:
405
 * @array: a #cairo_user_data_array_t
406
 * @key: the address of the #cairo_user_data_key_t the user data was
407
 * attached to
408
 *
409
 * Returns user data previously attached using the specified
410
 * key.  If no user data has been attached with the given key this
411
 * function returns %NULL.
412
 *
413
 * Return value: the user data previously attached or %NULL.
414
 **/
415
void *
416
1902
_cairo_user_data_array_get_data (cairo_user_data_array_t     *array,
417
				 const cairo_user_data_key_t *key)
418
{
419
    unsigned int i, num_slots;
420
    cairo_user_data_slot_t *slots;
421

            
422
    /* We allow this to support degenerate objects such as cairo_surface_nil. */
423
1902
    if (array == NULL)
424
	return NULL;
425

            
426
1902
    num_slots = array->num_elements;
427
1902
    slots = _cairo_array_index (array, 0);
428
1906
    for (i = 0; i < num_slots; i++) {
429
1904
	if (slots[i].key == key)
430
1900
	    return slots[i].user_data;
431
    }
432

            
433
2
    return NULL;
434
}
435

            
436
/*< private >
437
 * _cairo_user_data_array_set_data:
438
 * @array: a #cairo_user_data_array_t
439
 * @key: the address of a #cairo_user_data_key_t to attach the user data to
440
 * @user_data: the user data to attach
441
 * @destroy: a #cairo_destroy_func_t which will be called when the
442
 * user data array is destroyed or when new user data is attached using the
443
 * same key.
444
 *
445
 * Attaches user data to a user data array.  To remove user data,
446
 * call this function with the key that was used to set it and %NULL
447
 * for @data.
448
 *
449
 * Return value: %CAIRO_STATUS_SUCCESS or %CAIRO_STATUS_NO_MEMORY if a
450
 * slot could not be allocated for the user data.
451
 **/
452
cairo_status_t
453
5662
_cairo_user_data_array_set_data (cairo_user_data_array_t     *array,
454
				 const cairo_user_data_key_t *key,
455
				 void			     *user_data,
456
				 cairo_destroy_func_t	      destroy)
457
{
458
    cairo_status_t status;
459
    unsigned int i, num_slots;
460
    cairo_user_data_slot_t *slots, *slot, new_slot;
461

            
462
5662
    if (user_data) {
463
5658
	new_slot.key = key;
464
5658
	new_slot.user_data = user_data;
465
5658
	new_slot.destroy = destroy;
466
    } else {
467
4
	new_slot.key = NULL;
468
4
	new_slot.user_data = NULL;
469
4
	new_slot.destroy = NULL;
470
    }
471

            
472
5662
    slot = NULL;
473
5662
    num_slots = array->num_elements;
474
5662
    slots = _cairo_array_index (array, 0);
475
5804
    for (i = 0; i < num_slots; i++) {
476
147
	if (slots[i].key == key) {
477
5
	    slot = &slots[i];
478
5
	    if (slot->destroy && slot->user_data)
479
4
		slot->destroy (slot->user_data);
480
5
	    break;
481
	}
482
142
	if (user_data && slots[i].user_data == NULL) {
483
4
	    slot = &slots[i];	/* Have to keep searching for an exact match */
484
	}
485
    }
486

            
487
5662
    if (slot) {
488
7
	*slot = new_slot;
489
7
	return CAIRO_STATUS_SUCCESS;
490
    }
491

            
492
5655
    if (user_data == NULL)
493
	return CAIRO_STATUS_SUCCESS;
494

            
495
5655
    status = _cairo_array_append (array, &new_slot);
496
5655
    if (unlikely (status))
497
	return status;
498

            
499
5655
    return CAIRO_STATUS_SUCCESS;
500
}
501

            
502
cairo_status_t
503
345
_cairo_user_data_array_copy (cairo_user_data_array_t	*dst,
504
			     const cairo_user_data_array_t	*src)
505
{
506
    /* discard any existing user-data */
507
345
    if (dst->num_elements != 0) {
508
	_cairo_user_data_array_fini (dst);
509
	_cairo_user_data_array_init (dst);
510
    }
511

            
512
    /* don't call _cairo_array_append_multiple if there's nothing to do,
513
     * as it assumes at least 1 element is to be appended */
514
345
    if (src->num_elements == 0)
515
312
        return CAIRO_STATUS_SUCCESS;
516

            
517
33
    return _cairo_array_append_multiple (dst,
518
					 _cairo_array_index_const (src, 0),
519
33
					 src->num_elements);
520
}
521

            
522
void
523
345
_cairo_user_data_array_foreach (cairo_user_data_array_t     *array,
524
				void (*func) (const void *key,
525
					      void *elt,
526
					      void *closure),
527
				void *closure)
528
{
529
    cairo_user_data_slot_t *slots;
530
    unsigned int i, num_slots;
531

            
532
345
    num_slots = array->num_elements;
533
345
    slots = _cairo_array_index (array, 0);
534
396
    for (i = 0; i < num_slots; i++) {
535
51
	if (slots[i].user_data != NULL)
536
51
	    func (slots[i].key, slots[i].user_data, closure);
537
    }
538
345
}
539

            
540
void
541
10
_cairo_array_sort (const cairo_array_t *array, int (*compar)(const void *, const void *))
542
{
543
10
    qsort (array->elements, array->num_elements, array->element_size, compar);
544
10
}
545

            
546
/*< private >
547
 * _cairo_array_pop_element:
548
 * @array: a #cairo_array_t
549
 * Returns: A TRUE if element successfully popped, FALSE if the array is empty.
550
 *
551
 * Copy the last element out of the array from index @index into the
552
 * location pointed to by @dst and remove the element from the array.
553
 **/
554
cairo_bool_t
555
9
_cairo_array_pop_element (cairo_array_t *array, void *dst)
556
{
557
9
    if (array->num_elements > 0) {
558
9
	_cairo_array_copy_element (array, array->num_elements - 1, dst);
559
9
	array->num_elements--;
560
9
	return TRUE;
561
    }
562

            
563
    return FALSE;
564
}
565

            
566
/*< private >
567
 * _cairo_array_top_element:
568
 * @array: a #cairo_array_t
569
 * Returns: A pointer to the last of object or NULL if array is empty.
570
 *
571
 * Get the pointer to the last element of of the array.
572
 **/
573
void *
574
19
_cairo_array_last_element (cairo_array_t *array)
575
{
576
19
    if (array->num_elements > 0)
577
13
	return _cairo_array_index (array, array->num_elements - 1);
578

            
579
6
    return NULL;
580
}