blob: fc67c70c986dd4fa84a25f145644a0bd5443826f [file] [log] [blame]
cristy3ed852e2009-09-05 21:47:34 +00001/*
2%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
3% %
4% %
5% %
6% H H AAA SSSSS H H M M AAA PPPP %
7% H H A A SS H H MM MM A A P P %
8% HHHHH AAAAA SSS HHHHH M M M AAAAA PPPP %
9% H H A A SS H H M M A A P %
10% H H A A SSSSS H H M M A A P %
11% %
12% %
13% MagickCore Hash-map and Linked-list Methods %
14% %
15% Software Design %
16% John Cristy %
17% December 2002 %
18% %
19% %
cristy7e41fe82010-12-04 23:12:08 +000020% Copyright 1999-2011 ImageMagick Studio LLC, a non-profit organization %
cristy3ed852e2009-09-05 21:47:34 +000021% dedicated to making software imaging solutions freely available. %
22% %
23% You may not use this file except in compliance with the License. You may %
24% obtain a copy of the License at %
25% %
26% http://www.imagemagick.org/script/license.php %
27% %
28% Unless required by applicable law or agreed to in writing, software %
29% distributed under the License is distributed on an "AS IS" BASIS, %
30% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. %
31% See the License for the specific language governing permissions and %
32% limitations under the License. %
33% %
34%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
35%
36% This module implements the standard handy hash and linked-list methods for
37% storing and retrieving large numbers of data elements. It is loosely based
38% on the Java implementation of these algorithms.
39%
40*/
41
42/*
43 Include declarations.
44*/
45#include "magick/studio.h"
46#include "magick/exception.h"
47#include "magick/exception-private.h"
48#include "magick/hashmap.h"
49#include "magick/memory_.h"
50#include "magick/semaphore.h"
51#include "magick/signature-private.h"
52#include "magick/string_.h"
53
54/*
55 Typedef declarations.
56*/
57typedef struct _ElementInfo
58{
59 void
60 *value;
61
62 struct _ElementInfo
63 *next;
64} ElementInfo;
65
66typedef struct _EntryInfo
67{
68 size_t
69 hash;
70
71 void
72 *key,
73 *value;
74} EntryInfo;
75
76struct _LinkedListInfo
77{
cristybb503372010-05-27 20:51:26 +000078 size_t
cristy3ed852e2009-09-05 21:47:34 +000079 capacity,
80 elements;
81
82 ElementInfo
83 *head,
84 *tail,
85 *next;
86
87 MagickBooleanType
88 debug;
89
90 SemaphoreInfo
91 *semaphore;
92
cristybb503372010-05-27 20:51:26 +000093 size_t
cristy3ed852e2009-09-05 21:47:34 +000094 signature;
95};
96
97struct _HashmapInfo
98{
99 size_t
100 (*hash)(const void *);
101
102 MagickBooleanType
103 (*compare)(const void *,const void *);
104
105 void
106 *(*relinquish_key)(void *),
107 *(*relinquish_value)(void *);
108
cristybb503372010-05-27 20:51:26 +0000109 size_t
cristy3ed852e2009-09-05 21:47:34 +0000110 capacity,
111 entries,
112 next;
113
114 MagickBooleanType
115 head_of_list;
116
117 LinkedListInfo
118 **map;
119
120 MagickBooleanType
121 debug;
122
123 SemaphoreInfo
124 *semaphore;
125
cristybb503372010-05-27 20:51:26 +0000126 size_t
cristy3ed852e2009-09-05 21:47:34 +0000127 signature;
128};
129
130/*
131%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
132% %
133% %
134% %
135% A p p e n d V a l u e T o L i n k e d L i s t %
136% %
137% %
138% %
139%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
140%
141% AppendValueToLinkedList() appends a value to the end of the linked-list.
142%
143% The format of the AppendValueToLinkedList method is:
144%
145% MagickBooleanType AppendValueToLinkedList(LinkedListInfo *list_info,
146% const void *value)
147%
148% A description of each parameter follows:
149%
150% o list_info: the linked-list info.
151%
152% o value: the value.
153%
154*/
155MagickExport MagickBooleanType AppendValueToLinkedList(
156 LinkedListInfo *list_info,const void *value)
157{
158 register ElementInfo
159 *next;
160
161 assert(list_info != (LinkedListInfo *) NULL);
162 assert(list_info->signature == MagickSignature);
163 list_info->debug=IsEventLogging();
164 if (list_info->debug != MagickFalse)
165 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
166 if (list_info->elements == list_info->capacity)
167 return(MagickFalse);
cristy73bd4a52010-10-05 11:24:23 +0000168 next=(ElementInfo *) AcquireMagickMemory(sizeof(*next));
cristy3ed852e2009-09-05 21:47:34 +0000169 if (next == (ElementInfo *) NULL)
170 return(MagickFalse);
171 next->value=(void *) value;
172 next->next=(ElementInfo *) NULL;
cristyf84a1932010-01-03 18:00:18 +0000173 LockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000174 if (list_info->next == (ElementInfo *) NULL)
175 list_info->next=next;
176 if (list_info->elements == 0)
177 list_info->head=next;
178 else
179 list_info->tail->next=next;
180 list_info->tail=next;
181 list_info->elements++;
cristyf84a1932010-01-03 18:00:18 +0000182 UnlockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000183 return(MagickTrue);
184}
185
186/*
187%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
188% %
189% %
190% %
191% C l e a r L i n k e d L i s t %
192% %
193% %
194% %
195%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
196%
197% ClearLinkedList() clears all the elements from the linked-list.
198%
199% The format of the ClearLinkedList method is:
200%
201% void ClearLinkedList(LinkedListInfo *list_info,
202% void *(*relinquish_value)(void *))
203%
204% A description of each parameter follows:
205%
206% o list_info: the linked-list info.
207%
208% o relinquish_value: the value deallocation method; typically
209% RelinquishMagickMemory().
210%
211*/
212MagickExport void ClearLinkedList(LinkedListInfo *list_info,
213 void *(*relinquish_value)(void *))
214{
215 ElementInfo
216 *element;
217
218 register ElementInfo
219 *next;
220
221 assert(list_info != (LinkedListInfo *) NULL);
222 assert(list_info->signature == MagickSignature);
223 if (list_info->debug != MagickFalse)
224 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristyf84a1932010-01-03 18:00:18 +0000225 LockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000226 next=list_info->head;
227 while (next != (ElementInfo *) NULL)
228 {
229 if (relinquish_value != (void *(*)(void *)) NULL)
230 next->value=relinquish_value(next->value);
231 element=next;
232 next=next->next;
233 element=(ElementInfo *) RelinquishMagickMemory(element);
234 }
235 list_info->head=(ElementInfo *) NULL;
236 list_info->tail=(ElementInfo *) NULL;
237 list_info->next=(ElementInfo *) NULL;
238 list_info->elements=0;
cristyf84a1932010-01-03 18:00:18 +0000239 UnlockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000240}
241
242/*
243%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
244% %
245% %
246% %
247% C o m p a r e H a s h m a p S t r i n g %
248% %
249% %
250% %
251%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
252%
cristy7a40ba82011-01-08 20:31:18 +0000253% CompareHashmapString() finds an entry in a hash-map based on the contents
254% of a string.
cristy3ed852e2009-09-05 21:47:34 +0000255%
256% The format of the CompareHashmapString method is:
257%
258% MagickBooleanType CompareHashmapString(const void *target,
259% const void *source)
260%
261% A description of each parameter follows:
262%
263% o target: the target string.
264%
265% o source: the source string.
266%
267*/
268MagickExport MagickBooleanType CompareHashmapString(const void *target,
269 const void *source)
270{
271 const char
272 *p,
273 *q;
274
275 p=(const char *) target;
276 q=(const char *) source;
277 return(LocaleCompare(p,q) == 0 ? MagickTrue : MagickFalse);
278}
279
280/*
281%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
282% %
283% %
284% %
285% C o m p a r e H a s h m a p S t r i n g I n f o %
286% %
287% %
288% %
289%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
290%
cristy7a40ba82011-01-08 20:31:18 +0000291% CompareHashmapStringInfo() finds an entry in a hash-map based on the
292% contents of a string.
cristy3ed852e2009-09-05 21:47:34 +0000293%
294% The format of the CompareHashmapStringInfo method is:
295%
296% MagickBooleanType CompareHashmapStringInfo(const void *target,
297% const void *source)
298%
299% A description of each parameter follows:
300%
301% o target: the target string.
302%
303% o source: the source string.
304%
305*/
306MagickExport MagickBooleanType CompareHashmapStringInfo(const void *target,
307 const void *source)
308{
309 const StringInfo
310 *p,
311 *q;
312
313 p=(const StringInfo *) target;
314 q=(const StringInfo *) source;
315 return(CompareStringInfo(p,q) == 0 ? MagickTrue : MagickFalse);
316}
317
318/*
319%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
320% %
321% %
322% %
323% D e s t r o y H a s h m a p %
324% %
325% %
326% %
327%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
328%
329% DestroyHashmap() frees the hash-map and all associated resources.
330%
331% The format of the DestroyHashmap method is:
332%
333% HashmapInfo *DestroyHashmap(HashmapInfo *hashmap_info)
334%
335% A description of each parameter follows:
336%
337% o hashmap_info: the hashmap info.
338%
339*/
340MagickExport HashmapInfo *DestroyHashmap(HashmapInfo *hashmap_info)
341{
342 LinkedListInfo
343 *list_info;
344
345 register EntryInfo
346 *entry;
347
cristybb503372010-05-27 20:51:26 +0000348 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000349 i;
350
351 assert(hashmap_info != (HashmapInfo *) NULL);
352 assert(hashmap_info->signature == MagickSignature);
353 if (hashmap_info->debug != MagickFalse)
354 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristyf84a1932010-01-03 18:00:18 +0000355 LockSemaphoreInfo(hashmap_info->semaphore);
cristybb503372010-05-27 20:51:26 +0000356 for (i=0; i < (ssize_t) hashmap_info->capacity; i++)
cristy3ed852e2009-09-05 21:47:34 +0000357 {
358 list_info=hashmap_info->map[i];
359 if (list_info != (LinkedListInfo *) NULL)
360 {
361 list_info->next=list_info->head;
362 entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
363 while (entry != (EntryInfo *) NULL)
364 {
365 if (hashmap_info->relinquish_key != (void *(*)(void *)) NULL)
366 entry->key=hashmap_info->relinquish_key(entry->key);
367 if (hashmap_info->relinquish_value != (void *(*)(void *)) NULL)
368 entry->value=hashmap_info->relinquish_value(entry->value);
369 entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
370 }
371 }
372 if (list_info != (LinkedListInfo *) NULL)
373 list_info=DestroyLinkedList(list_info,RelinquishMagickMemory);
374 }
375 hashmap_info->map=(LinkedListInfo **) RelinquishMagickMemory(
376 hashmap_info->map);
377 hashmap_info->signature=(~MagickSignature);
cristyf84a1932010-01-03 18:00:18 +0000378 UnlockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000379 DestroySemaphoreInfo(&hashmap_info->semaphore);
380 hashmap_info=(HashmapInfo *) RelinquishMagickMemory(hashmap_info);
381 return(hashmap_info);
382}
383
384/*
385%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
386% %
387% %
388% %
389% D e s t r o y L i n k e d L i s t %
390% %
391% %
392% %
393%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
394%
395% DestroyLinkedList() frees the linked-list and all associated resources.
396%
397% The format of the DestroyLinkedList method is:
398%
399% LinkedListInfo *DestroyLinkedList(LinkedListInfo *list_info,
400% void *(*relinquish_value)(void *))
401%
402% A description of each parameter follows:
403%
404% o list_info: the linked-list info.
405%
406% o relinquish_value: the value deallocation method; typically
407% RelinquishMagickMemory().
408%
409*/
410MagickExport LinkedListInfo *DestroyLinkedList(LinkedListInfo *list_info,
411 void *(*relinquish_value)(void *))
412{
413 ElementInfo
414 *entry;
415
416 register ElementInfo
417 *next;
418
419 assert(list_info != (LinkedListInfo *) NULL);
420 assert(list_info->signature == MagickSignature);
421 if (list_info->debug != MagickFalse)
422 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristyf84a1932010-01-03 18:00:18 +0000423 LockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000424 for (next=list_info->head; next != (ElementInfo *) NULL; )
425 {
426 if (relinquish_value != (void *(*)(void *)) NULL)
427 next->value=relinquish_value(next->value);
428 entry=next;
429 next=next->next;
430 entry=(ElementInfo *) RelinquishMagickMemory(entry);
431 }
432 list_info->signature=(~MagickSignature);
cristyf84a1932010-01-03 18:00:18 +0000433 UnlockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000434 DestroySemaphoreInfo(&list_info->semaphore);
435 list_info=(LinkedListInfo *) RelinquishMagickMemory(list_info);
436 return(list_info);
437}
438
439/*
440%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
441% %
442% %
443% %
444% G e t L a s t V a l u e I n L i n k e d L i s t %
445% %
446% %
447% %
448%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
449%
450% GetLastValueInLinkedList() gets the last value in the linked-list.
451%
452% The format of the GetLastValueInLinkedList method is:
453%
454% void *GetLastValueInLinkedList(LinkedListInfo *list_info)
455%
456% A description of each parameter follows:
457%
458% o list_info: the linked_list info.
459%
460*/
461MagickExport void *GetLastValueInLinkedList(LinkedListInfo *list_info)
462{
463 void
464 *value;
465
466 assert(list_info != (LinkedListInfo *) NULL);
467 assert(list_info->signature == MagickSignature);
468 if (list_info->debug != MagickFalse)
469 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
470 if (list_info->elements == 0)
471 return((void *) NULL);
cristyf84a1932010-01-03 18:00:18 +0000472 LockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000473 value=list_info->tail->value;
cristyf84a1932010-01-03 18:00:18 +0000474 UnlockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000475 return(value);
476}
477
478/*
479%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
480% %
481% %
482% %
483% G e t N e x t K e y I n H a s h m a p %
484% %
485% %
486% %
487%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
488%
489% GetNextKeyInHashmap() gets the next key in the hash-map.
490%
491% The format of the GetNextKeyInHashmap method is:
492%
493% void *GetNextKeyInHashmap(HashmapInfo *hashmap_info)
494%
495% A description of each parameter follows:
496%
497% o hashmap_info: the hashmap info.
498%
499*/
500MagickExport void *GetNextKeyInHashmap(HashmapInfo *hashmap_info)
501{
502 LinkedListInfo
503 *list_info;
504
505 register EntryInfo
506 *entry;
507
508 void
509 *key;
510
511 assert(hashmap_info != (HashmapInfo *) NULL);
512 assert(hashmap_info->signature == MagickSignature);
513 if (hashmap_info->debug != MagickFalse)
514 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristyf84a1932010-01-03 18:00:18 +0000515 LockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000516 while (hashmap_info->next < hashmap_info->capacity)
517 {
518 list_info=hashmap_info->map[hashmap_info->next];
519 if (list_info != (LinkedListInfo *) NULL)
520 {
521 if (hashmap_info->head_of_list == MagickFalse)
522 {
523 list_info->next=list_info->head;
524 hashmap_info->head_of_list=MagickTrue;
525 }
526 entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
527 if (entry != (EntryInfo *) NULL)
528 {
529 key=entry->key;
cristyf84a1932010-01-03 18:00:18 +0000530 UnlockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000531 return(key);
532 }
533 hashmap_info->head_of_list=MagickFalse;
534 }
535 hashmap_info->next++;
536 }
cristyf84a1932010-01-03 18:00:18 +0000537 UnlockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000538 return((void *) NULL);
539}
540
541/*
542%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
543% %
544% %
545% %
546% G e t N e x t V a l u e I n H a s h m a p %
547% %
548% %
549% %
550%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
551%
552% GetNextValueInHashmap() gets the next value in the hash-map.
553%
554% The format of the GetNextValueInHashmap method is:
555%
556% void *GetNextValueInHashmap(HashmapInfo *hashmap_info)
557%
558% A description of each parameter follows:
559%
560% o hashmap_info: the hashmap info.
561%
562*/
563MagickExport void *GetNextValueInHashmap(HashmapInfo *hashmap_info)
564{
565 LinkedListInfo
566 *list_info;
567
568 register EntryInfo
569 *entry;
570
571 void
572 *value;
573
574 assert(hashmap_info != (HashmapInfo *) NULL);
575 assert(hashmap_info->signature == MagickSignature);
576 if (hashmap_info->debug != MagickFalse)
577 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristyf84a1932010-01-03 18:00:18 +0000578 LockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000579 while (hashmap_info->next < hashmap_info->capacity)
580 {
581 list_info=hashmap_info->map[hashmap_info->next];
582 if (list_info != (LinkedListInfo *) NULL)
583 {
584 if (hashmap_info->head_of_list == MagickFalse)
585 {
586 list_info->next=list_info->head;
587 hashmap_info->head_of_list=MagickTrue;
588 }
589 entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
590 if (entry != (EntryInfo *) NULL)
591 {
592 value=entry->value;
cristyf84a1932010-01-03 18:00:18 +0000593 UnlockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000594 return(value);
595 }
596 hashmap_info->head_of_list=MagickFalse;
597 }
598 hashmap_info->next++;
599 }
cristyf84a1932010-01-03 18:00:18 +0000600 UnlockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000601 return((void *) NULL);
602}
603
604/*
605%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
606% %
607% %
608% %
609% G e t N e x t V a l u e I n L i n k e d L i s t %
610% %
611% %
612% %
613%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
614%
615% GetNextValueInLinkedList() gets the next value in the linked-list.
616%
617% The format of the GetNextValueInLinkedList method is:
618%
619% void *GetNextValueInLinkedList(LinkedListInfo *list_info)
620%
621% A description of each parameter follows:
622%
623% o list_info: the linked-list info.
624%
625*/
626MagickExport void *GetNextValueInLinkedList(LinkedListInfo *list_info)
627{
628 void
629 *value;
630
631 assert(list_info != (LinkedListInfo *) NULL);
632 assert(list_info->signature == MagickSignature);
633 if (list_info->debug != MagickFalse)
634 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristyf84a1932010-01-03 18:00:18 +0000635 LockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000636 if (list_info->next == (ElementInfo *) NULL)
637 {
cristyf84a1932010-01-03 18:00:18 +0000638 UnlockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000639 return((void *) NULL);
640 }
641 value=list_info->next->value;
642 list_info->next=list_info->next->next;
cristyf84a1932010-01-03 18:00:18 +0000643 UnlockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000644 return(value);
645}
646
647/*
648%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
649% %
650% %
651% %
652% G e t N u m b e r O f E n t r i e s I n H a s h m a p %
653% %
654% %
655% %
656%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
657%
658% GetNumberOfEntriesInHashmap() returns the number of entries in the hash-map.
659%
660% The format of the GetNumberOfEntriesInHashmap method is:
661%
cristybb503372010-05-27 20:51:26 +0000662% size_t GetNumberOfEntriesInHashmap(const HashmapInfo *hashmap_info)
cristy3ed852e2009-09-05 21:47:34 +0000663%
664% A description of each parameter follows:
665%
666% o hashmap_info: the hashmap info.
667%
668*/
cristybb503372010-05-27 20:51:26 +0000669MagickExport size_t GetNumberOfEntriesInHashmap(
cristy3ed852e2009-09-05 21:47:34 +0000670 const HashmapInfo *hashmap_info)
671{
672 assert(hashmap_info != (HashmapInfo *) NULL);
673 assert(hashmap_info->signature == MagickSignature);
674 if (hashmap_info->debug != MagickFalse)
675 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
676 return(hashmap_info->entries);
677}
678
679/*
680%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
681% %
682% %
683% %
684% G e t N u m b e r O f E l e m e n t s I n L i n k e d L i s t %
685% %
686% %
687% %
688%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
689%
690% GetNumberOfElementsInLinkedList() returns the number of entries in the
691% linked-list.
692%
693% The format of the GetNumberOfElementsInLinkedList method is:
694%
cristybb503372010-05-27 20:51:26 +0000695% size_t GetNumberOfElementsInLinkedList(
cristy3ed852e2009-09-05 21:47:34 +0000696% const LinkedListInfo *list_info)
697%
698% A description of each parameter follows:
699%
700% o list_info: the linked-list info.
701%
702*/
cristybb503372010-05-27 20:51:26 +0000703MagickExport size_t GetNumberOfElementsInLinkedList(
cristy3ed852e2009-09-05 21:47:34 +0000704 const LinkedListInfo *list_info)
705{
706 assert(list_info != (LinkedListInfo *) NULL);
707 assert(list_info->signature == MagickSignature);
708 if (list_info->debug != MagickFalse)
709 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
710 return(list_info->elements);
711}
712
713/*
714%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
715% %
716% %
717% %
718% G e t V a l u e F r o m H a s h m a p %
719% %
720% %
721% %
722%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
723%
724% GetValueFromHashmap() gets an entry from the hash-map by its key.
725%
726% The format of the GetValueFromHashmap method is:
727%
728% void *GetValueFromHashmap(HashmapInfo *hashmap_info,const void *key)
729%
730% A description of each parameter follows:
731%
732% o hashmap_info: the hashmap info.
733%
734% o key: the key.
735%
736*/
737MagickExport void *GetValueFromHashmap(HashmapInfo *hashmap_info,
738 const void *key)
739{
740 LinkedListInfo
741 *list_info;
742
743 register EntryInfo
744 *entry;
745
746 size_t
747 hash;
748
749 void
750 *value;
751
752 assert(hashmap_info != (HashmapInfo *) NULL);
753 assert(hashmap_info->signature == MagickSignature);
754 if (hashmap_info->debug != MagickFalse)
755 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
756 if (key == (const void *) NULL)
757 return((void *) NULL);
cristyf84a1932010-01-03 18:00:18 +0000758 LockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000759 hash=hashmap_info->hash(key);
760 list_info=hashmap_info->map[hash % hashmap_info->capacity];
761 if (list_info != (LinkedListInfo *) NULL)
762 {
763 list_info->next=list_info->head;
764 entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
765 while (entry != (EntryInfo *) NULL)
766 {
767 if (entry->hash == hash)
768 {
769 MagickBooleanType
770 compare;
771
772 compare=MagickTrue;
773 if (hashmap_info->compare !=
774 (MagickBooleanType (*)(const void *,const void *)) NULL)
775 compare=hashmap_info->compare(key,entry->key);
776 if (compare == MagickTrue)
777 {
778 value=entry->value;
cristyf84a1932010-01-03 18:00:18 +0000779 UnlockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000780 return(value);
781 }
782 }
783 entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
784 }
785 }
cristyf84a1932010-01-03 18:00:18 +0000786 UnlockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000787 return((void *) NULL);
788}
789
790/*
791%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
792% %
793% %
794% %
795% G e t V a l u e F r o m L i n k e d L i s t %
796% %
797% %
798% %
799%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
800%
801% GetValueFromLinkedList() gets a value from the linked-list at the specified
802% location.
803%
804% The format of the GetValueFromLinkedList method is:
805%
806% void *GetValueFromLinkedList(LinkedListInfo *list_info,
cristybb503372010-05-27 20:51:26 +0000807% const size_t index)
cristy3ed852e2009-09-05 21:47:34 +0000808%
809% A description of each parameter follows:
810%
811% o list_info: the linked_list info.
812%
813% o index: the list index.
814%
815*/
816MagickExport void *GetValueFromLinkedList(LinkedListInfo *list_info,
cristybb503372010-05-27 20:51:26 +0000817 const size_t index)
cristy3ed852e2009-09-05 21:47:34 +0000818{
819 register ElementInfo
820 *next;
821
cristybb503372010-05-27 20:51:26 +0000822 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000823 i;
824
825 void
826 *value;
827
828 assert(list_info != (LinkedListInfo *) NULL);
829 assert(list_info->signature == MagickSignature);
830 if (list_info->debug != MagickFalse)
831 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
832 if (index >= list_info->elements)
833 return((void *) NULL);
cristyf84a1932010-01-03 18:00:18 +0000834 LockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000835 if (index == 0)
836 {
837 value=list_info->head->value;
cristyf84a1932010-01-03 18:00:18 +0000838 UnlockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000839 return(value);
840 }
841 if (index == (list_info->elements-1))
842 {
843 value=list_info->tail->value;
cristyf84a1932010-01-03 18:00:18 +0000844 UnlockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000845 return(value);
846 }
847 next=list_info->head;
cristybb503372010-05-27 20:51:26 +0000848 for (i=0; i < (ssize_t) index; i++)
cristy3ed852e2009-09-05 21:47:34 +0000849 next=next->next;
850 value=next->value;
cristyf84a1932010-01-03 18:00:18 +0000851 UnlockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +0000852 return(value);
853}
854
855/*
856%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
857% %
858% %
859% %
860% H a s h P o i n t e r T y p e %
861% %
862% %
863% %
864%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
865%
cristy7a40ba82011-01-08 20:31:18 +0000866% HashPointerType() finds an entry in a hash-map based on the address of a
867% pointer.
cristy3ed852e2009-09-05 21:47:34 +0000868%
869% The format of the HashPointerType method is:
870%
871% size_t HashPointerType(const void *pointer)
872%
873% A description of each parameter follows:
874%
875% o pointer: compute the hash entry location from this pointer address.
876%
877*/
878MagickExport size_t HashPointerType(const void *pointer)
879{
880 size_t
881 hash;
882
883 hash=(size_t) pointer;
884 hash+=(~(hash << 9));
885 hash^=(hash >> 14);
886 hash+=(hash << 4);
887 hash^=(hash >> 10);
888 return(hash);
889}
890
891/*
892%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
893% %
894% %
895% %
896% H a s h S t r i n g T y p e %
897% %
898% %
899% %
900%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
901%
cristy7a40ba82011-01-08 20:31:18 +0000902% HashStringType() finds an entry in a hash-map based on the contents of a
903% string.
cristy3ed852e2009-09-05 21:47:34 +0000904%
905% The format of the HashStringType method is:
906%
907% size_t HashStringType(const void *string)
908%
909% A description of each parameter follows:
910%
911% o string: compute the hash entry location from this string.
912%
913*/
914MagickExport size_t HashStringType(const void *string)
915{
916 const unsigned char
917 *digest;
918
cristybb503372010-05-27 20:51:26 +0000919 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000920 i;
921
922 SignatureInfo
923 *signature_info;
924
925 size_t
926 hash;
927
928 StringInfo
929 *signature;
930
931 signature_info=AcquireSignatureInfo();
932 signature=StringToStringInfo((const char *) string);
933 UpdateSignature(signature_info,signature);
934 FinalizeSignature(signature_info);
935 digest=GetStringInfoDatum(GetSignatureDigest(signature_info));
936 hash=0;
937 for (i=0; i < 8; i++)
938 hash^=digest[i];
939 signature=DestroyStringInfo(signature);
940 signature_info=DestroySignatureInfo(signature_info);
941 return(hash);
942}
943
944/*
945%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
946% %
947% %
948% %
949% H a s h S t r i n g I n f o T y p e %
950% %
951% %
952% %
953%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
954%
955% Specify the HashStringInfoType() method in NewHashmap() to find an entry
956% in a hash-map based on the contents of a string.
957%
958% The format of the HashStringInfoType method is:
959%
960% size_t HashStringInfoType(const void *string_info)
961%
962% A description of each parameter follows:
963%
964% o string_info: compute the hash entry location from this string.
965%
966*/
967MagickExport size_t HashStringInfoType(const void *string_info)
968{
969 const unsigned char
970 *digest;
971
cristybb503372010-05-27 20:51:26 +0000972 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +0000973 i;
974
975 SignatureInfo
976 *signature_info;
977
978 size_t
979 hash;
980
981 signature_info=AcquireSignatureInfo();
982 UpdateSignature(signature_info,(const StringInfo *) string_info);
983 FinalizeSignature(signature_info);
984 digest=GetStringInfoDatum(GetSignatureDigest(signature_info));
985 hash=0;
986 for (i=0; i < 8; i++)
987 hash^=digest[i];
988 signature_info=DestroySignatureInfo(signature_info);
989 return(hash);
990}
991
992/*
993%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
994% %
995% %
996% %
997% I n s e r t V a l u e I n L i n k e d L i s t %
998% %
999% %
1000% %
1001%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1002%
1003% InsertValueInLinkedList() inserts an element in the linked-list at the
1004% specified location.
1005%
1006% The format of the InsertValueInLinkedList method is:
1007%
1008% MagickBooleanType InsertValueInLinkedList(ListInfo *list_info,
cristybb503372010-05-27 20:51:26 +00001009% const size_t index,const void *value)
cristy3ed852e2009-09-05 21:47:34 +00001010%
1011% A description of each parameter follows:
1012%
1013% o list_info: the hashmap info.
1014%
1015% o index: the index.
1016%
1017% o value: the value.
1018%
1019*/
1020MagickExport MagickBooleanType InsertValueInLinkedList(
cristybb503372010-05-27 20:51:26 +00001021 LinkedListInfo *list_info,const size_t index,const void *value)
cristy3ed852e2009-09-05 21:47:34 +00001022{
1023 register ElementInfo
1024 *next;
1025
cristybb503372010-05-27 20:51:26 +00001026 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001027 i;
1028
1029 assert(list_info != (LinkedListInfo *) NULL);
1030 assert(list_info->signature == MagickSignature);
1031 if (list_info->debug != MagickFalse)
1032 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1033 if (value == (const void *) NULL)
1034 return(MagickFalse);
1035 if ((index > list_info->elements) ||
1036 (list_info->elements == list_info->capacity))
1037 return(MagickFalse);
cristy73bd4a52010-10-05 11:24:23 +00001038 next=(ElementInfo *) AcquireMagickMemory(sizeof(*next));
cristy3ed852e2009-09-05 21:47:34 +00001039 if (next == (ElementInfo *) NULL)
1040 return(MagickFalse);
1041 next->value=(void *) value;
1042 next->next=(ElementInfo *) NULL;
cristyf84a1932010-01-03 18:00:18 +00001043 LockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001044 if (list_info->elements == 0)
1045 {
1046 if (list_info->next == (ElementInfo *) NULL)
1047 list_info->next=next;
1048 list_info->head=next;
1049 list_info->tail=next;
1050 }
1051 else
1052 {
1053 if (index == 0)
1054 {
1055 if (list_info->next == list_info->head)
1056 list_info->next=next;
1057 next->next=list_info->head;
1058 list_info->head=next;
1059 }
1060 else
1061 if (index == list_info->elements)
1062 {
1063 if (list_info->next == (ElementInfo *) NULL)
1064 list_info->next=next;
1065 list_info->tail->next=next;
1066 list_info->tail=next;
1067 }
1068 else
1069 {
1070 ElementInfo
1071 *element;
1072
1073 element=list_info->head;
1074 next->next=element->next;
cristybb503372010-05-27 20:51:26 +00001075 for (i=1; i < (ssize_t) index; i++)
cristy3ed852e2009-09-05 21:47:34 +00001076 {
1077 element=element->next;
1078 next->next=element->next;
1079 }
1080 next=next->next;
1081 element->next=next;
1082 if (list_info->next == next->next)
1083 list_info->next=next;
1084 }
1085 }
1086 list_info->elements++;
cristyf84a1932010-01-03 18:00:18 +00001087 UnlockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001088 return(MagickTrue);
1089}
1090
1091/*
1092%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1093% %
1094% %
1095% %
1096% I n s e r t V a l u e I n S o r t e d L i n k e d L i s t %
1097% %
1098% %
1099% %
1100%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1101%
1102% InsertValueInSortedLinkedList() inserts a value in the sorted linked-list.
1103%
1104% The format of the InsertValueInSortedLinkedList method is:
1105%
1106% MagickBooleanType InsertValueInSortedLinkedList(ListInfo *list_info,
1107% int (*compare)(const void *,const void *),void **replace,
1108% const void *value)
1109%
1110% A description of each parameter follows:
1111%
1112% o list_info: the hashmap info.
1113%
1114% o index: the index.
1115%
1116% o compare: the compare method.
1117%
1118% o replace: return previous element here.
1119%
1120% o value: the value.
1121%
1122*/
1123MagickExport MagickBooleanType InsertValueInSortedLinkedList(
1124 LinkedListInfo *list_info,int (*compare)(const void *,const void *),
1125 void **replace,const void *value)
1126{
1127 ElementInfo
1128 *element;
1129
1130 register ElementInfo
1131 *next;
1132
cristybb503372010-05-27 20:51:26 +00001133 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001134 i;
1135
1136 assert(list_info != (LinkedListInfo *) NULL);
1137 assert(list_info->signature == MagickSignature);
1138 if (list_info->debug != MagickFalse)
1139 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1140 if ((compare == (int (*)(const void *,const void *)) NULL) ||
1141 (value == (const void *) NULL))
1142 return(MagickFalse);
1143 if (list_info->elements == list_info->capacity)
1144 return(MagickFalse);
cristy73bd4a52010-10-05 11:24:23 +00001145 next=(ElementInfo *) AcquireMagickMemory(sizeof(*next));
cristy3ed852e2009-09-05 21:47:34 +00001146 if (next == (ElementInfo *) NULL)
1147 return(MagickFalse);
1148 next->value=(void *) value;
1149 element=(ElementInfo *) NULL;
cristyf84a1932010-01-03 18:00:18 +00001150 LockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001151 next->next=list_info->head;
1152 while (next->next != (ElementInfo *) NULL)
1153 {
cristycee97112010-05-28 00:44:52 +00001154 i=(ssize_t) compare(value,next->next->value);
cristy3ed852e2009-09-05 21:47:34 +00001155 if ((i < 0) || ((replace != (void **) NULL) && (i == 0)))
1156 {
1157 if (i == 0)
1158 {
1159 *replace=next->next->value;
1160 next->next=next->next->next;
1161 if (element != (ElementInfo *) NULL)
1162 element->next=(ElementInfo *) RelinquishMagickMemory(
1163 element->next);
1164 list_info->elements--;
1165 }
1166 if (element != (ElementInfo *) NULL)
1167 element->next=next;
1168 else
1169 list_info->head=next;
1170 break;
1171 }
1172 element=next->next;
1173 next->next=next->next->next;
1174 }
1175 if (next->next == (ElementInfo *) NULL)
1176 {
1177 if (element != (ElementInfo *) NULL)
1178 element->next=next;
1179 else
1180 list_info->head=next;
1181 list_info->tail=next;
1182 }
1183 list_info->elements++;
cristyf84a1932010-01-03 18:00:18 +00001184 UnlockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001185 return(MagickTrue);
1186}
1187
1188/*
1189%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1190% %
1191% %
1192% %
1193% I s H a s h m a p E m p t y %
1194% %
1195% %
1196% %
1197%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1198%
1199% IsHashmapEmpty() returns MagickTrue if the hash-map is empty.
1200%
1201% The format of the IsHashmapEmpty method is:
1202%
1203% MagickBooleanType IsHashmapEmpty(const HashmapInfo *hashmap_info)
1204%
1205% A description of each parameter follows:
1206%
1207% o hashmap_info: the hashmap info.
1208%
1209*/
1210MagickExport MagickBooleanType IsHashmapEmpty(const HashmapInfo *hashmap_info)
1211{
1212 assert(hashmap_info != (HashmapInfo *) NULL);
1213 assert(hashmap_info->signature == MagickSignature);
1214 if (hashmap_info->debug != MagickFalse)
1215 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1216 return(hashmap_info->entries == 0 ? MagickTrue : MagickFalse);
1217}
1218
1219/*
1220%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1221% %
1222% %
1223% %
1224% I s L i n k e d L i s t E m p t y %
1225% %
1226% %
1227% %
1228%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1229%
1230% IsLinkedListEmpty() returns MagickTrue if the linked-list is empty.
1231%
1232% The format of the IsLinkedListEmpty method is:
1233%
1234% MagickBooleanType IsLinkedListEmpty(LinkedListInfo *list_info)
1235%
1236% A description of each parameter follows:
1237%
1238% o list_info: the linked-list info.
1239%
1240*/
1241MagickExport MagickBooleanType IsLinkedListEmpty(
1242 const LinkedListInfo *list_info)
1243{
1244 assert(list_info != (LinkedListInfo *) NULL);
1245 assert(list_info->signature == MagickSignature);
1246 if (list_info->debug != MagickFalse)
1247 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1248 return(list_info->elements == 0 ? MagickTrue : MagickFalse);
1249}
1250
1251/*
1252%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1253% %
1254% %
1255% %
1256% L i n k e d L i s t T o A r r a y %
1257% %
1258% %
1259% %
1260%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1261%
1262% LinkedListToArray() converts the linked-list to an array.
1263%
1264% The format of the LinkedListToArray method is:
1265%
1266% MagickBooleanType LinkedListToArray(LinkedListInfo *list_info,
1267% void **array)
1268%
1269% A description of each parameter follows:
1270%
1271% o list_info: the linked-list info.
1272%
1273% o array: the array.
1274%
1275*/
1276MagickExport MagickBooleanType LinkedListToArray(LinkedListInfo *list_info,
1277 void **array)
1278{
1279 register ElementInfo
1280 *next;
1281
cristybb503372010-05-27 20:51:26 +00001282 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001283 i;
1284
1285 assert(list_info != (LinkedListInfo *) NULL);
1286 assert(list_info->signature == MagickSignature);
1287 if (list_info->debug != MagickFalse)
1288 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1289 if (array == (void **) NULL)
1290 return(MagickFalse);
cristyf84a1932010-01-03 18:00:18 +00001291 LockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001292 next=list_info->head;
1293 for (i=0; next != (ElementInfo *) NULL; i++)
1294 {
1295 array[i]=next->value;
1296 next=next->next;
1297 }
cristyf84a1932010-01-03 18:00:18 +00001298 UnlockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001299 return(MagickTrue);
1300}
1301
1302/*
1303%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1304% %
1305% %
1306% %
1307% N e w H a s h m a p %
1308% %
1309% %
1310% %
1311%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1312%
1313% NewHashmap() returns a pointer to a HashmapInfo structure initialized
1314% to default values. The capacity is an initial estimate. The hashmap will
1315% increase capacity dynamically as the demand requires.
1316%
1317% The format of the NewHashmap method is:
1318%
cristybb503372010-05-27 20:51:26 +00001319% HashmapInfo *NewHashmap(const size_t capacity,
cristy3ed852e2009-09-05 21:47:34 +00001320% size_t (*hash)(const void *),
1321% MagickBooleanType (*compare)(const void *,const void *),
1322% void *(*relinquish_key)(void *),void *(*relinquish_value)(void *))
1323%
1324% A description of each parameter follows:
1325%
1326% o capacity: the initial number entries in the hash-map: typically
1327% SmallHashmapSize, MediumHashmapSize, or LargeHashmapSize. The
1328% hashmap will dynamically increase its capacity on demand.
1329%
1330% o hash: the hash method, typically HashPointerType(), HashStringType(),
1331% or HashStringInfoType().
1332%
1333% o compare: the compare method, typically NULL, CompareHashmapString(),
1334% or CompareHashmapStringInfo().
1335%
1336% o relinquish_key: the key deallocation method, typically
1337% RelinquishMagickMemory(), called whenever a key is removed from the
1338% hash-map.
1339%
1340% o relinquish_value: the value deallocation method; typically
1341% RelinquishMagickMemory(), called whenever a value object is removed from
1342% the hash-map.
1343%
1344*/
cristybb503372010-05-27 20:51:26 +00001345MagickExport HashmapInfo *NewHashmap(const size_t capacity,
cristy3ed852e2009-09-05 21:47:34 +00001346 size_t (*hash)(const void *),
1347 MagickBooleanType (*compare)(const void *,const void *),
1348 void *(*relinquish_key)(void *),void *(*relinquish_value)(void *))
1349{
1350 HashmapInfo
1351 *hashmap_info;
1352
cristy73bd4a52010-10-05 11:24:23 +00001353 hashmap_info=(HashmapInfo *) AcquireMagickMemory(sizeof(*hashmap_info));
cristy3ed852e2009-09-05 21:47:34 +00001354 if (hashmap_info == (HashmapInfo *) NULL)
1355 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1356 (void) ResetMagickMemory(hashmap_info,0,sizeof(*hashmap_info));
1357 hashmap_info->hash=HashPointerType;
1358 if (hash != (size_t (*)(const void *)) NULL)
1359 hashmap_info->hash=hash;
1360 hashmap_info->compare=(MagickBooleanType (*)(const void *,const void *)) NULL;
1361 if (compare != (MagickBooleanType (*)(const void *,const void *)) NULL)
1362 hashmap_info->compare=compare;
1363 hashmap_info->relinquish_key=relinquish_key;
1364 hashmap_info->relinquish_value=relinquish_value;
1365 hashmap_info->entries=0;
1366 hashmap_info->capacity=capacity;
1367 hashmap_info->map=(LinkedListInfo **) NULL;
1368 if (~capacity >= 1UL)
1369 hashmap_info->map=(LinkedListInfo **) AcquireQuantumMemory((size_t)
1370 capacity+1UL,sizeof(*hashmap_info->map));
1371 if (hashmap_info->map == (LinkedListInfo **) NULL)
1372 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1373 (void) ResetMagickMemory(hashmap_info->map,0,(size_t) capacity*
1374 sizeof(*hashmap_info->map));
1375 hashmap_info->debug=IsEventLogging();
1376 hashmap_info->semaphore=AllocateSemaphoreInfo();
1377 hashmap_info->signature=MagickSignature;
1378 return(hashmap_info);
1379}
1380
1381/*
1382%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1383% %
1384% %
1385% %
1386% N e w L i n k e d L i s t I n f o %
1387% %
1388% %
1389% %
1390%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1391%
1392% NewLinkedList() returns a pointer to a LinkedListInfo structure
1393% initialized to default values.
1394%
1395% The format of the NewLinkedList method is:
1396%
cristybb503372010-05-27 20:51:26 +00001397% LinkedListInfo *NewLinkedList(const size_t capacity)
cristy3ed852e2009-09-05 21:47:34 +00001398%
1399% A description of each parameter follows:
1400%
1401% o capacity: the maximum number of elements in the list.
1402%
1403*/
cristybb503372010-05-27 20:51:26 +00001404MagickExport LinkedListInfo *NewLinkedList(const size_t capacity)
cristy3ed852e2009-09-05 21:47:34 +00001405{
1406 LinkedListInfo
1407 *list_info;
1408
cristy73bd4a52010-10-05 11:24:23 +00001409 list_info=(LinkedListInfo *) AcquireMagickMemory(sizeof(*list_info));
cristy3ed852e2009-09-05 21:47:34 +00001410 if (list_info == (LinkedListInfo *) NULL)
1411 ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
1412 (void) ResetMagickMemory(list_info,0,sizeof(*list_info));
cristybb503372010-05-27 20:51:26 +00001413 list_info->capacity=capacity == 0 ? (size_t) (~0) : capacity;
cristy3ed852e2009-09-05 21:47:34 +00001414 list_info->elements=0;
1415 list_info->head=(ElementInfo *) NULL;
1416 list_info->tail=(ElementInfo *) NULL;
1417 list_info->next=(ElementInfo *) NULL;
1418 list_info->debug=MagickFalse;
1419 list_info->semaphore=AllocateSemaphoreInfo();
1420 list_info->signature=MagickSignature;
1421 return(list_info);
1422}
1423
1424/*
1425%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1426% %
1427% %
1428% %
1429% P u t E n t r y I n H a s h m a p %
1430% %
1431% %
1432% %
1433%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1434%
1435% PutEntryInHashmap() puts an entry in the hash-map. If the key already
1436% exists in the map it is first removed.
1437%
1438% The format of the PutEntryInHashmap method is:
1439%
1440% MagickBooleanType PutEntryInHashmap(HashmapInfo *hashmap_info,
1441% const void *key,const void *value)
1442%
1443% A description of each parameter follows:
1444%
1445% o hashmap_info: the hashmap info.
1446%
1447% o key: the key.
1448%
1449% o value: the value.
1450%
1451*/
1452
1453static MagickBooleanType IncreaseHashmapCapacity(HashmapInfo *hashmap_info)
1454{
1455#define MaxCapacities 20
1456
cristybb503372010-05-27 20:51:26 +00001457 const size_t
cristy3ed852e2009-09-05 21:47:34 +00001458 capacities[MaxCapacities] =
1459 {
1460 17, 31, 61, 131, 257, 509, 1021, 2053, 4099, 8191, 16381, 32771,
1461 65537, 131071, 262147, 524287, 1048573, 2097143, 4194301, 8388617
1462 };
1463
1464 ElementInfo
1465 *element;
1466
1467 EntryInfo
1468 *entry;
1469
1470 LinkedListInfo
1471 *list_info,
1472 *map_info,
1473 **map;
1474
1475 register ElementInfo
1476 *next;
1477
cristybb503372010-05-27 20:51:26 +00001478 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001479 i;
1480
cristybb503372010-05-27 20:51:26 +00001481 size_t
cristy3ed852e2009-09-05 21:47:34 +00001482 capacity;
1483
1484 /*
1485 Increase to the next prime capacity.
1486 */
1487 for (i=0; i < MaxCapacities; i++)
1488 if (hashmap_info->capacity < capacities[i])
1489 break;
1490 if (i >= (MaxCapacities-1))
1491 return(MagickFalse);
1492 capacity=capacities[i+1];
1493 map=(LinkedListInfo **) AcquireQuantumMemory((size_t) capacity+1UL,
1494 sizeof(*map));
1495 if (map == (LinkedListInfo **) NULL)
1496 return(MagickFalse);
1497 (void) ResetMagickMemory(map,0,(size_t) capacity*sizeof(*map));
1498 /*
1499 Copy entries to new hashmap with increased capacity.
1500 */
cristybb503372010-05-27 20:51:26 +00001501 for (i=0; i < (ssize_t) hashmap_info->capacity; i++)
cristy3ed852e2009-09-05 21:47:34 +00001502 {
1503 list_info=hashmap_info->map[i];
1504 if (list_info == (LinkedListInfo *) NULL)
1505 continue;
cristyf84a1932010-01-03 18:00:18 +00001506 LockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001507 for (next=list_info->head; next != (ElementInfo *) NULL; )
1508 {
1509 element=next;
1510 next=next->next;
1511 entry=(EntryInfo *) element->value;
1512 map_info=map[entry->hash % capacity];
1513 if (map_info == (LinkedListInfo *) NULL)
1514 {
1515 map_info=NewLinkedList(0);
1516 map[entry->hash % capacity]=map_info;
1517 }
1518 map_info->next=element;
1519 element->next=map_info->head;
1520 map_info->head=element;
1521 map_info->elements++;
1522 }
1523 list_info->signature=(~MagickSignature);
cristyf84a1932010-01-03 18:00:18 +00001524 UnlockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001525 DestroySemaphoreInfo(&list_info->semaphore);
1526 list_info=(LinkedListInfo *) RelinquishMagickMemory(list_info);
1527 }
1528 hashmap_info->map=(LinkedListInfo **) RelinquishMagickMemory(
1529 hashmap_info->map);
1530 hashmap_info->map=map;
1531 hashmap_info->capacity=capacity;
1532 return(MagickTrue);
1533}
1534
1535MagickExport MagickBooleanType PutEntryInHashmap(HashmapInfo *hashmap_info,
1536 const void *key,const void *value)
1537{
1538 EntryInfo
1539 *entry,
1540 *next;
1541
1542 LinkedListInfo
1543 *list_info;
1544
cristybb503372010-05-27 20:51:26 +00001545 register size_t
cristy3ed852e2009-09-05 21:47:34 +00001546 i;
1547
1548 assert(hashmap_info != (HashmapInfo *) NULL);
1549 assert(hashmap_info->signature == MagickSignature);
1550 if (hashmap_info->debug != MagickFalse)
1551 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1552 if ((key == (void *) NULL) || (value == (void *) NULL))
1553 return(MagickFalse);
cristy73bd4a52010-10-05 11:24:23 +00001554 next=(EntryInfo *) AcquireMagickMemory(sizeof(*next));
cristy3ed852e2009-09-05 21:47:34 +00001555 if (next == (EntryInfo *) NULL)
1556 return(MagickFalse);
cristyf84a1932010-01-03 18:00:18 +00001557 LockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001558 next->hash=hashmap_info->hash(key);
1559 next->key=(void *) key;
1560 next->value=(void *) value;
1561 list_info=hashmap_info->map[next->hash % hashmap_info->capacity];
1562 if (list_info == (LinkedListInfo *) NULL)
1563 {
1564 list_info=NewLinkedList(0);
1565 hashmap_info->map[next->hash % hashmap_info->capacity]=list_info;
1566 }
1567 else
1568 {
1569 list_info->next=list_info->head;
1570 entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
1571 for (i=0; entry != (EntryInfo *) NULL; i++)
1572 {
1573 if (entry->hash == next->hash)
1574 {
1575 MagickBooleanType
1576 compare;
1577
1578 compare=MagickTrue;
1579 if (hashmap_info->compare !=
1580 (MagickBooleanType (*)(const void *,const void *)) NULL)
1581 compare=hashmap_info->compare(key,entry->key);
1582 if (compare == MagickTrue)
1583 {
1584 (void) RemoveElementFromLinkedList(list_info,i);
1585 if (hashmap_info->relinquish_key != (void *(*)(void *)) NULL)
1586 entry->key=hashmap_info->relinquish_key(entry->key);
1587 if (hashmap_info->relinquish_value != (void *(*)(void *)) NULL)
1588 entry->value=hashmap_info->relinquish_value(entry->value);
1589 entry=(EntryInfo *) RelinquishMagickMemory(entry);
1590 break;
1591 }
1592 }
1593 entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
1594 }
1595 }
1596 if (InsertValueInLinkedList(list_info,0,next) == MagickFalse)
1597 {
1598 next=(EntryInfo *) RelinquishMagickMemory(next);
cristyf84a1932010-01-03 18:00:18 +00001599 UnlockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001600 return(MagickFalse);
1601 }
1602 if (list_info->elements >= (hashmap_info->capacity-1))
1603 if (IncreaseHashmapCapacity(hashmap_info) == MagickFalse)
1604 {
cristyf84a1932010-01-03 18:00:18 +00001605 UnlockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001606 return(MagickFalse);
1607 }
1608 hashmap_info->entries++;
cristyf84a1932010-01-03 18:00:18 +00001609 UnlockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001610 return(MagickTrue);
1611}
1612
1613/*
1614%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1615% %
1616% %
1617% %
1618% R e m o v e E l e m e n t B y V a l u e F r o m L i n k e d L i s t %
1619% %
1620% %
1621% %
1622%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1623%
1624% RemoveElementByValueFromLinkedList() removes an element from the linked-list
1625% by value.
1626%
1627% The format of the RemoveElementByValueFromLinkedList method is:
1628%
1629% void *RemoveElementByValueFromLinkedList(LinkedListInfo *list_info,
1630% const void *value)
1631%
1632% A description of each parameter follows:
1633%
1634% o list_info: the list info.
1635%
1636% o value: the value.
1637%
1638*/
1639MagickExport void *RemoveElementByValueFromLinkedList(LinkedListInfo *list_info,
1640 const void *value)
1641{
1642 ElementInfo
1643 *next;
1644
1645 assert(list_info != (LinkedListInfo *) NULL);
1646 assert(list_info->signature == MagickSignature);
1647 if (list_info->debug != MagickFalse)
1648 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1649 if ((list_info->elements == 0) || (value == (const void *) NULL))
1650 return((void *) NULL);
cristyf84a1932010-01-03 18:00:18 +00001651 LockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001652 if (value == list_info->head->value)
1653 {
1654 if (list_info->next == list_info->head)
1655 list_info->next=list_info->head->next;
1656 next=list_info->head;
1657 list_info->head=list_info->head->next;
1658 next=(ElementInfo *) RelinquishMagickMemory(next);
1659 }
1660 else
1661 {
1662 ElementInfo
1663 *element;
1664
1665 next=list_info->head;
1666 while ((next->next != (ElementInfo *) NULL) &&
1667 (next->next->value != value))
1668 next=next->next;
1669 if (next->next == (ElementInfo *) NULL)
1670 {
cristyf84a1932010-01-03 18:00:18 +00001671 UnlockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001672 return((void *) NULL);
1673 }
1674 element=next->next;
1675 next->next=element->next;
1676 if (element == list_info->tail)
1677 list_info->tail=next;
1678 if (list_info->next == element)
1679 list_info->next=element->next;
1680 element=(ElementInfo *) RelinquishMagickMemory(element);
1681 }
1682 list_info->elements--;
cristyf84a1932010-01-03 18:00:18 +00001683 UnlockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001684 return((void *) value);
1685}
1686
1687/*
1688%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1689% %
1690% %
1691% %
1692% R e m o v e E l e m e n t F r o m L i n k e d L i s t %
1693% %
1694% %
1695% %
1696%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1697%
1698% RemoveElementFromLinkedList() removes an element from the linked-list at the
1699% specified location.
1700%
1701% The format of the RemoveElementFromLinkedList method is:
1702%
1703% void *RemoveElementFromLinkedList(LinkedListInfo *list_info,
cristybb503372010-05-27 20:51:26 +00001704% const size_t index)
cristy3ed852e2009-09-05 21:47:34 +00001705%
1706% A description of each parameter follows:
1707%
1708% o list_info: the linked-list info.
1709%
1710% o index: the index.
1711%
1712*/
1713MagickExport void *RemoveElementFromLinkedList(LinkedListInfo *list_info,
cristybb503372010-05-27 20:51:26 +00001714 const size_t index)
cristy3ed852e2009-09-05 21:47:34 +00001715{
1716 ElementInfo
1717 *next;
1718
cristybb503372010-05-27 20:51:26 +00001719 register ssize_t
cristy3ed852e2009-09-05 21:47:34 +00001720 i;
1721
1722 void
1723 *value;
1724
1725 assert(list_info != (LinkedListInfo *) NULL);
1726 assert(list_info->signature == MagickSignature);
1727 if (list_info->debug != MagickFalse)
1728 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1729 if (index >= list_info->elements)
1730 return((void *) NULL);
cristyf84a1932010-01-03 18:00:18 +00001731 LockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001732 if (index == 0)
1733 {
1734 if (list_info->next == list_info->head)
1735 list_info->next=list_info->head->next;
1736 value=list_info->head->value;
1737 next=list_info->head;
1738 list_info->head=list_info->head->next;
1739 next=(ElementInfo *) RelinquishMagickMemory(next);
1740 }
1741 else
1742 {
1743 ElementInfo
1744 *element;
1745
1746 next=list_info->head;
cristybb503372010-05-27 20:51:26 +00001747 for (i=1; i < (ssize_t) index; i++)
cristy3ed852e2009-09-05 21:47:34 +00001748 next=next->next;
1749 element=next->next;
1750 next->next=element->next;
1751 if (element == list_info->tail)
1752 list_info->tail=next;
1753 if (list_info->next == element)
1754 list_info->next=element->next;
1755 value=element->value;
1756 element=(ElementInfo *) RelinquishMagickMemory(element);
1757 }
1758 list_info->elements--;
cristyf84a1932010-01-03 18:00:18 +00001759 UnlockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001760 return(value);
1761}
1762
1763/*
1764%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1765% %
1766% %
1767% %
1768% R e m o v e E n t r y F r o m H a s h m a p %
1769% %
1770% %
1771% %
1772%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1773%
1774% RemoveEntryFromHashmap() removes an entry from the hash-map by its key.
1775%
1776% The format of the RemoveEntryFromHashmap method is:
1777%
1778% void *RemoveEntryFromHashmap(HashmapInfo *hashmap_info,void *key)
1779%
1780% A description of each parameter follows:
1781%
1782% o hashmap_info: the hashmap info.
1783%
1784% o key: the key.
1785%
1786*/
1787MagickExport void *RemoveEntryFromHashmap(HashmapInfo *hashmap_info,
1788 const void *key)
1789{
1790 EntryInfo
1791 *entry;
1792
1793 LinkedListInfo
1794 *list_info;
1795
cristybb503372010-05-27 20:51:26 +00001796 register size_t
cristy3ed852e2009-09-05 21:47:34 +00001797 i;
1798
1799 size_t
1800 hash;
1801
1802 void
1803 *value;
1804
1805 assert(hashmap_info != (HashmapInfo *) NULL);
1806 assert(hashmap_info->signature == MagickSignature);
1807 if (hashmap_info->debug != MagickFalse)
1808 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1809 if (key == (const void *) NULL)
1810 return((void *) NULL);
cristyf84a1932010-01-03 18:00:18 +00001811 LockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001812 hash=hashmap_info->hash(key);
1813 list_info=hashmap_info->map[hash % hashmap_info->capacity];
1814 if (list_info != (LinkedListInfo *) NULL)
1815 {
1816 list_info->next=list_info->head;
1817 entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
1818 for (i=0; entry != (EntryInfo *) NULL; i++)
1819 {
1820 if (entry->hash == hash)
1821 {
1822 MagickBooleanType
1823 compare;
1824
1825 compare=MagickTrue;
1826 if (hashmap_info->compare !=
1827 (MagickBooleanType (*)(const void *,const void *)) NULL)
1828 compare=hashmap_info->compare(key,entry->key);
1829 if (compare == MagickTrue)
1830 {
1831 entry=(EntryInfo *) RemoveElementFromLinkedList(list_info,i);
1832 if (entry == (EntryInfo *) NULL)
1833 {
cristyf84a1932010-01-03 18:00:18 +00001834 UnlockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001835 return((void *) NULL);
1836 }
1837 if (hashmap_info->relinquish_key != (void *(*)(void *)) NULL)
1838 entry->key=hashmap_info->relinquish_key(entry->key);
1839 value=entry->value;
1840 entry=(EntryInfo *) RelinquishMagickMemory(entry);
1841 hashmap_info->entries--;
cristyf84a1932010-01-03 18:00:18 +00001842 UnlockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001843 return(value);
1844 }
1845 }
1846 entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
1847 }
1848 }
cristyf84a1932010-01-03 18:00:18 +00001849 UnlockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001850 return((void *) NULL);
1851}
1852
1853/*
1854%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1855% %
1856% %
1857% %
1858% R e m o v e L a s t E l e m e n t F r o m L i n k e d L i s t %
1859% %
1860% %
1861% %
1862%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1863%
1864% RemoveLastElementFromLinkedList() removes the last element from the
1865% linked-list.
1866%
1867% The format of the RemoveLastElementFromLinkedList method is:
1868%
1869% void *RemoveLastElementFromLinkedList(LinkedListInfo *list_info)
1870%
1871% A description of each parameter follows:
1872%
1873% o list_info: the linked-list info.
1874%
1875*/
1876MagickExport void *RemoveLastElementFromLinkedList(LinkedListInfo *list_info)
1877{
1878 void
1879 *value;
1880
1881 assert(list_info != (LinkedListInfo *) NULL);
1882 assert(list_info->signature == MagickSignature);
1883 if (list_info->debug != MagickFalse)
1884 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
1885 if (list_info->elements == 0)
1886 return((void *) NULL);
cristyf84a1932010-01-03 18:00:18 +00001887 LockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001888 if (list_info->next == list_info->tail)
1889 list_info->next=(ElementInfo *) NULL;
1890 if (list_info->elements == 1UL)
1891 {
1892 value=list_info->head->value;
1893 list_info->head=(ElementInfo *) NULL;
1894 list_info->tail=(ElementInfo *) RelinquishMagickMemory(list_info->tail);
1895 }
1896 else
1897 {
1898 ElementInfo
1899 *next;
1900
1901 value=list_info->tail->value;
1902 next=list_info->head;
1903 while (next->next != list_info->tail)
1904 next=next->next;
1905 list_info->tail=(ElementInfo *) RelinquishMagickMemory(list_info->tail);
1906 list_info->tail=next;
1907 next->next=(ElementInfo *) NULL;
1908 }
1909 list_info->elements--;
cristyf84a1932010-01-03 18:00:18 +00001910 UnlockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001911 return(value);
1912}
1913
1914/*
1915%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1916% %
1917% %
1918% %
1919% R e s e t H a s h m a p I t e r a t o r %
1920% %
1921% %
1922% %
1923%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1924%
1925% ResetHashmapIterator() resets the hash-map iterator. Use it in conjunction
1926% with GetNextKeyInHashmap() to iterate over all the keys in the hash-map.
1927%
1928% The format of the ResetHashmapIterator method is:
1929%
1930% ResetHashmapIterator(HashmapInfo *hashmap_info)
1931%
1932% A description of each parameter follows:
1933%
1934% o hashmap_info: the hashmap info.
1935%
1936*/
1937MagickExport void ResetHashmapIterator(HashmapInfo *hashmap_info)
1938{
1939 assert(hashmap_info != (HashmapInfo *) NULL);
1940 assert(hashmap_info->signature == MagickSignature);
1941 if (hashmap_info->debug != MagickFalse)
1942 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristyf84a1932010-01-03 18:00:18 +00001943 LockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001944 hashmap_info->next=0;
1945 hashmap_info->head_of_list=MagickFalse;
cristyf84a1932010-01-03 18:00:18 +00001946 UnlockSemaphoreInfo(hashmap_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001947}
1948
1949/*
1950%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1951% %
1952% %
1953% %
1954% R e s e t L i n k e d L i s t I t e r a t o r %
1955% %
1956% %
1957% %
1958%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
1959%
1960% ResetLinkedListIterator() resets the lined-list iterator. Use it in
1961% conjunction with GetNextValueInLinkedList() to iterate over all the values
1962% in the linked-list.
1963%
1964% The format of the ResetLinkedListIterator method is:
1965%
1966% ResetLinkedListIterator(LinkedListInfo *list_info)
1967%
1968% A description of each parameter follows:
1969%
1970% o list_info: the linked-list info.
1971%
1972*/
1973MagickExport void ResetLinkedListIterator(LinkedListInfo *list_info)
1974{
1975 assert(list_info != (LinkedListInfo *) NULL);
1976 assert(list_info->signature == MagickSignature);
1977 if (list_info->debug != MagickFalse)
1978 (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
cristyf84a1932010-01-03 18:00:18 +00001979 LockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001980 list_info->next=list_info->head;
cristyf84a1932010-01-03 18:00:18 +00001981 UnlockSemaphoreInfo(list_info->semaphore);
cristy3ed852e2009-09-05 21:47:34 +00001982}