<commit_before>/*  Part of SWI-Prolog

    Author:        <NAME>
    E-mail:        <EMAIL>
    WWW:           http://www.swi-prolog.org
    Copyright (C): 2013, VU University Amsterdam

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

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "pl-incl.h"

int PL_get_map_ex(term_t data, term_t class, term_t map);

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Maps are associative arrays,  where  keys   are  either  atoms  or small
integers. Maps should be considered  an   abstract  data  type. They are
currently represented as compound terms   using the functor `map`/Arity.
The term has the following layout on the global stack:

  -----------
  | `map`/A |
  -----------
  | class   |
  -----------
  | key1    |
  -----------
  | value1  |
  -----------
  | key2    |
  -----------
  | value2  |
      ...

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#define CACHED_MAP_FUNCTORS 128

static functor_t map_functors[CACHED_MAP_FUNCTORS] = {0};

static functor_t
map_functor(int arity)
{ if ( arity < CACHED_MAP_FUNCTORS )
  { if ( map_functors[arity] )
      return map_functors[arity];

    map_functors[arity] = lookupFunctorDef(ATOM_map, arity);
    return map_functors[arity];
  } else
  { return lookupFunctorDef(ATOM_map, arity);
  }
}


static int
get_map_ex(term_t t, Word mp, int create ARG_LD)
{ Word p = valTermRef(t);

  deRef(p);
  if ( isTerm(*p) )
  { Functor f = valueTerm(*p);
    FunctorDef fd = valueFunctor(f->definition);

    if ( fd->name == ATOM_map &&
	 fd->arity%2 == 1 )		/* does *not* validate ordering */
    { *mp = *p;
      return TRUE;
    }
  }

  if ( create )
  { term_t new;

    if ( (new = PL_new_term_ref()) &&
	  PL_get_map_ex(t, 0, new) )
    { p = valTermRef(new);
      deRef(p);
      *mp = *p;
      return TRUE;
    }

    return FALSE;
  }

  return PL_type_error("map", t);
}


static inline int
is_key(word w)
{ return isAtom(w) || isTaggedInt(w);
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
map_lookup_ptr() returns a pointer to the value for a given key
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

Word
map_lookup_ptr(word map, word name ARG_LD)
{ Functor data = valueTerm(map);
  int arity = arityFunctor(data->definition);
  int l = 1, h = arity-2;		/* odd numbers are the keys */

  assert(arity%2 == 1);

  for(;;)
  { int m = ((l+h)/2)|0x1;
    Word p;

    deRef2(&data->arguments[m], p);
    if ( *p == name )
      return p+1;

    if ( l == h )
      return NULL;

    if ( *p < name )
      l=m;
    else if ( h > m )
      h=m;
    else
      h=m-2;
  }
}


static int
compare_map_entry(const void *a, const void *b)
{ GET_LD				/* painful */
  Word p = (Word)a;
  Word q = (Word)b;

  deRef(p);
  deRef(q);
  return (*p<*q ? -1 : *p>*q ? 1 : 0);
}


static int
map_ordered(Word data, int count ARG_LD)
{ Word n1, n2;

  deRef2(data, n1);
  for(; count > 1; count--, data += 2, n1=n2)
  { deRef2(data+2, n2);
    if ( *n1 >= *n2 )
      return FALSE;
  }

  return TRUE;
}


static int
map_order(Word map ARG_LD)
{ Functor data = (Functor)map;
  int arity = arityFunctor(data->definition);

  assert(arity%2 == 1);

  qsort(data->arguments+1, arity/2, sizeof(word)*2,
	compare_map_entry);

  return map_ordered(data->arguments+1, arity/2 PASS_LD);
}


int
map_put(word map, int size, Word nv, word *new_map ARG_LD)
{ Functor data = valueTerm(map);
  int arity = arityFunctor(data->definition);<commit_msg>Check that all keys in the map are proper keys<commit_after>/*  Part of SWI-Prolog

    Author:        <NAME>
    E-mail:        <EMAIL>
    WWW:           http://www.swi-prolog.org
    Copyright (C): 2013, VU University Amsterdam

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

    This library 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
    Lesser General Public License for more details.

    You should have received a copy of the GNU Lesser General Public
    License along with this library; if not, write to the Free Software
    Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
*/

#include "pl-incl.h"

int PL_get_map_ex(term_t data, term_t class, term_t map);

/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
Maps are associative arrays,  where  keys   are  either  atoms  or small
integers. Maps should be considered  an   abstract  data  type. They are
currently represented as compound terms   using the functor `map`/Arity.
The term has the following layout on the global stack:

  -----------
  | `map`/A |
  -----------
  | class   |
  -----------
  | key1    |
  -----------
  | value1  |
  -----------
  | key2    |
  -----------
  | value2  |
      ...

- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

#define CACHED_MAP_FUNCTORS 128

static functor_t map_functors[CACHED_MAP_FUNCTORS] = {0};

static functor_t
map_functor(int arity)
{ if ( arity < CACHED_MAP_FUNCTORS )
  { if ( map_functors[arity] )
      return map_functors[arity];

    map_functors[arity] = lookupFunctorDef(ATOM_map, arity);
    return map_functors[arity];
  } else
  { return lookupFunctorDef(ATOM_map, arity);
  }
}


static int
get_map_ex(term_t t, Word mp, int create ARG_LD)
{ Word p = valTermRef(t);

  deRef(p);
  if ( isTerm(*p) )
  { Functor f = valueTerm(*p);
    FunctorDef fd = valueFunctor(f->definition);

    if ( fd->name == ATOM_map &&
	 fd->arity%2 == 1 )		/* does *not* validate ordering */
    { *mp = *p;
      return TRUE;
    }
  }

  if ( create )
  { term_t new;

    if ( (new = PL_new_term_ref()) &&
	  PL_get_map_ex(t, 0, new) )
    { p = valTermRef(new);
      deRef(p);
      *mp = *p;
      return TRUE;
    }

    return FALSE;
  }

  return PL_type_error("map", t);
}


static inline int
is_key(word w)
{ return isAtom(w) || isTaggedInt(w);
}


/* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
map_lookup_ptr() returns a pointer to the value for a given key
- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - */

Word
map_lookup_ptr(word map, word name ARG_LD)
{ Functor data = valueTerm(map);
  int arity = arityFunctor(data->definition);
  int l = 1, h = arity-2;		/* odd numbers are the keys */

  assert(arity%2 == 1);

  for(;;)
  { int m = ((l+h)/2)|0x1;
    Word p;

    deRef2(&data->arguments[m], p);
    if ( *p == name )
      return p+1;

    if ( l == h )
      return NULL;

    if ( *p < name )
      l=m;
    else if ( h > m )
      h=m;
    else
      h=m-2;
  }
}


static int
compare_map_entry(const void *a, const void *b)
{ GET_LD				/* painful */
  Word p = (Word)a;
  Word q = (Word)b;

  deRef(p);
  deRef(q);
  return (*p<*q ? -1 : *p>*q ? 1 : 0);
}


/* True if the keys are proper keys and ordered.
*/

static int
map_ordered(Word data, int count ARG_LD)
{ Word n1, n2;

  deRef2(data, n1);
  if ( !is_key(*n1) )
    return FALSE;
  for(; count > 1; count--, data += 2, n1=n2)
  { deRef2(data+2, n2);
    if ( !is_key(*n2) )
      return FALSE;
    if ( *n1 >= *n2 )
      return FALSE;
  }

  return TRUE;
}


static int
map_order(Word map ARG_LD)
{ Functor data = (Functor)map;
  int arity = arityFunctor(data->definition);

  assert(arity%2 == 1);

  qsort(data->arguments+1, arity/2, sizeof(word)*2,
	compare_map_entry);

  return map_ordered(data->arguments+1, arity/2 PASS_LD);
}


int
map_put(word map, int size, Word nv, word *new_map ARG_LD)
{ Functor data = valueTerm(map);
  int arity = arityFunctor(data->definition);
{'fraction_non_alphanumeric': 0.1577906976744186, 'fraction_numerical': 0.01441860465116279, 'mean_word_length': 2.079484425349087, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 33, 'https://': 0, 'lorem ipsum': 0, 'www.': 2, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 48, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '3893436', 'n_tokens_mistral': 3283, 'n_tokens_neox': 3164, 'n_words': 889}