Plan 9 from Bell Labs’s /usr/web/sources/contrib/fgb/root/sys/src/cmd/magick/magick/hashmap.c

Copyright © 2021 Plan 9 Foundation.
Distributed under the MIT License.
Download the Plan 9 distribution.


/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%                H   H   AAA   SSSSS  H   H  M   M   AAA   PPPP               %
%                H   H  A   A  SS     H   H  MM MM  A   A  P   P              %
%                HHHHH  AAAAA   SSS   HHHHH  M M M  AAAAA  PPPP               %
%                H   H  A   A     SS  H   H  M   M  A   A  P                  %
%                H   H  A   A  SSSSS  H   H  M   M  A   A  P                  %
%                                                                             %
%                                                                             %
%                  ImageMagick Hash-map and Linked-list Methods               %
%                                                                             %
%                              Software Design                                %
%                                John Cristy                                  %
%                               December 2002                                 %
%                                                                             %
%                                                                             %
%  Copyright 1999-2007 ImageMagick Studio LLC, a non-profit organization      %
%  dedicated to making software imaging solutions freely available.           %
%                                                                             %
%  You may not use this file except in compliance with the License.  You may  %
%  obtain a copy of the License at                                            %
%                                                                             %
%    http://www.imagemagick.org/script/license.php                            %
%                                                                             %
%  Unless required by applicable law or agreed to in writing, software        %
%  distributed under the License is distributed on an "AS IS" BASIS,          %
%  WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.   %
%  See the License for the specific language governing permissions and        %
%  limitations under the License.                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  This module implements the standard handy hash and linked-list methods for
%  storing and retrieving large numbers of data elements.  It is loosely based
%  on the Java implementation of these algorithms.
%
*/

/*
  Include declarations.
*/
#include "magick/studio.h"
#include "magick/exception.h"
#include "magick/exception-private.h"
#include "magick/hashmap.h"
#include "magick/memory_.h"
#include "magick/semaphore.h"
#include "magick/signature.h"
#include "magick/string_.h"

/*
  Typedef declarations.
*/
typedef struct _ElementInfo
{
  void
    *value;

  struct _ElementInfo
    *next;
} ElementInfo;

typedef struct _EntryInfo
{
  size_t
    hash;

  void
    *key,
    *value;
} EntryInfo;

struct _LinkedListInfo
{
  unsigned long
    capacity,
    elements;

  ElementInfo
    *head,
    *tail,
    *next;

  MagickBooleanType
    debug;

  SemaphoreInfo
    *semaphore;

  unsigned long
    signature;
};

struct _HashmapInfo
{
  size_t
    (*hash)(const void *);

  MagickBooleanType
    (*compare)(const void *,const void *);

  void
    *(*relinquish_key)(void *),
    *(*relinquish_value)(void *);

  unsigned long
    capacity,
    entries,
    next;

  MagickBooleanType
    head_of_list;

  LinkedListInfo
    **map;

  MagickBooleanType
    debug;

  SemaphoreInfo
    *semaphore;

  unsigned long
    signature;
};

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   A p p e n d V a l u e T o L i n k e d L i s t                             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  AppendValueToLinkedList() appends a value to the end of the linked-list.
%
%  The format of the AppendValueToLinkedList method is:
%
%      MagickBooleanType AppendValueToLinkedList(LinkedListInfo *list_info,
%        const void *value)
%
%  A description of each parameter follows:
%
%    o list_info: The linked-list info.
%
%    o value: The value.
%
*/
MagickExport MagickBooleanType AppendValueToLinkedList(
  LinkedListInfo *list_info,const void *value)
{
  register ElementInfo
    *next;

  assert(list_info != (LinkedListInfo *) NULL);
  assert(list_info->signature == MagickSignature);
  list_info->debug=IsEventLogging();
  if (list_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  if (list_info->elements == list_info->capacity)
    return(MagickFalse);
  next=(ElementInfo *) AcquireMagickMemory(sizeof(*next));
  if (next == (ElementInfo *) NULL)
    return(MagickFalse);
  next->value=(void *) value;
  next->next=(ElementInfo *) NULL;
  AcquireSemaphoreInfo(&list_info->semaphore);
  if (list_info->next == (ElementInfo *) NULL)
    list_info->next=next;
  if (list_info->elements == 0)
    list_info->head=next;
  else
    list_info->tail->next=next;
  list_info->tail=next;
  list_info->elements++;
  RelinquishSemaphoreInfo(list_info->semaphore);
  return(MagickTrue);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   C l e a r L i n k e d L i s t                                             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  ClearLinkedList() clears all the elements from the linked-list.
%
%  The format of the ClearLinkedList method is:
%
%      void ClearLinkedList(LinkedListInfo *list_info,
%        void *(*relinquish_value)(void *))
%
%  A description of each parameter follows:
%
%    o list_info: The linked-list info.
%
%    o relinquish_value: The value deallocation method; typically
%      RelinquishMagickMemory().
%
*/
MagickExport void ClearLinkedList(LinkedListInfo *list_info,
  void *(*relinquish_value)(void *))
{
  ElementInfo
    *element;

  register ElementInfo
    *next;

  assert(list_info != (LinkedListInfo *) NULL);
  assert(list_info->signature == MagickSignature);
  if (list_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  AcquireSemaphoreInfo(&list_info->semaphore);
  next=list_info->head;
  while (next != (ElementInfo *) NULL)
  {
    if (relinquish_value != (void *(*)(void *)) NULL)
      next->value=relinquish_value(next->value);
    element=next;
    next=next->next;
    element=(ElementInfo *) RelinquishMagickMemory(element);
  }
  list_info->head=(ElementInfo *) NULL;
  list_info->tail=(ElementInfo *) NULL;
  list_info->next=(ElementInfo *) NULL;
  list_info->elements=0;
  RelinquishSemaphoreInfo(list_info->semaphore);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   C o m p a r e H a s h m a p S t r i n g                                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Specify the CompareHashmapString() method in NewHashmap() to find an entry
%  in a hash-map based on the contents of a string.
%
%  The format of the CompareHashmapString method is:
%
%      MagickBooleanType CompareHashmapString(const void *target,
%        const void *source)
%
%  A description of each parameter follows:
%
%    o target: The target string.
%
%    o source: The source string.
%
*/
MagickExport MagickBooleanType CompareHashmapString(const void *target,
  const void *source)
{
  const char
    *p,
    *q;

  p=(const char *) target;
  q=(const char *) source;
  return(LocaleCompare(p,q) == 0 ? MagickTrue : MagickFalse);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   C o m p a r e H a s h m a p S t r i n g I n f o                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Specify the CompareHashmapStringInfo() method in NewHashmap() to find an
%  entry in a hash-map based on the contents of a string.
%
%  The format of the CompareHashmapStringInfo method is:
%
%      MagickBooleanType CompareHashmapStringInfo(const void *target,
%        const void *source)
%
%  A description of each parameter follows:
%
%    o target: The target string.
%
%    o source: The source string.
%
*/
MagickExport MagickBooleanType CompareHashmapStringInfo(const void *target,
  const void *source)
{
  const StringInfo
    *p,
    *q;

  p=(const StringInfo *) target;
  q=(const StringInfo *) source;
  return(CompareStringInfo(p,q) == 0 ? MagickTrue : MagickFalse);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   D e s t r o y H a s h m a p                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  DestroyHashmap() frees the hash-map and all associated resources.
%
%  The format of the DestroyHashmap method is:
%
%      HashmapInfo *DestroyHashmap(HashmapInfo *hashmap_info)
%
%  A description of each parameter follows:
%
%    o hashmap_info: The hashmap info.
%
*/
MagickExport HashmapInfo *DestroyHashmap(HashmapInfo *hashmap_info)
{
  LinkedListInfo
    *list_info;

  register EntryInfo
    *entry;

  register long
    i;

  assert(hashmap_info != (HashmapInfo *) NULL);
  assert(hashmap_info->signature == MagickSignature);
  if (hashmap_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  AcquireSemaphoreInfo(&hashmap_info->semaphore);
  for (i=0; i < (long) hashmap_info->capacity; i++)
  {
    list_info=hashmap_info->map[i];
    if (list_info != (LinkedListInfo *) NULL)
      {
        list_info->next=list_info->head;
        entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
        while (entry != (EntryInfo *) NULL)
        {
          if (hashmap_info->relinquish_key != (void *(*)(void *)) NULL)
            entry->key=hashmap_info->relinquish_key(entry->key);
          if (hashmap_info->relinquish_value != (void *(*)(void *)) NULL)
            entry->value=hashmap_info->relinquish_value(entry->value);
          entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
        }
      }
    if (list_info != (LinkedListInfo *) NULL)
      list_info=DestroyLinkedList(list_info,RelinquishMagickMemory);
  }
  hashmap_info->map=(LinkedListInfo **) RelinquishMagickMemory(
    hashmap_info->map);
  hashmap_info->signature=(~MagickSignature);
  RelinquishSemaphoreInfo(hashmap_info->semaphore);
  hashmap_info->semaphore=DestroySemaphoreInfo(hashmap_info->semaphore);
  hashmap_info=(HashmapInfo *) RelinquishMagickMemory(hashmap_info);
  return(hashmap_info);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   D e s t r o y L i n k e d L i s t                                         %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  DestroyLinkedList() frees the linked-list and all associated resources.
%
%  The format of the DestroyLinkedList method is:
%
%      LinkedListInfo *DestroyLinkedList(LinkedListInfo *list_info,
%        void *(*relinquish_value)(void *))
%
%  A description of each parameter follows:
%
%    o list_info: The linked-list info.
%
%    o relinquish_value: The value deallocation method;  typically
%      RelinquishMagickMemory().
%
*/
MagickExport LinkedListInfo *DestroyLinkedList(LinkedListInfo *list_info,
  void *(*relinquish_value)(void *))
{
  ElementInfo
    *entry;

  register ElementInfo
    *next;

  assert(list_info != (LinkedListInfo *) NULL);
  assert(list_info->signature == MagickSignature);
  if (list_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  AcquireSemaphoreInfo(&list_info->semaphore);
  for (next=list_info->head; next != (ElementInfo *) NULL; )
  {
    if (relinquish_value != (void *(*)(void *)) NULL)
      next->value=relinquish_value(next->value);
    entry=next;
    next=next->next;
    entry=(ElementInfo *) RelinquishMagickMemory(entry);
  }
  list_info->signature=(~MagickSignature);
  RelinquishSemaphoreInfo(list_info->semaphore);
  list_info->semaphore=DestroySemaphoreInfo(list_info->semaphore);
  list_info=(LinkedListInfo *) RelinquishMagickMemory(list_info);
  return(list_info);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   G e t L a s t V a l u e I n L i n k e d L i s t                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  GetLastValueInLinkedList() gets the last value in the linked-list.
%
%  The format of the GetLastValueInLinkedList method is:
%
%      void *GetLastValueInLinkedList(LinkedListInfo *list_info)
%
%  A description of each parameter follows:
%
%    o list_info: The linked_list info.
%
*/
MagickExport void *GetLastValueInLinkedList(LinkedListInfo *list_info)
{
  void
    *value;

  assert(list_info != (LinkedListInfo *) NULL);
  assert(list_info->signature == MagickSignature);
  if (list_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  if (list_info->elements == 0)
    return((void *) NULL);
  AcquireSemaphoreInfo(&list_info->semaphore);
  value=list_info->tail->value;
  RelinquishSemaphoreInfo(list_info->semaphore);
  return(value);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   G e t N e x t K e y I n H a s h m a p                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  GetNextKeyInHashmap() gets the next key in the hash-map.
%
%  The format of the GetNextKeyInHashmap method is:
%
%      void *GetNextKeyInHashmap(HashmapInfo *hashmap_info)
%
%  A description of each parameter follows:
%
%    o hashmap_info: The hashmap info.
%
*/
MagickExport void *GetNextKeyInHashmap(HashmapInfo *hashmap_info)
{
  LinkedListInfo
    *list_info;

  register EntryInfo
    *entry;

  void
    *key;

  assert(hashmap_info != (HashmapInfo *) NULL);
  assert(hashmap_info->signature == MagickSignature);
  if (hashmap_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  AcquireSemaphoreInfo(&hashmap_info->semaphore);
  while (hashmap_info->next < hashmap_info->capacity)
  {
    list_info=hashmap_info->map[hashmap_info->next];
    if (list_info != (LinkedListInfo *) NULL)
      {
        if (hashmap_info->head_of_list == MagickFalse)
          {
            list_info->next=list_info->head;
            hashmap_info->head_of_list=MagickTrue;
          }
        entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
        if (entry != (EntryInfo *) NULL)
          {
            key=entry->key;
            RelinquishSemaphoreInfo(hashmap_info->semaphore);
            return(key);
          }
        hashmap_info->head_of_list=MagickFalse;
      }
    hashmap_info->next++;
  }
  RelinquishSemaphoreInfo(hashmap_info->semaphore);
  return((void *) NULL);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   G e t N e x t V a l u e I n H a s h m a p                                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  GetNextValueInHashmap() gets the next value in the hash-map.
%
%  The format of the GetNextValueInHashmap method is:
%
%      void *GetNextValueInHashmap(HashmapInfo *hashmap_info)
%
%  A description of each parameter follows:
%
%    o hashmap_info: The hashmap info.
%
*/
MagickExport void *GetNextValueInHashmap(HashmapInfo *hashmap_info)
{
  LinkedListInfo
    *list_info;

  register EntryInfo
    *entry;

  void
    *value;

  assert(hashmap_info != (HashmapInfo *) NULL);
  assert(hashmap_info->signature == MagickSignature);
  if (hashmap_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  AcquireSemaphoreInfo(&hashmap_info->semaphore);
  while (hashmap_info->next < hashmap_info->capacity)
  {
    list_info=hashmap_info->map[hashmap_info->next];
    if (list_info != (LinkedListInfo *) NULL)
      {
        if (hashmap_info->head_of_list == MagickFalse)
          {
            list_info->next=list_info->head;
            hashmap_info->head_of_list=MagickTrue;
          }
        entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
        if (entry != (EntryInfo *) NULL)
          {
            value=entry->value;
            RelinquishSemaphoreInfo(hashmap_info->semaphore);
            return(value);
          }
        hashmap_info->head_of_list=MagickFalse;
      }
    hashmap_info->next++;
  }
  RelinquishSemaphoreInfo(hashmap_info->semaphore);
  return((void *) NULL);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   G e t N e x t V a l u e I n L i n k e d L i s t                           %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  GetNextValueInLinkedList() gets the next value in the linked-list.
%
%  The format of the GetNextValueInLinkedList method is:
%
%      void *GetNextValueInLinkedList(LinkedListInfo *list_info)
%
%  A description of each parameter follows:
%
%    o list_info: The linked-list info.
%
*/
MagickExport void *GetNextValueInLinkedList(LinkedListInfo *list_info)
{
  void
    *value;

  assert(list_info != (LinkedListInfo *) NULL);
  assert(list_info->signature == MagickSignature);
  if (list_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  if (list_info->next == (ElementInfo *) NULL)
    return((void *) NULL);
  AcquireSemaphoreInfo(&list_info->semaphore);
  value=list_info->next->value;
  list_info->next=list_info->next->next;
  RelinquishSemaphoreInfo(list_info->semaphore);
  return(value);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   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                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  GetNumberOfEntriesInHashmap() returns the number of entries in the hash-map.
%
%  The format of the GetNumberOfEntriesInHashmap method is:
%
%      unsigned long GetNumberOfEntriesInHashmap(const HashmapInfo *hashmap_info)
%
%  A description of each parameter follows:
%
%    o hashmap_info: The hashmap info.
%
*/
MagickExport unsigned long GetNumberOfEntriesInHashmap(
  const HashmapInfo *hashmap_info)
{
  assert(hashmap_info != (HashmapInfo *) NULL);
  assert(hashmap_info->signature == MagickSignature);
  if (hashmap_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  return(hashmap_info->entries);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   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             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  GetNumberOfElementsInLinkedList() returns the number of entries in the
%  linked-list.
%
%  The format of the GetNumberOfElementsInLinkedList method is:
%
%      unsigned long GetNumberOfElementsInLinkedList(
%        const LinkedListInfo *list_info)
%
%  A description of each parameter follows:
%
%    o list_info: The linked-list info.
%
*/
MagickExport unsigned long GetNumberOfElementsInLinkedList(
  const LinkedListInfo *list_info)
{
  assert(list_info != (LinkedListInfo *) NULL);
  assert(list_info->signature == MagickSignature);
  if (list_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  return(list_info->elements);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   G e t V a l u e F r o m H a s h m a p                                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  GetValueFromHashmap() gets an entry from the hash-map by its key.
%
%  The format of the GetValueFromHashmap method is:
%
%      void *GetValueFromHashmap(HashmapInfo *hashmap_info,const void *key)
%
%  A description of each parameter follows:
%
%    o hashmap_info: The hashmap info.
%
%    o key: The key.
%
*/
MagickExport void *GetValueFromHashmap(HashmapInfo *hashmap_info,
  const void *key)
{
  LinkedListInfo
    *list_info;

  register EntryInfo
    *entry;

  size_t
    hash;

  void
    *value;

  assert(hashmap_info != (HashmapInfo *) NULL);
  assert(hashmap_info->signature == MagickSignature);
  if (hashmap_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  if (key == (const void *) NULL)
    return((void *) NULL);
  AcquireSemaphoreInfo(&hashmap_info->semaphore);
  hash=hashmap_info->hash(key);
  list_info=hashmap_info->map[hash % hashmap_info->capacity];
  if (list_info != (LinkedListInfo *) NULL)
    {
      list_info->next=list_info->head;
      entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
      while (entry != (EntryInfo *) NULL)
      {
        if (entry->hash == hash)
          {
            MagickBooleanType
              compare;

            compare=MagickTrue;
            if (hashmap_info->compare !=
                (MagickBooleanType (*)(const void *,const void *)) NULL)
              compare=hashmap_info->compare(key,entry->key);
            if (compare == MagickTrue)
              {
                value=entry->value;
                RelinquishSemaphoreInfo(hashmap_info->semaphore);
                return(value);
              }
          }
        entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
      }
    }
  RelinquishSemaphoreInfo(hashmap_info->semaphore);
  return((void *) NULL);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   G e t V a l u e F r o m L i n k e d L i s t                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  GetValueFromLinkedList() gets a value from the linked-list at the specified
%  location.
%
%  The format of the GetValueFromLinkedList method is:
%
%      void *GetValueFromLinkedList(LinkedListInfo *list_info,
%        const unsigned long index)
%
%  A description of each parameter follows:
%
%    o list_info: The linked_list info.
%
%    o index: The list index.
%
*/
MagickExport void *GetValueFromLinkedList(LinkedListInfo *list_info,
  const unsigned long index)
{
  register ElementInfo
    *next;

  register long
    i;

  void
    *value;

  assert(list_info != (LinkedListInfo *) NULL);
  assert(list_info->signature == MagickSignature);
  if (list_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  if (index >= list_info->elements)
    return((void *) NULL);
  AcquireSemaphoreInfo(&list_info->semaphore);
  if (index == 0)
    {
      value=list_info->head->value;
      RelinquishSemaphoreInfo(list_info->semaphore);
      return(value);
    }
  if (index == (list_info->elements-1))
    {
      value=list_info->tail->value;
      RelinquishSemaphoreInfo(list_info->semaphore);
      return(value);
    }
  next=list_info->head;
  for (i=0; i < (long) index; i++)
    next=next->next;
  value=next->value;
  RelinquishSemaphoreInfo(list_info->semaphore);
  return(value);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   H a s h P o i n t e r T y p e                                             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Specify the HashPointerType() method in NewHashmap() to find an entry
%  in a hash-map based on the address of a pointer.
%
%  The format of the HashPointerType method is:
%
%      size_t HashPointerType(const void *pointer)
%
%  A description of each parameter follows:
%
%    o pointer: compute the hash entry location from this pointer address.
%
*/
MagickExport size_t HashPointerType(const void *pointer)
{
  size_t
    hash;

  hash=(size_t) pointer;
  hash+=(~(hash << 9));
  hash^=(hash >> 14);
  hash+=(hash << 4);
  hash^=(hash >> 10);
  return(hash);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   H a s h S t r i n g T y p e                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Specify the HashStringType() method in NewHashmap() to find an entry
%  in a hash-map based on the contents of a string.
%
%  The format of the HashStringType method is:
%
%      size_t HashStringType(const void *string)
%
%  A description of each parameter follows:
%
%    o string: compute the hash entry location from this string.
%
*/
MagickExport size_t HashStringType(const void *string)
{
  register long
    i;

  SignatureInfo
    signature_info;

  size_t
    hash;

  GetSignatureInfo(&signature_info);
  UpdateSignature(&signature_info,(const unsigned char *) string,
    strlen((const char *) string));
  FinalizeSignature(&signature_info);
  hash=0;
  for (i=0; i < 8; i++)
    hash^=signature_info.digest[i];
  return(hash);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   H a s h S t r i n g I n f o T y p e                                       %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  Specify the HashStringInfoType() method in NewHashmap() to find an entry
%  in a hash-map based on the contents of a string.
%
%  The format of the HashStringInfoType method is:
%
%      size_t HashStringInfoType(const void *string)
%
%  A description of each parameter follows:
%
%    o string: compute the hash entry location from this string.
%
*/
MagickExport size_t HashStringInfoType(const void *string)
{
  register long
    i;

  SignatureInfo
    signature_info;

  size_t
    hash;

  GetSignatureInfo(&signature_info);
  UpdateSignature(&signature_info,GetStringInfoDatum((const StringInfo *)
    string),GetStringInfoLength((const StringInfo *) string));
  FinalizeSignature(&signature_info);
  hash=0;
  for (i=0; i < 8; i++)
    hash^=signature_info.digest[i];
  return(hash);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   I n s e r t V a l u e I n L i n k e d L i s t                             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  InsertValueInLinkedList() inserts an element in the linked-list at the
%  specified location.
%
%  The format of the InsertValueInLinkedList method is:
%
%      MagickBooleanType InsertValueInLinkedList(ListInfo *list_info,
%        const unsigned long index,const void *value)
%
%  A description of each parameter follows:
%
%    o list_info: The hashmap info.
%
%    o index: The index.
%
%    o value: The value.
%
*/
MagickExport MagickBooleanType InsertValueInLinkedList(
  LinkedListInfo *list_info,const unsigned long index,const void *value)
{
  register ElementInfo
    *next;

  register long
    i;

  assert(list_info != (LinkedListInfo *) NULL);
  assert(list_info->signature == MagickSignature);
  if (list_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  if (value == (const void *) NULL)
    return(MagickFalse);
  if ((index > list_info->elements) ||
      (list_info->elements == list_info->capacity))
    return(MagickFalse);
  next=(ElementInfo *) AcquireMagickMemory(sizeof(*next));
  if (next == (ElementInfo *) NULL)
    return(MagickFalse);
  next->value=(void *) value;
  next->next=(ElementInfo *) NULL;
  AcquireSemaphoreInfo(&list_info->semaphore);
  if (list_info->elements == 0)
    {
      if (list_info->next == (ElementInfo *) NULL)
        list_info->next=next;
      list_info->head=next;
      list_info->tail=next;
    }
  else
    {
      if (index == 0)
        {
          if (list_info->next == list_info->head)
            list_info->next=next;
          next->next=list_info->head;
          list_info->head=next;
        }
      else
        if (index == list_info->elements)
          {
            if (list_info->next == (ElementInfo *) NULL)
              list_info->next=next;
            list_info->tail->next=next;
            list_info->tail=next;
          }
        else
          {
            ElementInfo
              *element;

            element=list_info->head;
            next->next=element->next;
            for (i=1; i < (long) index; i++)
            {
              element=element->next;
              next->next=element->next;
            }
            next=next->next;
            element->next=next;
            if (list_info->next == next->next)
              list_info->next=next;
          }
    }
  list_info->elements++;
  RelinquishSemaphoreInfo(list_info->semaphore);
  return(MagickTrue);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   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                 %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  InsertValueInSortedLinkedList() inserts a value in the sorted linked-list.
%
%  The format of the InsertValueInSortedLinkedList method is:
%
%      MagickBooleanType InsertValueInSortedLinkedList(ListInfo *list_info,
%        int (*compare)(const void *,const void *),void **replace,
%        const void *value)
%
%  A description of each parameter follows:
%
%    o list_info: The hashmap info.
%
%    o index: The index.
%
%    o compare: The compare method.
%
%    o replace: return previous element here.
%
%    o value: The value.
%
*/
MagickExport MagickBooleanType InsertValueInSortedLinkedList(
  LinkedListInfo *list_info,int (*compare)(const void *,const void *),
  void **replace,const void *value)
{
  ElementInfo
    *element;

  register ElementInfo
    *next;

  register long
    i;

  assert(list_info != (LinkedListInfo *) NULL);
  assert(list_info->signature == MagickSignature);
  if (list_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  if ((compare == (int (*)(const void *,const void *)) NULL) ||
      (value == (const void *) NULL))
    return(MagickFalse);
  if (list_info->elements == list_info->capacity)
    return(MagickFalse);
  next=(ElementInfo *) AcquireMagickMemory(sizeof(*next));
  if (next == (ElementInfo *) NULL)
    return(MagickFalse);
  next->value=(void *) value;
  element=(ElementInfo *) NULL;
  AcquireSemaphoreInfo(&list_info->semaphore);
  next->next=list_info->head;
  while (next->next != (ElementInfo *) NULL)
  {
    i=compare(value,next->next->value);
    if ((i < 0) || ((replace != (void **) NULL) && (i == 0)))
      {
        if (i == 0)
          {
            *replace=next->next->value;
            next->next=next->next->next;
            if (element != (ElementInfo *) NULL)
              element->next=(ElementInfo *) RelinquishMagickMemory(
                element->next);
            list_info->elements--;
          }
        if (element != (ElementInfo *) NULL)
          element->next=next;
        else
          list_info->head=next;
        break;
      }
    element=next->next;
    next->next=next->next->next;
  }
  if (next->next == (ElementInfo *) NULL)
    {
      if (element != (ElementInfo *) NULL)
        element->next=next;
      else
        list_info->head=next;
      list_info->tail=next;
    }
  list_info->elements++;
  RelinquishSemaphoreInfo(list_info->semaphore);
  return(MagickTrue);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   I s H a s h m a p E m p t y                                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  IsHashmapEmpty() returns MagickTrue if the hash-map is empty.
%
%  The format of the IsHashmapEmpty method is:
%
%      MagickBooleanType IsHashmapEmpty(const HashmapInfo *hashmap_info)
%
%  A description of each parameter follows:
%
%    o hashmap_info: The hashmap info.
%
*/
MagickExport MagickBooleanType IsHashmapEmpty(const HashmapInfo *hashmap_info)
{
  assert(hashmap_info != (HashmapInfo *) NULL);
  assert(hashmap_info->signature == MagickSignature);
  if (hashmap_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  return(hashmap_info->entries == 0 ? MagickTrue : MagickFalse);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   I s L i n k e d L i s t E m p t y                                         %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  IsLinkedListEmpty() returns MagickTrue if the linked-list is empty.
%
%  The format of the IsLinkedListEmpty method is:
%
%      MagickBooleanType IsLinkedListEmpty(LinkedListInfo *list_info)
%
%  A description of each parameter follows:
%
%    o list_info: The linked-list info.
%
*/
MagickExport MagickBooleanType IsLinkedListEmpty(
  const LinkedListInfo *list_info)
{
  assert(list_info != (LinkedListInfo *) NULL);
  assert(list_info->signature == MagickSignature);
  if (list_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  return(list_info->elements == 0 ? MagickTrue : MagickFalse);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   L i n k e d L i s t T o A r r a y                                         %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  LinkedListToArray() converts the linked-list to an array.
%
%  The format of the LinkedListToArray method is:
%
%      MagickBooleanType LinkedListToArray(LinkedListInfo *list_info,
%        void **array)
%
%  A description of each parameter follows:
%
%    o list_info: The linked-list info.
%
%    o array: The array.
%
*/
MagickExport MagickBooleanType LinkedListToArray(LinkedListInfo *list_info,
  void **array)
{
  register ElementInfo
    *next;

  register long
    i;

  assert(list_info != (LinkedListInfo *) NULL);
  assert(list_info->signature == MagickSignature);
  if (list_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  if (array == (void **) NULL)
    return(MagickFalse);
  AcquireSemaphoreInfo(&list_info->semaphore);
  next=list_info->head;
  for (i=0; next != (ElementInfo *) NULL; i++)
  {
    array[i]=next->value;
    next=next->next;
  }
  RelinquishSemaphoreInfo(list_info->semaphore);
  return(MagickTrue);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   N e w H a s h m a p                                                       %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  NewHashmap() returns a pointer to a HashmapInfo structure initialized
%  to default values.  The capacity is an initial estimate.  The hashmap will
%  increase capacity dynamically as the demand requires.
%
%  The format of the NewHashmap method is:
%
%      HashmapInfo *NewHashmap(const unsigned long capacity,
%        size_t (*hash)(const void *),
%        MagickBooleanType (*compare)(const void *,const void *),
%        void *(*relinquish_key)(void *),void *(*relinquish_value)(void *))
%
%  A description of each parameter follows:
%
%    o capacity: The initial number entries in the hash-map: typically
%      SmallHashmapSize, MediumHashmapSize, or LargeHashmapSize.  The
%      hashmap will dynamically increase its capacity on demand.
%
%    o hash: The hash method, typically HashPointerType(), HashStringType(),
%      or HashStringInfoType().
%
%    o compare: The compare method, typically NULL, CompareHashmapString(),
%      or CompareHashmapStringInfo().
%
%    o relinquish_key: The key deallocation method, typically
%      RelinquishMagickMemory(), called whenever a key is removed from the
%      hash-map.
%
%    o relinquish_value: The value deallocation method;  typically
%      RelinquishMagickMemory(), called whenever a value object is removed from
%      the hash-map.
%
*/
MagickExport HashmapInfo *NewHashmap(const unsigned long capacity,
  size_t (*hash)(const void *),
  MagickBooleanType (*compare)(const void *,const void *),
  void *(*relinquish_key)(void *),void *(*relinquish_value)(void *))
{
  HashmapInfo
    *hashmap_info;

  hashmap_info=(HashmapInfo *) AcquireMagickMemory(sizeof(*hashmap_info));
  if (hashmap_info == (HashmapInfo *) NULL)
    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
  (void) ResetMagickMemory(hashmap_info,0,sizeof(*hashmap_info));
  hashmap_info->hash=HashPointerType;
  if (hash != (size_t (*)(const void *)) NULL)
    hashmap_info->hash=hash;
  hashmap_info->compare=(MagickBooleanType (*)(const void *,const void *)) NULL;
  if (compare != (MagickBooleanType (*)(const void *,const void *)) NULL)
    hashmap_info->compare=compare;
  hashmap_info->relinquish_key=relinquish_key;
  hashmap_info->relinquish_value=relinquish_value;
  hashmap_info->entries=0;
  hashmap_info->capacity=capacity;
  hashmap_info->map=(LinkedListInfo **) NULL;
  if (~capacity >= 1UL)
    hashmap_info->map=(LinkedListInfo **) AcquireQuantumMemory((size_t)
      capacity+1UL,sizeof(*hashmap_info->map));
  if (hashmap_info->map == (LinkedListInfo **) NULL)
    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
  (void) ResetMagickMemory(hashmap_info->map,0,(size_t) capacity*
    sizeof(*hashmap_info->map));
  hashmap_info->debug=IsEventLogging();
  hashmap_info->semaphore=(SemaphoreInfo *) NULL;
  hashmap_info->signature=MagickSignature;
  return(hashmap_info);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   N e w L i n k e d L i s t I n f o                                         %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  NewLinkedList() returns a pointer to a LinkedListInfo structure
%  initialized to default values.
%
%  The format of the NewLinkedList method is:
%
%      LinkedListInfo *NewLinkedList(const unsigned long capacity)
%
%  A description of each parameter follows:
%
%    o capacity: The maximum number of elements in the list.
%
*/
MagickExport LinkedListInfo *NewLinkedList(const unsigned long capacity)
{
  LinkedListInfo
    *list_info;

  list_info=(LinkedListInfo *) AcquireMagickMemory(sizeof(*list_info));
  if (list_info == (LinkedListInfo *) NULL)
    ThrowFatalException(ResourceLimitFatalError,"MemoryAllocationFailed");
  (void) ResetMagickMemory(list_info,0,sizeof(*list_info));
  list_info->capacity=capacity == 0 ? (unsigned long) (~0) : capacity;
  list_info->elements=0;
  list_info->head=(ElementInfo *) NULL;
  list_info->tail=(ElementInfo *) NULL;
  list_info->next=(ElementInfo *) NULL;
  list_info->debug=MagickFalse;
  list_info->semaphore=(SemaphoreInfo *) NULL;
  list_info->signature=MagickSignature;
  return(list_info);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   P u t E n t r y I n H a s h m a p                                         %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  PutEntryInHashmap() puts an entry in the hash-map.  If the key already
%  exists in the map it is first removed.
%
%  The format of the PutEntryInHashmap method is:
%
%      MagickBooleanType PutEntryInHashmap(HashmapInfo *hashmap_info,
%        const void *key,const void *value)
%
%  A description of each parameter follows:
%
%    o hashmap_info: The hashmap info.
%
%    o key: The key.
%
%    o value: The value.
%
*/

static MagickBooleanType IncreaseHashmapCapacity(HashmapInfo *hashmap_info)
{
#define MaxCapacities  20

  const unsigned long
    capacities[MaxCapacities] =
    {
      17, 31, 61, 131, 257, 509, 1021, 2053, 4099, 8191, 16381, 32771,
      65537, 131071, 262147, 524287, 1048573, 2097143, 4194301, 8388617
    };

  ElementInfo
    *element;

  EntryInfo
    *entry;

  LinkedListInfo
    *list_info,
    *map_info,
    **map;

  register ElementInfo
    *next;

  register long
    i;

  unsigned long
    capacity;

  /*
    Increase to the next prime capacity.
  */
  for (i=0; i < MaxCapacities; i++)
    if (hashmap_info->capacity < capacities[i])
      break;
  if (i >= (MaxCapacities-1))
    return(MagickFalse);
  capacity=capacities[i+1];
  map=(LinkedListInfo **) AcquireQuantumMemory((size_t) capacity+1UL,
    sizeof(*map));
  if (map == (LinkedListInfo **) NULL)
    return(MagickFalse);
  (void) ResetMagickMemory(map,0,(size_t) capacity*sizeof(*map));
  /*
    Copy entries to new hashmap with increased capacity.
  */
  for (i=0; i < (long) hashmap_info->capacity; i++)
  {
    list_info=hashmap_info->map[i];
    if (list_info == (LinkedListInfo *) NULL)
      continue;
    AcquireSemaphoreInfo(&list_info->semaphore);
    for (next=list_info->head; next != (ElementInfo *) NULL; )
    {
      element=next;
      next=next->next;
      entry=(EntryInfo *) element->value;
      map_info=map[entry->hash % capacity];
      if (map_info == (LinkedListInfo *) NULL)
        {
          map_info=NewLinkedList(0);
          map[entry->hash % capacity]=map_info;
        }
      map_info->next=element;
      element->next=map_info->head;
      map_info->head=element;
      map_info->elements++;
    }
    list_info->signature=(~MagickSignature);
    RelinquishSemaphoreInfo(list_info->semaphore);
    list_info->semaphore=DestroySemaphoreInfo(list_info->semaphore);
    list_info=(LinkedListInfo *) RelinquishMagickMemory(list_info);
  }
  hashmap_info->map=(LinkedListInfo **) RelinquishMagickMemory(
    hashmap_info->map);
  hashmap_info->map=map;
  hashmap_info->capacity=capacity;
  return(MagickTrue);
}

MagickExport MagickBooleanType PutEntryInHashmap(HashmapInfo *hashmap_info,
  const void *key,const void *value)
{
  EntryInfo
    *entry,
    *next;

  LinkedListInfo
    *list_info;

  register unsigned long
    i;

  assert(hashmap_info != (HashmapInfo *) NULL);
  assert(hashmap_info->signature == MagickSignature);
  if (hashmap_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  if ((key == (void *) NULL) || (value == (void *) NULL))
    return(MagickFalse);
  next=(EntryInfo *) AcquireMagickMemory(sizeof(*next));
  if (next == (EntryInfo *) NULL)
    return(MagickFalse);
  AcquireSemaphoreInfo(&hashmap_info->semaphore);
  next->hash=hashmap_info->hash(key);
  next->key=(void *) key;
  next->value=(void *) value;
  list_info=hashmap_info->map[next->hash % hashmap_info->capacity];
  if (list_info == (LinkedListInfo *) NULL)
    {
      list_info=NewLinkedList(0);
      hashmap_info->map[next->hash % hashmap_info->capacity]=list_info;
    }
  else
    {
      list_info->next=list_info->head;
      entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
      for (i=0; entry != (EntryInfo *) NULL; i++)
      {
        if (entry->hash == next->hash)
          {
            MagickBooleanType
              compare;

            compare=MagickTrue;
            if (hashmap_info->compare !=
                (MagickBooleanType (*)(const void *,const void *)) NULL)
              compare=hashmap_info->compare(key,entry->key);
            if (compare == MagickTrue)
              {
                (void) RemoveElementFromLinkedList(list_info,i);
                if (hashmap_info->relinquish_key != (void *(*)(void *)) NULL)
                  entry->key=hashmap_info->relinquish_key(entry->key);
                if (hashmap_info->relinquish_value != (void *(*)(void *)) NULL)
                  entry->value=hashmap_info->relinquish_value(entry->value);
                entry=(EntryInfo *) RelinquishMagickMemory(entry);
                break;
              }
          }
        entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
      }
    }
  if (InsertValueInLinkedList(list_info,0,next) == MagickFalse)
    {
      next=(EntryInfo *) RelinquishMagickMemory(next);
      RelinquishSemaphoreInfo(hashmap_info->semaphore);
      return(MagickFalse);
    }
  if (list_info->elements >= (hashmap_info->capacity-1))
    if (IncreaseHashmapCapacity(hashmap_info) == MagickFalse)
      {
        RelinquishSemaphoreInfo(hashmap_info->semaphore);
        return(MagickFalse);
      }
  hashmap_info->entries++;
  RelinquishSemaphoreInfo(hashmap_info->semaphore);
  return(MagickTrue);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   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       %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  RemoveElementByValueFromLinkedList() removes an element from the linked-list
%  by value.
%
%  The format of the RemoveElementByValueFromLinkedList method is:
%
%      void *RemoveElementByValueFromLinkedList(LinkedListInfo *list_info,
%        const void *value)
%
%  A description of each parameter follows:
%
%    o list_info: The list info.
%
%    o value: The value.
%
*/
MagickExport void *RemoveElementByValueFromLinkedList(LinkedListInfo *list_info,
  const void *value)
{
  ElementInfo
    *next;

  assert(list_info != (LinkedListInfo *) NULL);
  assert(list_info->signature == MagickSignature);
  if (list_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  if ((list_info->elements == 0) || (value == (const void *) NULL))
    return((void *) NULL);
  AcquireSemaphoreInfo(&list_info->semaphore);
  if (value == list_info->head->value)
    {
      if (list_info->next == list_info->head)
        list_info->next=list_info->head->next;
      next=list_info->head;
      list_info->head=list_info->head->next;
      next=(ElementInfo *) RelinquishMagickMemory(next);
    }
  else
    {
      ElementInfo
        *element;

      next=list_info->head;
      while ((next->next != (ElementInfo *) NULL) &&
             (next->next->value != value))
        next=next->next;
      if (next->next == (ElementInfo *) NULL)
        {
          RelinquishSemaphoreInfo(list_info->semaphore);
          return((void *) NULL);
        }
      element=next->next;
      next->next=element->next;
      if (element == list_info->tail)
        list_info->tail=next;
      if (list_info->next == element)
        list_info->next=element->next;
      element=(ElementInfo *) RelinquishMagickMemory(element);
    }
  list_info->elements--;
  RelinquishSemaphoreInfo(list_info->semaphore);
  return((void *) value);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   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                     %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  RemoveElementFromLinkedList() removes an element from the linked-list at the
%  specified location.
%
%  The format of the RemoveElementFromLinkedList method is:
%
%      void *RemoveElementFromLinkedList(LinkedListInfo *list_info,
%        const unsigned long index)
%
%  A description of each parameter follows:
%
%    o list_info: The linked-list info.
%
%    o index: The index.
%
*/
MagickExport void *RemoveElementFromLinkedList(LinkedListInfo *list_info,
  const unsigned long index)
{
  ElementInfo
    *next;

  register long
    i;

  void
    *value;

  assert(list_info != (LinkedListInfo *) NULL);
  assert(list_info->signature == MagickSignature);
  if (list_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  if (index >= list_info->elements)
    return((void *) NULL);
  AcquireSemaphoreInfo(&list_info->semaphore);
  if (index == 0)
    {
      if (list_info->next == list_info->head)
        list_info->next=list_info->head->next;
      value=list_info->head->value;
      next=list_info->head;
      list_info->head=list_info->head->next;
      next=(ElementInfo *) RelinquishMagickMemory(next);
    }
  else
    {
      ElementInfo
        *element;

      next=list_info->head;
      for (i=1; i < (long) index; i++)
        next=next->next;
      element=next->next;
      next->next=element->next;
      if (element == list_info->tail)
        list_info->tail=next;
      if (list_info->next == element)
        list_info->next=element->next;
      value=element->value;
      element=(ElementInfo *) RelinquishMagickMemory(element);
    }
  list_info->elements--;
  RelinquishSemaphoreInfo(list_info->semaphore);
  return(value);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   R e m o v e E n t r y F r o m H a s h m a p                               %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  RemoveEntryFromHashmap() removes an entry from the hash-map by its key.
%
%  The format of the RemoveEntryFromHashmap method is:
%
%      void *RemoveEntryFromHashmap(HashmapInfo *hashmap_info,void *key)
%
%  A description of each parameter follows:
%
%    o hashmap_info: The hashmap info.
%
%    o key: The key.
%
*/
MagickExport void *RemoveEntryFromHashmap(HashmapInfo *hashmap_info,
  const void *key)
{
  EntryInfo
    *entry;

  LinkedListInfo
    *list_info;

  register unsigned long
    i;

  size_t
    hash;

  void
    *value;

  assert(hashmap_info != (HashmapInfo *) NULL);
  assert(hashmap_info->signature == MagickSignature);
  if (hashmap_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  if (key == (const void *) NULL)
    return((void *) NULL);
  AcquireSemaphoreInfo(&hashmap_info->semaphore);
  hash=hashmap_info->hash(key);
  list_info=hashmap_info->map[hash % hashmap_info->capacity];
  if (list_info != (LinkedListInfo *) NULL)
    {
      list_info->next=list_info->head;
      entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
      for (i=0; entry != (EntryInfo *) NULL; i++)
      {
        if (entry->hash == hash)
          {
            MagickBooleanType
              compare;

            compare=MagickTrue;
            if (hashmap_info->compare !=
                (MagickBooleanType (*)(const void *,const void *)) NULL)
              compare=hashmap_info->compare(key,entry->key);
            if (compare == MagickTrue)
              {
                entry=(EntryInfo *) RemoveElementFromLinkedList(list_info,i);
                if (entry == (EntryInfo *) NULL)
                  {
                    RelinquishSemaphoreInfo(hashmap_info->semaphore);
                    return((void *) NULL);
                  }
                if (hashmap_info->relinquish_key != (void *(*)(void *)) NULL)
                  entry->key=hashmap_info->relinquish_key(entry->key);
                value=entry->value;
                entry=(EntryInfo *) RelinquishMagickMemory(entry);
                hashmap_info->entries--;
                RelinquishSemaphoreInfo(hashmap_info->semaphore);
                return(value);
              }
          }
        entry=(EntryInfo *) GetNextValueInLinkedList(list_info);
      }
    }
  RelinquishSemaphoreInfo(hashmap_info->semaphore);
  return((void *) NULL);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   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             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  RemoveLastElementFromLinkedList() removes the last element from the
%  linked-list.
%
%  The format of the RemoveLastElementFromLinkedList method is:
%
%      void *RemoveLastElementFromLinkedList(LinkedListInfo *list_info)
%
%  A description of each parameter follows:
%
%    o list_info: The linked-list info.
%
*/
MagickExport void *RemoveLastElementFromLinkedList(LinkedListInfo *list_info)
{
  void
    *value;

  assert(list_info != (LinkedListInfo *) NULL);
  assert(list_info->signature == MagickSignature);
  if (list_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  if (list_info->elements == 0)
    return((void *) NULL);
  AcquireSemaphoreInfo(&list_info->semaphore);
  if (list_info->next == list_info->tail)
    list_info->next=(ElementInfo *) NULL;
  if (list_info->elements == 1UL)
    {
      value=list_info->head->value;
      list_info->head=(ElementInfo *) NULL;
      list_info->tail=(ElementInfo *) RelinquishMagickMemory(list_info->tail);
    }
  else
    {
      ElementInfo
        *next;

      value=list_info->tail->value;
      next=list_info->head;
      while (next->next != list_info->tail)
        next=next->next;
      list_info->tail=(ElementInfo *) RelinquishMagickMemory(list_info->tail);
      list_info->tail=next;
      next->next=(ElementInfo *) NULL;
    }
  list_info->elements--;
  RelinquishSemaphoreInfo(list_info->semaphore);
  return(value);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   R e s e t H a s h m a p I t e r a t o r                                   %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  ResetHashmapIterator() resets the hash-map iterator.  Use it in conjunction
%  with GetNextKeyInHashmap() to iterate over all the keys in the hash-map.
%
%  The format of the ResetHashmapIterator method is:
%
%      ResetHashmapIterator(HashmapInfo *hashmap_info)
%
%  A description of each parameter follows:
%
%    o hashmap_info: The hashmap info.
%
*/
MagickExport void ResetHashmapIterator(HashmapInfo *hashmap_info)
{
  assert(hashmap_info != (HashmapInfo *) NULL);
  assert(hashmap_info->signature == MagickSignature);
  if (hashmap_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  AcquireSemaphoreInfo(&hashmap_info->semaphore);
  hashmap_info->next=0;
  hashmap_info->head_of_list=MagickFalse;
  RelinquishSemaphoreInfo(hashmap_info->semaphore);
}

/*
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%                                                                             %
%                                                                             %
%                                                                             %
%   R e s e t L i n k e d L i s t I t e r a t o r                             %
%                                                                             %
%                                                                             %
%                                                                             %
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
%  ResetLinkedListIterator() resets the lined-list iterator.  Use it in
%  conjunction with GetNextValueInLinkedList() to iterate over all the values
%  in the linked-list.
%
%  The format of the ResetLinkedListIterator method is:
%
%      ResetLinkedListIterator(LinkedListInfo *list_info)
%
%  A description of each parameter follows:
%
%    o list_info: The linked-list info.
%
*/
MagickExport void ResetLinkedListIterator(LinkedListInfo *list_info)
{
  assert(list_info != (LinkedListInfo *) NULL);
  assert(list_info->signature == MagickSignature);
  if (list_info->debug != MagickFalse)
    (void) LogMagickEvent(TraceEvent,GetMagickModule(),"...");
  AcquireSemaphoreInfo(&list_info->semaphore);
  list_info->next=list_info->head;
  RelinquishSemaphoreInfo(list_info->semaphore);
}

Bell Labs OSI certified Powered by Plan 9

(Return to Plan 9 Home Page)

Copyright © 2021 Plan 9 Foundation. All Rights Reserved.
Comments to webmaster@9p.io.