1 /************************************************************************* 2 * 3 * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER. 4 * 5 * Copyright 2000, 2010 Oracle and/or its affiliates. 6 * 7 * OpenOffice.org - a multi-platform office productivity suite 8 * 9 * This file is part of OpenOffice.org. 10 * 11 * OpenOffice.org is free software: you can redistribute it and/or modify 12 * it under the terms of the GNU Lesser General Public License version 3 13 * only, as published by the Free Software Foundation. 14 * 15 * OpenOffice.org is distributed in the hope that it will be useful, 16 * but WITHOUT ANY WARRANTY; without even the implied warranty of 17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 18 * GNU Lesser General Public License version 3 for more details 19 * (a copy is included in the LICENSE file that accompanied this code). 20 * 21 * You should have received a copy of the GNU Lesser General Public License 22 * version 3 along with OpenOffice.org. If not, see 23 * <http://www.openoffice.org/license.html> 24 * for a copy of the LGPLv3 License. 25 * 26 ************************************************************************/ 27 28 /*[]---------------------------------------------------[]*/ 29 /*| |*/ 30 /*| list.c - bidirectional list class |*/ 31 /*| |*/ 32 /*| |*/ 33 /*| Author: Alexander Gelfenbain |*/ 34 /*[]---------------------------------------------------[]*/ 35 36 #include <rtl/alloc.h> 37 38 #if OSL_DEBUG_LEVEL == 0 39 # ifndef NDEBUG 40 # define NDEBUG 41 # endif 42 #endif 43 44 #include <assert.h> 45 46 /* #define TEST */ 47 #include "list.h" 48 49 /*- private data types */ 50 typedef struct _lnode { 51 struct _lnode *next; 52 struct _lnode *prev; 53 54 void *value; 55 56 } lnode; 57 58 struct _list { 59 lnode *head, *tail, *cptr; 60 size_t aCount; 61 list_destructor eDtor; 62 }; 63 64 /*- private methods */ 65 66 static lnode *newNode(void *el) 67 { 68 lnode *ptr = rtl_allocateMemory(sizeof(lnode)); 69 assert(ptr != 0); 70 71 ptr->value = el; 72 73 return ptr; 74 } 75 76 static lnode *appendPrim(list this, void *el) 77 { 78 lnode *ptr = newNode(el); 79 lnode **flink, *blink; 80 81 if (this->tail != 0) { 82 flink = &(this->tail->next); 83 blink = this->tail; 84 } else { 85 flink = &this->head; 86 blink = 0; 87 this->cptr = ptr; /*- list was empty - set current to this element */ 88 } 89 90 *flink = ptr; 91 this->tail = ptr; 92 93 ptr->prev = blink; 94 ptr->next = 0; 95 96 this->aCount++; 97 return ptr; 98 } 99 #ifdef TEST 100 static lnode *prependPrim(list this, void *el) 101 { 102 lnode *ptr = newNode(el); 103 lnode *flink, **blink; 104 105 if (this->head != 0) { 106 blink = &(this->head->prev); 107 flink = this->head; 108 } else { 109 blink = &this->tail; 110 flink = 0; 111 this->cptr = ptr; /*- list was empty - set current to this element */ 112 } 113 114 *blink = ptr; 115 this->head = ptr; 116 117 ptr->next = flink; 118 ptr->prev = 0; 119 120 this->aCount++; 121 return ptr; 122 } 123 #endif 124 125 /*- public methods */ 126 list listNewEmpty(void) /*- default ctor */ 127 { 128 list this = rtl_allocateMemory(sizeof(struct _list)); 129 assert(this != 0); 130 131 this->aCount = 0; 132 this->eDtor = 0; 133 this->head = this->tail = this->cptr = 0; 134 135 return this; 136 } 137 138 #ifdef TEST 139 list listNewCopy(list l) /*- copy ctor */ 140 { 141 lnode *ptr, *c; 142 list this; 143 assert(l != 0); 144 145 this = rtl_allocateMemory(sizeof(struct _list)); 146 assert(this != 0); 147 148 ptr = l->head; 149 150 this->aCount = 0; 151 this->eDtor = 0; 152 this->head = this->tail = this->cptr = 0; 153 154 while (ptr) { 155 c = appendPrim(this, ptr->value); 156 if (ptr == l->cptr) this->cptr = c; 157 ptr = ptr->next; 158 } 159 160 return this; 161 } 162 #endif 163 164 void listDispose(list this) /*- dtor */ 165 { 166 assert(this != 0); 167 listClear(this); 168 rtl_freeMemory(this); 169 } 170 171 void listSetElementDtor(list this, list_destructor f) 172 { 173 assert(this != 0); 174 this->eDtor = f; 175 } 176 177 /* calling this function on an empty list is a run-time error */ 178 void *listCurrent(list this) 179 { 180 assert(this != 0); 181 assert(this->cptr != 0); 182 return this->cptr->value; 183 } 184 185 int listCount(list this) 186 { 187 assert(this != 0); 188 return this->aCount; 189 } 190 191 int listIsEmpty(list this) 192 { 193 assert(this != 0); 194 return this->aCount == 0; 195 } 196 197 198 #ifdef TEST 199 int listAtFirst(list this) 200 { 201 assert(this != 0); 202 return this->cptr == this->head; 203 } 204 205 int listAtLast(list this) 206 { 207 assert(this != 0); 208 return this->cptr == this->tail; 209 } 210 211 int listPosition(list this) 212 { 213 int res = 0; 214 lnode *ptr; 215 assert(this != 0); 216 217 ptr = this->head; 218 219 while (ptr != this->cptr) { 220 ptr = ptr->next; 221 res++; 222 } 223 224 return res; 225 } 226 #endif 227 int listFind(list this, void *el) 228 { 229 lnode *ptr; 230 assert(this != 0); 231 232 ptr = this->head; 233 234 while (ptr) { 235 if (ptr->value == el) { 236 this->cptr = ptr; 237 return 1; 238 } 239 ptr = ptr->next; 240 } 241 242 return 0; 243 } 244 245 int listNext(list this) 246 { 247 return listSkipForward(this, 1); 248 } 249 250 int listSkipForward(list this, int n) 251 { 252 int m = 0; 253 assert(this != 0); 254 255 if (this->cptr == 0) return 0; 256 257 while (n != 0) { 258 if (this->cptr->next == 0) break; 259 this->cptr = this->cptr->next; 260 n--; 261 m++; 262 } 263 return m; 264 } 265 266 int listToFirst(list this) 267 { 268 assert(this != 0); 269 270 if (this->cptr != this->head) { 271 this->cptr = this->head; 272 return 1; 273 } 274 return 0; 275 } 276 277 int listToLast(list this) 278 { 279 assert(this != 0); 280 281 if (this->cptr != this->tail) { 282 this->cptr = this->tail; 283 return 1; 284 } 285 return 0; 286 } 287 288 int listPositionAt(list this, int n) /*- returns the actual position number */ 289 { 290 int m = 0; 291 assert(this != 0); 292 293 this->cptr = this->head; 294 while (n != 0) { 295 if (this->cptr->next == 0) break; 296 this->cptr = this->cptr->next; 297 n--; 298 m++; 299 } 300 return m; 301 } 302 303 list listAppend(list this, void *el) 304 { 305 assert(this != 0); 306 307 appendPrim(this, el); 308 return this; 309 } 310 #ifdef TEST 311 list listPrepend(list this, void *el) 312 { 313 assert(this != 0); 314 315 prependPrim(this, el); 316 return this; 317 } 318 319 list listInsertAfter(list this, void *el) 320 { 321 lnode *ptr; 322 assert(this != 0); 323 324 if (this->cptr == 0) return listAppend(this, el); 325 326 ptr = newNode(el); 327 328 ptr->prev = this->cptr; 329 ptr->next = this->cptr->next; 330 this->cptr->next = ptr; 331 332 if (ptr->next != 0) { 333 ptr->next->prev = ptr; 334 } else { 335 this->tail = ptr; 336 } 337 this->aCount++; 338 return this; 339 } 340 341 list listInsertBefore(list this, void *el) 342 { 343 lnode *ptr; 344 assert(this != 0); 345 346 if (this->cptr == 0) return listAppend(this, el); 347 348 ptr = newNode(el); 349 350 ptr->prev = this->cptr->prev; 351 ptr->next = this->cptr; 352 this->cptr->prev = ptr; 353 354 if (ptr->prev != 0) { 355 ptr->prev->next = ptr; 356 } else { 357 this->head = ptr; 358 } 359 this->aCount++; 360 return this; 361 } 362 #endif 363 list listRemove(list this) 364 { 365 lnode *ptr = 0; 366 if (this->cptr == 0) return this; 367 368 if (this->cptr->next != 0) { 369 ptr = this->cptr->next; 370 this->cptr->next->prev = this->cptr->prev; 371 } else { 372 this->tail = this->cptr->prev; 373 } 374 375 if (this->cptr->prev != 0) { 376 if (ptr == 0) ptr = this->cptr->prev; 377 this->cptr->prev->next = this->cptr->next; 378 } else { 379 this->head = this->cptr->next; 380 } 381 382 if (this->eDtor) this->eDtor(this->cptr->value); /* call the dtor callback */ 383 384 rtl_freeMemory(this->cptr); 385 this->aCount--; 386 this->cptr = ptr; 387 return this; 388 } 389 390 list listClear(list this) 391 { 392 lnode *node = this->head, *ptr; 393 394 while (node) { 395 ptr = node->next; 396 if (this->eDtor) this->eDtor(node->value); /* call the dtor callback */ 397 rtl_freeMemory(node); 398 this->aCount--; 399 node = ptr; 400 } 401 402 this->head = this->tail = this->cptr = 0; 403 assert(this->aCount == 0); 404 return this; 405 } 406 407 #ifdef TEST 408 409 void listForAll(list this, void (*f)(void *)) 410 { 411 lnode *ptr = this->head; 412 while (ptr) { 413 f(ptr->value); 414 ptr = ptr->next; 415 } 416 } 417 418 419 #include <stdio.h> 420 421 void printlist(list l) 422 { 423 int saved; 424 assert(l != 0); 425 saved = listPosition(l); 426 427 printf("[ "); 428 429 if (!listIsEmpty(l)) { 430 listToFirst(l); 431 do { 432 printf("%d ", (int) listCurrent(l)); 433 } while (listNext(l)); 434 } 435 436 printf("]\n"); 437 438 listPositionAt(l, saved); 439 } 440 441 void printstringlist(list l) 442 { 443 int saved; 444 assert(l != 0); 445 saved = listPosition(l); 446 447 printf("[ "); 448 449 if (!listIsEmpty(l)) { 450 listToFirst(l); 451 do { 452 printf("'%s' ", (char *) listCurrent(l)); 453 } while (listNext(l)); 454 } 455 456 printf("]\n"); 457 458 listPositionAt(l, saved); 459 } 460 461 void printstat(list l) 462 { 463 printf("count: %d, position: %d, isEmpty: %d, atFirst: %d, atLast: %d.\n", 464 listCount(l), listPosition(l), listIsEmpty(l), listAtFirst(l), listAtLast(l)); 465 } 466 467 void allfunc(void *e) 468 { 469 printf("%d ", e); 470 } 471 472 void edtor(void *ptr) 473 { 474 printf("element dtor: 0x%08x\n", ptr); 475 rtl_freeMemory(ptr); 476 } 477 478 int main() 479 { 480 list l1, l2; 481 char *ptr; 482 int i; 483 484 l1 = listNewEmpty(); 485 printstat(l1); 486 487 listAppend(l1, 1); 488 printstat(l1); 489 490 listAppend(l1, 2); 491 printstat(l1); 492 493 listAppend(l1, 3); 494 printstat(l1); 495 496 printlist(l1); 497 498 listToFirst(l1); 499 listInsertBefore(l1, -5); 500 printlist(l1); 501 502 l2 = listNewCopy(l1); 503 printlist(l2); 504 505 listForAll(l2, allfunc); 506 printf("\n"); 507 508 listClear(l1); 509 listSetElementDtor(l1, edtor); 510 511 for(i=0; i<10; i++) { 512 ptr = rtl_allocateMemory(20); 513 snprintf(ptr, 20, "element # %d", i); 514 listAppend(l1, ptr); 515 } 516 517 printstringlist(l1); 518 519 520 listDispose(l1); 521 listDispose(l2); 522 523 524 return 0; 525 } 526 #endif 527 528 529