<commit_before>/*
Copyright: <NAME>, 2017-2018
License: MIT
*/

/**
This facil.io core library provides wrappers around complex and (or) dynamic
types, abstracting some complexity and making dynamic type related tasks easier.
*/
#include "fiobject.h"

#include "fio_ary.h"

#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

/* *****************************************************************************
the `fiobj_each2` function
***************************************************************************** */
struct task_packet_s {
  int (*task)(FIOBJ obj, void *arg);
  void *arg;
  fio_ary_s *stack;
  FIOBJ next;
  uintptr_t *counter;
  uint8_t stop;
  uint8_t incomplete;
};

static int fiobj_task_wrapper(FIOBJ o, void *p_) {
  struct task_packet_s *p = p_;
  ++*p->counter;
  int ret = p->task(o, p->arg);
  if (ret == -1) {
    p->stop = 1;
    return -1;
  }
  if (FIOBJ_IS_ALLOCATED(o) && FIOBJECT2VTBL(o)->each) {
    p->incomplete = 1;
    p->next = o;
    return -1;
  }
  return 0;
}
/**
 * Single layer iteration using a callback for each nested fio object.
 *
 * Accepts any `FIOBJ ` type but only collections (Arrays and Hashes) are
 * processed. The container itself (the Array or the Hash) is **not** processed
 * (unlike `fiobj_each2`).
 *
 * The callback task function must accept an object and an opaque user pointer.
 *
 * Hash objects pass along a `FIOBJ_T_COUPLET` object, containing
 * references for both the key and the object. Keys shouldn't be altered once
 * placed as a key (or the Hash will break). Collections (Arrays / Hashes) can't
 * be used as keeys.
 *
 * If the callback returns -1, the loop is broken. Any other value is ignored.
 *
 * Returns the "stop" position, i.e., the number of items processed + the
 * starting point.
 */
size_t fiobj_each2(FIOBJ o, int (*task)(FIOBJ obj, void *arg), void *arg) {
  if (!o || !FIOBJ_IS_ALLOCATED(o) || (FIOBJECT2VTBL(o)->each == NULL)) {
    task(o, arg);
    return 1;
  }
  /* run task for root object */
  if (task(o, arg) == -1)
    return 1;
  uintptr_t pos = 0;
  fio_ary_s stack = FIO_ARY_INIT;
  size_t count = 1;
  struct task_packet_s packet = {
      .task = task, .arg = arg, .stack = &stack, .counter = &count,
  };
  fio_ary_new(&stack, 0);
  fio_ary_push(&stack, (void *)pos);
  fio_ary_push(&stack, (void *)o);
  do {
    o = (FIOBJ)fio_ary_pop(&stack);
    pos = (uintptr_t)fio_ary_pop(&stack);
    if (!pos)
      packet.next = 0;
    packet.incomplete = 0;
    pos = FIOBJECT2VTBL(o)->each(o, pos, fiobj_task_wrapper, &packet);
    if (packet.stop)
      goto finish;
    if (packet.incomplete) {
      fio_ary_push(&stack, (void *)pos);
      fio_ary_push(&stack, (void *)o);
    }

    if (packet.next) {
      fio_ary_push(&stack, (void *)0);
      fio_ary_push(&stack, (void *)packet.next);
    }

  } while (fio_ary_count(&stack));
finish:
  fio_ary_free(&stack);
  return count;
}

/* *****************************************************************************
Free complex objects (objects with nesting)
***************************************************************************** */

static void fiobj_dealloc_task(FIOBJ o, void *stack_) {
  // if (!o)
  //   fprintf(stderr, "* WARN: freeing a NULL no-object\n");
  // else
  //   fprintf(stderr, "* freeing object %s\n", fiobj_obj2cstr(o).data);
  if (!o || !FIOBJ_IS_ALLOCATED(o))
    return;
  if (OBJREF_REM(o))
    return;
  if (!FIOBJECT2VTBL(o)->each) {
    FIOBJECT2VTBL(o)->dealloc(o, NULL, NULL);
    return;
  }
  fio_ary_s *s = stack_;
  fio_ary_push(s, (void *)o);
}
/**
 * Decreases an object's reference count, releasing memory and
 * resources.
 *
 * This function affects nested objects, meaning that when an Array or
 * a Hash object is passed along, it's children (nested objects) are
 * also freed.
 */
void fiobj_free_complex_object(FIOBJ o) {
  fio_ary_s stack = {0};
  fio_ary_new(&stack, 0);
  fio_ary_push(&stack, (void *)o);
  do {
    o = (FIOBJ)fio_ary_pop(&stack);
    FIOBJECT2VTBL(o)->dealloc(o, fiobj_dealloc_task, &stack);
  } while (fio_ary_count(&stack));
  fio_ary_free(&stack);
}

/* *****************************************************************************
Defaults / NOOPs
***************************************************************************** */

void fiobject___noop_dealloc(FIOBJ o, void (*task)(FIOBJ, void *), void *arg) {
  (void)o;
  (void)task;
  (void)arg;
}
void fiobject___simple_dealloc(FIOBJ o, void (*task)(FIOBJ, void *),
                               void *arg) {
  free(FIOBJ2PTR(o));
  (void)task;
  (void)arg;
}

uintptr_t fiobject___noop_count(FIOBJ o) {
  (void)o;
  return 0;<commit_msg>Fix warning<commit_after>/*
Copyright: <NAME>, 2017-2018
License: MIT
*/

/**
This facil.io core library provides wrappers around complex and (or) dynamic
types, abstracting some complexity and making dynamic type related tasks easier.
*/
#include "fiobject.h"

#include "fio_ary.h"

#include <stdarg.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>

/* *****************************************************************************
the `fiobj_each2` function
***************************************************************************** */
struct task_packet_s {
  int (*task)(FIOBJ obj, void *arg);
  void *arg;
  fio_ary_s *stack;
  FIOBJ next;
  uintptr_t *counter;
  uint8_t stop;
  uint8_t incomplete;
};

static int fiobj_task_wrapper(FIOBJ o, void *p_) {
  struct task_packet_s *p = p_;
  ++*p->counter;
  int ret = p->task(o, p->arg);
  if (ret == -1) {
    p->stop = 1;
    return -1;
  }
  if (FIOBJ_IS_ALLOCATED(o) && FIOBJECT2VTBL(o)->each) {
    p->incomplete = 1;
    p->next = o;
    return -1;
  }
  return 0;
}
/**
 * Single layer iteration using a callback for each nested fio object.
 *
 * Accepts any `FIOBJ ` type but only collections (Arrays and Hashes) are
 * processed. The container itself (the Array or the Hash) is **not** processed
 * (unlike `fiobj_each2`).
 *
 * The callback task function must accept an object and an opaque user pointer.
 *
 * Hash objects pass along a `FIOBJ_T_COUPLET` object, containing
 * references for both the key and the object. Keys shouldn't be altered once
 * placed as a key (or the Hash will break). Collections (Arrays / Hashes) can't
 * be used as keeys.
 *
 * If the callback returns -1, the loop is broken. Any other value is ignored.
 *
 * Returns the "stop" position, i.e., the number of items processed + the
 * starting point.
 */
size_t fiobj_each2(FIOBJ o, int (*task)(FIOBJ obj, void *arg), void *arg) {
  if (!o || !FIOBJ_IS_ALLOCATED(o) || (FIOBJECT2VTBL(o)->each == NULL)) {
    task(o, arg);
    return 1;
  }
  /* run task for root object */
  if (task(o, arg) == -1)
    return 1;
  uintptr_t pos = 0;
  fio_ary_s stack = FIO_ARY_INIT;
  size_t count = 1;
  struct task_packet_s packet = {
      .task = task, .arg = arg, .stack = &stack, .counter = &count,
  };
  fio_ary_new(&stack, 0);
  fio_ary_push(&stack, (void *)pos);
  fio_ary_push(&stack, (void *)o);
  do {
    o = (FIOBJ)fio_ary_pop(&stack);
    pos = (uintptr_t)fio_ary_pop(&stack);
    if (!pos)
      packet.next = 0;
    packet.incomplete = 0;
    pos = FIOBJECT2VTBL(o)->each(o, pos, fiobj_task_wrapper, &packet);
    if (packet.stop)
      goto finish;
    if (packet.incomplete) {
      fio_ary_push(&stack, (void *)pos);
      fio_ary_push(&stack, (void *)o);
    }

    if (packet.next) {
      fio_ary_push(&stack, (void *)0);
      fio_ary_push(&stack, (void *)packet.next);
    }

  } while (fio_ary_count(&stack));
finish:
  fio_ary_free(&stack);
  return count;
}

/* *****************************************************************************
Free complex objects (objects with nesting)
***************************************************************************** */

static void fiobj_dealloc_task(FIOBJ o, void *stack_) {
  // if (!o)
  //   fprintf(stderr, "* WARN: freeing a NULL no-object\n");
  // else
  //   fprintf(stderr, "* freeing object %s\n", fiobj_obj2cstr(o).data);
  if (!o || !FIOBJ_IS_ALLOCATED(o))
    return;
  if (OBJREF_REM(o))
    return;
  if (!FIOBJECT2VTBL(o)->each) {
    FIOBJECT2VTBL(o)->dealloc(o, NULL, NULL);
    return;
  }
  fio_ary_s *s = stack_;
  fio_ary_push(s, (void *)o);
}
/**
 * Decreases an object's reference count, releasing memory and
 * resources.
 *
 * This function affects nested objects, meaning that when an Array or
 * a Hash object is passed along, it's children (nested objects) are
 * also freed.
 */
void fiobj_free_complex_object(FIOBJ o) {
  fio_ary_s stack = FIO_ARY_INIT;
  fio_ary_new(&stack, 0);
  fio_ary_push(&stack, (void *)o);
  do {
    o = (FIOBJ)fio_ary_pop(&stack);
    FIOBJECT2VTBL(o)->dealloc(o, fiobj_dealloc_task, &stack);
  } while (fio_ary_count(&stack));
  fio_ary_free(&stack);
}

/* *****************************************************************************
Defaults / NOOPs
***************************************************************************** */

void fiobject___noop_dealloc(FIOBJ o, void (*task)(FIOBJ, void *), void *arg) {
  (void)o;
  (void)task;
  (void)arg;
}
void fiobject___simple_dealloc(FIOBJ o, void (*task)(FIOBJ, void *),
                               void *arg) {
  free(FIOBJ2PTR(o));
  (void)task;
  (void)arg;
}

uintptr_t fiobject___noop_count(FIOBJ o) {
  (void)o;
  return 0;
{'fraction_non_alphanumeric': 0.22980366913421307, 'fraction_numerical': 0.008475485462933162, 'mean_word_length': 3.8857442348008386, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 37, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '6944108', 'n_tokens_mistral': 3338, 'n_tokens_neox': 3268, 'n_words': 874}