1 /* GLIB - Library of useful routines for C programming 2 * Copyright (C) 1995-1997 Peter Mattis, Spencer Kimball and Josh MacDonald 3 * 4 * This library is free software; you can redistribute it and/or 5 * modify it under the terms of the GNU Lesser General Public 6 * License as published by the Free Software Foundation; either 7 * version 2 of the License, or (at your option) any later version. 8 * 9 * This library is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 12 * Lesser General Public License for more details. 13 * 14 * You should have received a copy of the GNU Lesser General Public 15 * License along with this library; if not, write to the 16 * Free Software Foundation, Inc., 59 Temple Place - Suite 330, 17 * Boston, MA 02111-1307, USA. 18 */ 19 20 /* 21 * Modified by the GLib Team and others 1997-2000. See the AUTHORS 22 * file for a list of people on the GLib Team. See the ChangeLog 23 * files for a list of changes. These files are distributed with 24 * GLib at ftp://ftp.gtk.org/pub/gtk/. 25 */ 26 27 /* 28 * MT safe 29 */ 30 31 #include "config.h" 32 33 #include <string.h> 34 #include <stdlib.h> 35 36 #include "garray.h" 37 38 #include "gmem.h" 39 #include "gthread.h" 40 #include "gmessages.h" 41 #include "gqsort.h" 42 43 #include "galias.h" 44 45 46 #define MIN_ARRAY_SIZE 16 47 48 typedef struct _GRealArray GRealArray; 49 50 struct _GRealArray 51 { 52 guint8 *data; 53 guint len; 54 guint alloc; 55 guint elt_size; 56 guint zero_terminated : 1; 57 guint clear : 1; 58 }; 59 60 #define g_array_elt_len(array,i) ((array)->elt_size * (i)) 61 #define g_array_elt_pos(array,i) ((array)->data + g_array_elt_len((array),(i))) 62 #define g_array_elt_zero(array, pos, len) \ 63 (memset (g_array_elt_pos ((array), pos), 0, g_array_elt_len ((array), len))) 64 #define g_array_zero_terminate(array) G_STMT_START{ \ 65 if ((array)->zero_terminated) \ 66 g_array_elt_zero ((array), (array)->len, 1); \ 67 }G_STMT_END 68 69 static gint g_nearest_pow (gint num) G_GNUC_CONST; 70 static void g_array_maybe_expand (GRealArray *array, 71 gint len); 72 73 GArray* 74 g_array_new (gboolean zero_terminated, 75 gboolean clear, 76 guint elt_size) 77 { 78 return (GArray*) g_array_sized_new (zero_terminated, clear, elt_size, 0); 79 } 80 81 GArray* g_array_sized_new (gboolean zero_terminated, 82 gboolean clear, 83 guint elt_size, 84 guint reserved_size) 85 { 86 GRealArray *array = g_slice_new (GRealArray); 87 88 array->data = NULL; 89 array->len = 0; 90 array->alloc = 0; 91 array->zero_terminated = (zero_terminated ? 1 : 0); 92 array->clear = (clear ? 1 : 0); 93 array->elt_size = elt_size; 94 95 if (array->zero_terminated || reserved_size != 0) 96 { 97 g_array_maybe_expand (array, reserved_size); 98 g_array_zero_terminate(array); 99 } 100 101 return (GArray*) array; 102 } 103 104 gchar* 105 g_array_free (GArray *array, 106 gboolean free_segment) 107 { 108 gchar* segment; 109 110 g_return_val_if_fail (array, NULL); 111 112 if (free_segment) 113 { 114 g_free (array->data); 115 segment = NULL; 116 } 117 else 118 segment = array->data; 119 120 g_slice_free1 (sizeof (GRealArray), array); 121 122 return segment; 123 } 124 125 GArray* 126 g_array_append_vals (GArray *farray, 127 gconstpointer data, 128 guint len) 129 { 130 GRealArray *array = (GRealArray*) farray; 131 132 g_array_maybe_expand (array, len); 133 134 memcpy (g_array_elt_pos (array, array->len), data, 135 g_array_elt_len (array, len)); 136 137 array->len += len; 138 139 g_array_zero_terminate (array); 140 141 return farray; 142 } 143 144 GArray* 145 g_array_prepend_vals (GArray *farray, 146 gconstpointer data, 147 guint len) 148 { 149 GRealArray *array = (GRealArray*) farray; 150 151 g_array_maybe_expand (array, len); 152 153 g_memmove (g_array_elt_pos (array, len), g_array_elt_pos (array, 0), 154 g_array_elt_len (array, array->len)); 155 156 memcpy (g_array_elt_pos (array, 0), data, g_array_elt_len (array, len)); 157 158 array->len += len; 159 160 g_array_zero_terminate (array); 161 162 return farray; 163 } 164 165 GArray* 166 g_array_insert_vals (GArray *farray, 167 guint index_, 168 gconstpointer data, 169 guint len) 170 { 171 GRealArray *array = (GRealArray*) farray; 172 173 g_array_maybe_expand (array, len); 174 175 g_memmove (g_array_elt_pos (array, len + index_), 176 g_array_elt_pos (array, index_), 177 g_array_elt_len (array, array->len - index_)); 178 179 memcpy (g_array_elt_pos (array, index_), data, g_array_elt_len (array, len)); 180 181 array->len += len; 182 183 g_array_zero_terminate (array); 184 185 return farray; 186 } 187 188 GArray* 189 g_array_set_size (GArray *farray, 190 guint length) 191 { 192 GRealArray *array = (GRealArray*) farray; 193 if (length > array->len) 194 { 195 g_array_maybe_expand (array, length - array->len); 196 197 if (array->clear) 198 g_array_elt_zero (array, array->len, length - array->len); 199 } 200 else if (G_UNLIKELY (g_mem_gc_friendly) && length < array->len) 201 g_array_elt_zero (array, length, array->len - length); 202 203 array->len = length; 204 205 g_array_zero_terminate (array); 206 207 return farray; 208 } 209 210 GArray* 211 g_array_remove_index (GArray *farray, 212 guint index_) 213 { 214 GRealArray* array = (GRealArray*) farray; 215 216 g_return_val_if_fail (array, NULL); 217 218 g_return_val_if_fail (index_ < array->len, NULL); 219 220 if (index_ != array->len - 1) 221 g_memmove (g_array_elt_pos (array, index_), 222 g_array_elt_pos (array, index_ + 1), 223 g_array_elt_len (array, array->len - index_ - 1)); 224 225 array->len -= 1; 226 227 if (G_UNLIKELY (g_mem_gc_friendly)) 228 g_array_elt_zero (array, array->len, 1); 229 else 230 g_array_zero_terminate (array); 231 232 return farray; 233 } 234 235 GArray* 236 g_array_remove_index_fast (GArray *farray, 237 guint index_) 238 { 239 GRealArray* array = (GRealArray*) farray; 240 241 g_return_val_if_fail (array, NULL); 242 243 g_return_val_if_fail (index_ < array->len, NULL); 244 245 if (index_ != array->len - 1) 246 memcpy (g_array_elt_pos (array, index_), 247 g_array_elt_pos (array, array->len - 1), 248 g_array_elt_len (array, 1)); 249 250 array->len -= 1; 251 252 if (G_UNLIKELY (g_mem_gc_friendly)) 253 g_array_elt_zero (array, array->len, 1); 254 else 255 g_array_zero_terminate (array); 256 257 return farray; 258 } 259 260 GArray* 261 g_array_remove_range (GArray *farray, 262 guint index_, 263 guint length) 264 { 265 GRealArray *array = (GRealArray*) farray; 266 267 g_return_val_if_fail (array, NULL); 268 g_return_val_if_fail (index_ < array->len, NULL); 269 g_return_val_if_fail (index_ + length <= array->len, NULL); 270 271 if (index_ + length != array->len) 272 g_memmove (g_array_elt_pos (array, index_), 273 g_array_elt_pos (array, index_ + length), 274 (array->len - (index_ + length)) * array->elt_size); 275 276 array->len -= length; 277 if (G_UNLIKELY (g_mem_gc_friendly)) 278 g_array_elt_zero (array, array->len, length); 279 else 280 g_array_zero_terminate (array); 281 282 return farray; 283 } 284 285 void 286 g_array_sort (GArray *farray, 287 GCompareFunc compare_func) 288 { 289 GRealArray *array = (GRealArray*) farray; 290 291 g_return_if_fail (array != NULL); 292 293 qsort (array->data, 294 array->len, 295 array->elt_size, 296 compare_func); 297 } 298 299 void 300 g_array_sort_with_data (GArray *farray, 301 GCompareDataFunc compare_func, 302 gpointer user_data) 303 { 304 GRealArray *array = (GRealArray*) farray; 305 306 g_return_if_fail (array != NULL); 307 308 g_qsort_with_data (array->data, 309 array->len, 310 array->elt_size, 311 compare_func, 312 user_data); 313 } 314 315 316 static gint 317 g_nearest_pow (gint num) 318 { 319 gint n = 1; 320 321 while (n < num) 322 n <<= 1; 323 324 return n; 325 } 326 327 static void 328 g_array_maybe_expand (GRealArray *array, 329 gint len) 330 { 331 guint want_alloc = g_array_elt_len (array, array->len + len + 332 array->zero_terminated); 333 334 if (want_alloc > array->alloc) 335 { 336 want_alloc = g_nearest_pow (want_alloc); 337 want_alloc = MAX (want_alloc, MIN_ARRAY_SIZE); 338 339 array->data = g_realloc (array->data, want_alloc); 340 341 if (G_UNLIKELY (g_mem_gc_friendly)) 342 memset (array->data + array->alloc, 0, want_alloc - array->alloc); 343 344 array->alloc = want_alloc; 345 } 346 } 347 348 /* Pointer Array 349 */ 350 351 typedef struct _GRealPtrArray GRealPtrArray; 352 353 struct _GRealPtrArray 354 { 355 gpointer *pdata; 356 guint len; 357 guint alloc; 358 }; 359 360 static void g_ptr_array_maybe_expand (GRealPtrArray *array, 361 gint len); 362 363 GPtrArray* 364 g_ptr_array_new (void) 365 { 366 return g_ptr_array_sized_new (0); 367 } 368 369 GPtrArray* 370 g_ptr_array_sized_new (guint reserved_size) 371 { 372 GRealPtrArray *array = g_slice_new (GRealPtrArray); 373 374 array->pdata = NULL; 375 array->len = 0; 376 array->alloc = 0; 377 378 if (reserved_size != 0) 379 g_ptr_array_maybe_expand (array, reserved_size); 380 381 return (GPtrArray*) array; 382 } 383 384 gpointer* 385 g_ptr_array_free (GPtrArray *array, 386 gboolean free_segment) 387 { 388 gpointer* segment; 389 390 g_return_val_if_fail (array, NULL); 391 392 if (free_segment) 393 { 394 g_free (array->pdata); 395 segment = NULL; 396 } 397 else 398 segment = array->pdata; 399 400 g_slice_free1 (sizeof (GRealPtrArray), array); 401 402 return segment; 403 } 404 405 static void 406 g_ptr_array_maybe_expand (GRealPtrArray *array, 407 gint len) 408 { 409 if ((array->len + len) > array->alloc) 410 { 411 guint old_alloc = array->alloc; 412 array->alloc = g_nearest_pow (array->len + len); 413 array->alloc = MAX (array->alloc, MIN_ARRAY_SIZE); 414 array->pdata = g_realloc (array->pdata, sizeof (gpointer) * array->alloc); 415 if (G_UNLIKELY (g_mem_gc_friendly)) 416 for ( ; old_alloc < array->alloc; old_alloc++) 417 array->pdata [old_alloc] = NULL; 418 } 419 } 420 421 void 422 g_ptr_array_set_size (GPtrArray *farray, 423 gint length) 424 { 425 GRealPtrArray* array = (GRealPtrArray*) farray; 426 427 g_return_if_fail (array); 428 429 if (length > array->len) 430 { 431 int i; 432 g_ptr_array_maybe_expand (array, (length - array->len)); 433 /* This is not 434 * memset (array->pdata + array->len, 0, 435 * sizeof (gpointer) * (length - array->len)); 436 * to make it really portable. Remember (void*)NULL needn't be 437 * bitwise zero. It of course is silly not to use memset (..,0,..). 438 */ 439 for (i = array->len; i < length; i++) 440 array->pdata[i] = NULL; 441 } 442 if (G_UNLIKELY (g_mem_gc_friendly) && length < array->len) 443 { 444 int i; 445 for (i = length; i < array->len; i++) 446 array->pdata[i] = NULL; 447 } 448 449 array->len = length; 450 } 451 452 gpointer 453 g_ptr_array_remove_index (GPtrArray *farray, 454 guint index_) 455 { 456 GRealPtrArray* array = (GRealPtrArray*) farray; 457 gpointer result; 458 459 g_return_val_if_fail (array, NULL); 460 461 g_return_val_if_fail (index_ < array->len, NULL); 462 463 result = array->pdata[index_]; 464 465 if (index_ != array->len - 1) 466 g_memmove (array->pdata + index_, array->pdata + index_ + 1, 467 sizeof (gpointer) * (array->len - index_ - 1)); 468 469 array->len -= 1; 470 471 if (G_UNLIKELY (g_mem_gc_friendly)) 472 array->pdata[array->len] = NULL; 473 474 return result; 475 } 476 477 gpointer 478 g_ptr_array_remove_index_fast (GPtrArray *farray, 479 guint index_) 480 { 481 GRealPtrArray* array = (GRealPtrArray*) farray; 482 gpointer result; 483 484 g_return_val_if_fail (array, NULL); 485 486 g_return_val_if_fail (index_ < array->len, NULL); 487 488 result = array->pdata[index_]; 489 490 if (index_ != array->len - 1) 491 array->pdata[index_] = array->pdata[array->len - 1]; 492 493 array->len -= 1; 494 495 if (G_UNLIKELY (g_mem_gc_friendly)) 496 array->pdata[array->len] = NULL; 497 498 return result; 499 } 500 501 void 502 g_ptr_array_remove_range (GPtrArray *farray, 503 guint index_, 504 guint length) 505 { 506 GRealPtrArray* array = (GRealPtrArray*) farray; 507 508 g_return_if_fail (array); 509 g_return_if_fail (index_ < array->len); 510 g_return_if_fail (index_ + length <= array->len); 511 512 if (index_ + length != array->len) 513 g_memmove (&array->pdata[index_], 514 &array->pdata[index_ + length], 515 (array->len - (index_ + length)) * sizeof (gpointer)); 516 517 array->len -= length; 518 if (G_UNLIKELY (g_mem_gc_friendly)) 519 { 520 guint i; 521 for (i = 0; i < length; i++) 522 array->pdata[array->len + i] = NULL; 523 } 524 } 525 526 gboolean 527 g_ptr_array_remove (GPtrArray *farray, 528 gpointer data) 529 { 530 GRealPtrArray* array = (GRealPtrArray*) farray; 531 guint i; 532 533 g_return_val_if_fail (array, FALSE); 534 535 for (i = 0; i < array->len; i += 1) 536 { 537 if (array->pdata[i] == data) 538 { 539 g_ptr_array_remove_index (farray, i); 540 return TRUE; 541 } 542 } 543 544 return FALSE; 545 } 546 547 gboolean 548 g_ptr_array_remove_fast (GPtrArray *farray, 549 gpointer data) 550 { 551 GRealPtrArray* array = (GRealPtrArray*) farray; 552 guint i; 553 554 g_return_val_if_fail (array, FALSE); 555 556 for (i = 0; i < array->len; i += 1) 557 { 558 if (array->pdata[i] == data) 559 { 560 g_ptr_array_remove_index_fast (farray, i); 561 return TRUE; 562 } 563 } 564 565 return FALSE; 566 } 567 568 void 569 g_ptr_array_add (GPtrArray *farray, 570 gpointer data) 571 { 572 GRealPtrArray* array = (GRealPtrArray*) farray; 573 574 g_return_if_fail (array); 575 576 g_ptr_array_maybe_expand (array, 1); 577 578 array->pdata[array->len++] = data; 579 } 580 581 void 582 g_ptr_array_sort (GPtrArray *array, 583 GCompareFunc compare_func) 584 { 585 g_return_if_fail (array != NULL); 586 587 qsort (array->pdata, 588 array->len, 589 sizeof (gpointer), 590 compare_func); 591 } 592 593 void 594 g_ptr_array_sort_with_data (GPtrArray *array, 595 GCompareDataFunc compare_func, 596 gpointer user_data) 597 { 598 g_return_if_fail (array != NULL); 599 600 g_qsort_with_data (array->pdata, 601 array->len, 602 sizeof (gpointer), 603 compare_func, 604 user_data); 605 } 606 607 /** 608 * g_ptr_array_foreach: 609 * @array: a #GPtrArray 610 * @func: the function to call for each array element 611 * @user_data: user data to pass to the function 612 * 613 * Calls a function for each element of a #GPtrArray. 614 * 615 * Since: 2.4 616 **/ 617 void 618 g_ptr_array_foreach (GPtrArray *array, 619 GFunc func, 620 gpointer user_data) 621 { 622 guint i; 623 624 g_return_if_fail (array); 625 626 for (i = 0; i < array->len; i++) 627 (*func) (array->pdata[i], user_data); 628 } 629 630 /* Byte arrays 631 */ 632 633 GByteArray* g_byte_array_new (void) 634 { 635 return (GByteArray*) g_array_sized_new (FALSE, FALSE, 1, 0); 636 } 637 638 GByteArray* g_byte_array_sized_new (guint reserved_size) 639 { 640 return (GByteArray*) g_array_sized_new (FALSE, FALSE, 1, reserved_size); 641 } 642 643 guint8* g_byte_array_free (GByteArray *array, 644 gboolean free_segment) 645 { 646 return (guint8*) g_array_free ((GArray*) array, free_segment); 647 } 648 649 GByteArray* g_byte_array_append (GByteArray *array, 650 const guint8 *data, 651 guint len) 652 { 653 g_array_append_vals ((GArray*) array, (guint8*)data, len); 654 655 return array; 656 } 657 658 GByteArray* g_byte_array_prepend (GByteArray *array, 659 const guint8 *data, 660 guint len) 661 { 662 g_array_prepend_vals ((GArray*) array, (guint8*)data, len); 663 664 return array; 665 } 666 667 GByteArray* g_byte_array_set_size (GByteArray *array, 668 guint length) 669 { 670 g_array_set_size ((GArray*) array, length); 671 672 return array; 673 } 674 675 GByteArray* g_byte_array_remove_index (GByteArray *array, 676 guint index_) 677 { 678 g_array_remove_index ((GArray*) array, index_); 679 680 return array; 681 } 682 683 GByteArray* g_byte_array_remove_index_fast (GByteArray *array, 684 guint index_) 685 { 686 g_array_remove_index_fast ((GArray*) array, index_); 687 688 return array; 689 } 690 691 GByteArray* 692 g_byte_array_remove_range (GByteArray *array, 693 guint index_, 694 guint length) 695 { 696 g_return_val_if_fail (array, NULL); 697 g_return_val_if_fail (index_ < array->len, NULL); 698 g_return_val_if_fail (index_ + length <= array->len, NULL); 699 700 return (GByteArray *)g_array_remove_range ((GArray*) array, index_, length); 701 } 702 703 void 704 g_byte_array_sort (GByteArray *array, 705 GCompareFunc compare_func) 706 { 707 g_array_sort ((GArray *) array, compare_func); 708 } 709 710 void 711 g_byte_array_sort_with_data (GByteArray *array, 712 GCompareDataFunc compare_func, 713 gpointer user_data) 714 { 715 g_array_sort_with_data ((GArray *) array, compare_func, user_data); 716 } 717 718 #define __G_ARRAY_C__ 719 #include "galiasdef.c" 720