/* do not edit automatically generated by mc from Indexing.  */
/* Indexing.mod provides a dynamic indexing mechanism for CARDINAL.

Copyright (C) 2003-2025 Free Software Foundation, Inc.
Contributed by Gaius Mulley <gaius.mulley@southwales.ac.uk>.

This file is part of GNU Modula-2.

GNU Modula-2 is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.

GNU Modula-2 is distributed in the hope that it will be useful, but
WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
General Public License for more details.

Under Section 7 of GPL version 3, you are granted additional
permissions described in the GCC Runtime Library Exception, version
3.1, as published by the Free Software Foundation.

You should have received a copy of the GNU General Public License and
a copy of the GCC Runtime Library Exception along with this program;
see the files COPYING3 and COPYING.RUNTIME respectively.  If not, see
<http://www.gnu.org/licenses/>.  */

#include <stdbool.h>
#   if !defined (PROC_D)
#      define PROC_D
       typedef void (*PROC_t) (void);
       typedef struct { PROC_t proc; } PROC;
#   endif

#   if !defined (TRUE)
#      define TRUE (1==1)
#   endif

#   if !defined (FALSE)
#      define FALSE (1==0)
#   endif

#include <stddef.h>
#include <stdlib.h>
#   include "GStorage.h"
#   include "Gmcrts.h"
#if defined(__cplusplus)
#   undef NULL
#   define NULL 0
#endif
#define _Indexing_C

#include "GIndexing.h"
#   include "Glibc.h"
#   include "GStorage.h"
#   include "GSYSTEM.h"
#   include "GM2RTS.h"

typedef struct Indexing_IndexProcedure_p Indexing_IndexProcedure;

#   define MinSize 128
#   define DefaultGrowFactor 2
typedef struct Indexing__T2_r Indexing__T2;

typedef void * *Indexing_PtrToAddress;

typedef unsigned char *Indexing_PtrToByte;

typedef Indexing__T2 *Indexing_Index__opaque;

struct Indexing__T2_r {
                        void *ArrayStart;
                        unsigned int ArraySize;
                        unsigned int Used;
                        unsigned int Low;
                        unsigned int High;
                        bool Debug;
                        unsigned int Map;
                        unsigned int GrowFactor;
                      };


/*
   InitIndexTuned - creates a dynamic array with low indice.
                    The minsize is the initial number of elements the
                    array is allocated and growfactor determines how
                    it will be resized once it becomes full.
*/

extern "C" Indexing_Index Indexing_InitIndexTuned (unsigned int low, unsigned int minsize, unsigned int growfactor);

/*
   InitIndex - creates and returns an Index.
*/

extern "C" Indexing_Index Indexing_InitIndex (unsigned int low);

/*
   KillIndex - returns Index to free storage.
*/

extern "C" Indexing_Index Indexing_KillIndex (Indexing_Index i);

/*
   DebugIndex - turns on debugging within an index.
*/

extern "C" Indexing_Index Indexing_DebugIndex (Indexing_Index i);

/*
   InBounds - returns TRUE if indice, n, is within the bounds
              of the dynamic array.
*/

extern "C" bool Indexing_InBounds (Indexing_Index i, unsigned int n);

/*
   HighIndice - returns the last legally accessible indice of this array.
*/

extern "C" unsigned int Indexing_HighIndice (Indexing_Index i);

/*
   LowIndice - returns the first legally accessible indice of this array.
*/

extern "C" unsigned int Indexing_LowIndice (Indexing_Index i);

/*
   PutIndice - places, a, into the dynamic array at position i[n]
*/

extern "C" void Indexing_PutIndice (Indexing_Index i, unsigned int n, void * a);

/*
   GetIndice - retrieves, element i[n] from the dynamic array.
*/

extern "C" void * Indexing_GetIndice (Indexing_Index i, unsigned int n);

/*
   IsIndiceInIndex - returns TRUE if, a, is in the index, i.
*/

extern "C" bool Indexing_IsIndiceInIndex (Indexing_Index i, void * a);

/*
   RemoveIndiceFromIndex - removes, a, from Index, i.
*/

extern "C" void Indexing_RemoveIndiceFromIndex (Indexing_Index i, void * a);

/*
   DeleteIndice - delete i[j] from the array.
*/

extern "C" void Indexing_DeleteIndice (Indexing_Index i, unsigned int j);

/*
   IncludeIndiceIntoIndex - if the indice is not in the index, then
                            add it at the end.
*/

extern "C" void Indexing_IncludeIndiceIntoIndex (Indexing_Index i, void * a);

/*
   ForeachIndiceInIndexDo - for each j indice of i, call procedure p(i[j])
*/

extern "C" void Indexing_ForeachIndiceInIndexDo (Indexing_Index i, Indexing_IndexProcedure p);

/*
   IsEmpty - return TRUE if the array has no entries it.
*/

extern "C" bool Indexing_IsEmpty (Indexing_Index i);

/*
   FindIndice - returns the indice containing a.
                It returns zero if a is not found in array i.
*/

extern "C" unsigned int Indexing_FindIndice (Indexing_Index i, void * a);


/*
   InitIndexTuned - creates a dynamic array with low indice.
                    The minsize is the initial number of elements the
                    array is allocated and growfactor determines how
                    it will be resized once it becomes full.
*/

extern "C" Indexing_Index Indexing_InitIndexTuned (unsigned int low, unsigned int minsize, unsigned int growfactor)
{
  Indexing_Index__opaque i;

  Storage_ALLOCATE ((void **) &i, sizeof (Indexing__T2));
  i->Low = low;
  i->High = 0;
  i->ArraySize = minsize*sizeof (void *);
  Storage_ALLOCATE (&i->ArrayStart, i->ArraySize);
  i->ArrayStart = libc_memset (i->ArrayStart, 0, static_cast<size_t> (i->ArraySize));
  i->Debug = false;
  i->Used = 0;
  i->Map = (unsigned int) 0;
  i->GrowFactor = growfactor;
  return static_cast<Indexing_Index> (i);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   InitIndex - creates and returns an Index.
*/

extern "C" Indexing_Index Indexing_InitIndex (unsigned int low)
{
  return Indexing_InitIndexTuned (low, MinSize, DefaultGrowFactor);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   KillIndex - returns Index to free storage.
*/

extern "C" Indexing_Index Indexing_KillIndex (Indexing_Index i)
{
  Storage_DEALLOCATE (&static_cast<Indexing_Index__opaque> (i)->ArrayStart, static_cast<Indexing_Index__opaque> (i)->ArraySize);
  Storage_DEALLOCATE ((void **) &i, sizeof (Indexing__T2));
  return static_cast<Indexing_Index> (NULL);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   DebugIndex - turns on debugging within an index.
*/

extern "C" Indexing_Index Indexing_DebugIndex (Indexing_Index i)
{
  static_cast<Indexing_Index__opaque> (i)->Debug = true;
  return i;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   InBounds - returns TRUE if indice, n, is within the bounds
              of the dynamic array.
*/

extern "C" bool Indexing_InBounds (Indexing_Index i, unsigned int n)
{
  if (i == NULL)
    {
      M2RTS_HALT (-1);
      __builtin_unreachable ();
    }
  else
    {
      return (n >= static_cast<Indexing_Index__opaque> (i)->Low) && (n <= static_cast<Indexing_Index__opaque> (i)->High);
    }
  ReturnException ("../../gcc/m2/gm2-libs/Indexing.def", 25, 1);
  __builtin_unreachable ();
}


/*
   HighIndice - returns the last legally accessible indice of this array.
*/

extern "C" unsigned int Indexing_HighIndice (Indexing_Index i)
{
  if (i == NULL)
    {
      M2RTS_HALT (-1);
      __builtin_unreachable ();
    }
  else
    {
      return static_cast<Indexing_Index__opaque> (i)->High;
    }
  ReturnException ("../../gcc/m2/gm2-libs/Indexing.def", 25, 1);
  __builtin_unreachable ();
}


/*
   LowIndice - returns the first legally accessible indice of this array.
*/

extern "C" unsigned int Indexing_LowIndice (Indexing_Index i)
{
  if (i == NULL)
    {
      M2RTS_HALT (-1);
      __builtin_unreachable ();
    }
  else
    {
      return static_cast<Indexing_Index__opaque> (i)->Low;
    }
  ReturnException ("../../gcc/m2/gm2-libs/Indexing.def", 25, 1);
  __builtin_unreachable ();
}


/*
   PutIndice - places, a, into the dynamic array at position i[n]
*/

extern "C" void Indexing_PutIndice (Indexing_Index i, unsigned int n, void * a)
{
  typedef unsigned int * *PutIndice__T1;

  unsigned int oldSize;
  void * b;
  PutIndice__T1 p;

  if (! (Indexing_InBounds (i, n)))
    {
      /* avoid gcc warning by using compound statement even if not strictly necessary.  */
      if (n < static_cast<Indexing_Index__opaque> (i)->Low)
        {
          M2RTS_HALT (-1);
          __builtin_unreachable ();
        }
      else
        {
          oldSize = static_cast<Indexing_Index__opaque> (i)->ArraySize;
          while (((n-static_cast<Indexing_Index__opaque> (i)->Low)*sizeof (void *)) >= static_cast<Indexing_Index__opaque> (i)->ArraySize)
            {
              static_cast<Indexing_Index__opaque> (i)->ArraySize = static_cast<Indexing_Index__opaque> (i)->ArraySize*static_cast<Indexing_Index__opaque> (i)->GrowFactor;
            }
          if (oldSize != static_cast<Indexing_Index__opaque> (i)->ArraySize)
            {
              /*
               IF Debug
               THEN
                  printf2('increasing memory hunk from %d to %d
              ',
                          oldSize, ArraySize)
               END ;
  */
              Storage_REALLOCATE (&static_cast<Indexing_Index__opaque> (i)->ArrayStart, static_cast<Indexing_Index__opaque> (i)->ArraySize);
              /* and initialize the remainder of the array to NIL  */
              b = static_cast<Indexing_Index__opaque> (i)->ArrayStart;
              b = reinterpret_cast<void *> (reinterpret_cast<char *> (b)+oldSize);
              b = libc_memset (b, 0, static_cast<size_t> (static_cast<Indexing_Index__opaque> (i)->ArraySize-oldSize));
            }
          static_cast<Indexing_Index__opaque> (i)->High = n;
        }
    }
  b = static_cast<Indexing_Index__opaque> (i)->ArrayStart;
  b = reinterpret_cast<void *> (reinterpret_cast<char *> (b)+(n-static_cast<Indexing_Index__opaque> (i)->Low)*sizeof (void *));
  p = static_cast<PutIndice__T1> (b);
  (*p) = static_cast<unsigned int *> (a);
  static_cast<Indexing_Index__opaque> (i)->Used += 1;
  if (static_cast<Indexing_Index__opaque> (i)->Debug)
    {
      if (n < 32)
        {
          static_cast<Indexing_Index__opaque> (i)->Map |= (1 << (n ));
        }
    }
}


/*
   GetIndice - retrieves, element i[n] from the dynamic array.
*/

extern "C" void * Indexing_GetIndice (Indexing_Index i, unsigned int n)
{
  Indexing_PtrToByte b;
  Indexing_PtrToAddress p;

  if (! (Indexing_InBounds (i, n)))
    {
      M2RTS_HALT (-1);
      __builtin_unreachable ();
    }
  b = static_cast<Indexing_PtrToByte> (static_cast<Indexing_Index__opaque> (i)->ArrayStart);
  b += (n-static_cast<Indexing_Index__opaque> (i)->Low)*sizeof (void *);
  p = (Indexing_PtrToAddress) (b);
  if (static_cast<Indexing_Index__opaque> (i)->Debug)
    {
      if (((n < 32) && (! ((((1 << (n)) & (static_cast<Indexing_Index__opaque> (i)->Map)) != 0)))) && ((*p) != NULL))
        {
          M2RTS_HALT (-1);
          __builtin_unreachable ();
        }
    }
  return (*p);
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   IsIndiceInIndex - returns TRUE if, a, is in the index, i.
*/

extern "C" bool Indexing_IsIndiceInIndex (Indexing_Index i, void * a)
{
  unsigned int j;
  Indexing_PtrToByte b;
  Indexing_PtrToAddress p;

  j = static_cast<Indexing_Index__opaque> (i)->Low;
  b = static_cast<Indexing_PtrToByte> (static_cast<Indexing_Index__opaque> (i)->ArrayStart);
  while (j <= static_cast<Indexing_Index__opaque> (i)->High)
    {
      p = (Indexing_PtrToAddress) (b);
      if ((*p) == a)
        {
          return true;
        }
      /* we must not INC(p, ..) as p2c gets confused  */
      b += sizeof (void *);
      j += 1;
    }
  return false;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   RemoveIndiceFromIndex - removes, a, from Index, i.
*/

extern "C" void Indexing_RemoveIndiceFromIndex (Indexing_Index i, void * a)
{
  unsigned int j;
  Indexing_PtrToAddress p;
  Indexing_PtrToByte b;

  j = static_cast<Indexing_Index__opaque> (i)->Low;
  b = static_cast<Indexing_PtrToByte> (static_cast<Indexing_Index__opaque> (i)->ArrayStart);
  while (j <= static_cast<Indexing_Index__opaque> (i)->High)
    {
      p = (Indexing_PtrToAddress) (b);
      b += sizeof (void *);
      if ((*p) == a)
        {
          Indexing_DeleteIndice (i, j);
        }
      j += 1;
    }
}


/*
   DeleteIndice - delete i[j] from the array.
*/

extern "C" void Indexing_DeleteIndice (Indexing_Index i, unsigned int j)
{
  Indexing_PtrToAddress p;
  Indexing_PtrToByte b;

  if (Indexing_InBounds (i, j))
    {
      b = static_cast<Indexing_PtrToByte> (static_cast<Indexing_Index__opaque> (i)->ArrayStart);
      b += sizeof (void *)*(j-static_cast<Indexing_Index__opaque> (i)->Low);
      p = (Indexing_PtrToAddress) (b);
      b += sizeof (void *);
      p = static_cast<Indexing_PtrToAddress> (libc_memmove (reinterpret_cast <void *> (p), reinterpret_cast <void *> (b), static_cast<size_t> ((static_cast<Indexing_Index__opaque> (i)->High-j)*sizeof (void *))));
      static_cast<Indexing_Index__opaque> (i)->High -= 1;
      static_cast<Indexing_Index__opaque> (i)->Used -= 1;
    }
  else
    {
      M2RTS_HALT (-1);
      __builtin_unreachable ();
    }
}


/*
   IncludeIndiceIntoIndex - if the indice is not in the index, then
                            add it at the end.
*/

extern "C" void Indexing_IncludeIndiceIntoIndex (Indexing_Index i, void * a)
{
  if (! (Indexing_IsIndiceInIndex (i, a)))
    {
      /* avoid gcc warning by using compound statement even if not strictly necessary.  */
      if (static_cast<Indexing_Index__opaque> (i)->Used == 0)
        {
          Indexing_PutIndice (i, Indexing_LowIndice (i), a);
        }
      else
        {
          Indexing_PutIndice (i, (Indexing_HighIndice (i))+1, a);
        }
    }
}


/*
   ForeachIndiceInIndexDo - for each j indice of i, call procedure p(i[j])
*/

extern "C" void Indexing_ForeachIndiceInIndexDo (Indexing_Index i, Indexing_IndexProcedure p)
{
  unsigned int j;

  j = Indexing_LowIndice (i);
  while (j <= (Indexing_HighIndice (i)))
    {
      (*p.proc) (Indexing_GetIndice (i, j));
      j += 1;
    }
}


/*
   IsEmpty - return TRUE if the array has no entries it.
*/

extern "C" bool Indexing_IsEmpty (Indexing_Index i)
{
  return static_cast<Indexing_Index__opaque> (i)->Used == 0;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}


/*
   FindIndice - returns the indice containing a.
                It returns zero if a is not found in array i.
*/

extern "C" unsigned int Indexing_FindIndice (Indexing_Index i, void * a)
{
  unsigned int j;
  Indexing_PtrToAddress p;
  Indexing_PtrToByte b;

  j = static_cast<Indexing_Index__opaque> (i)->Low;
  b = static_cast<Indexing_PtrToByte> (static_cast<Indexing_Index__opaque> (i)->ArrayStart);
  while (j <= static_cast<Indexing_Index__opaque> (i)->High)
    {
      p = (Indexing_PtrToAddress) (b);
      b += sizeof (void *);
      if ((*p) == a)
        {
          return j;
        }
      j += 1;
    }
  return 0;
  /* static analysis guarentees a RETURN statement will be used before here.  */
  __builtin_unreachable ();
}

extern "C" void _M2_Indexing_init (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
}

extern "C" void _M2_Indexing_fini (__attribute__((unused)) int argc,__attribute__((unused)) char *argv[],__attribute__((unused)) char *envp[])
{
}