<commit_before>#include <strings.h>

#include "std/debug.h"
#include "std/memory.h"
#include "std/array.h"

struct _Array {
  ArrayDataT *array;
  size_t elemSize;
  size_t reserved;
  bool zeroed;
  FreeFuncT freeFunc;
  CompareFuncT compareFunc; 
};

static void DeleteArray(ArrayT *self) {
  if (self->freeFunc)
    ArrayForEach(self, (IterFuncT)self->freeFunc, NULL);
  MemUnref(self->array);
}

ArrayT *NewArray(size_t reserved, size_t elemSize, bool zeroed) {
  ArrayT *array = NewRecordGC(ArrayT, (FreeFuncT)DeleteArray);

  array->elemSize = elemSize;
  array->zeroed = zeroed;
  array->reserved = reserved;

  /*
   * Allocate one more element that will serve the purpose of temporary element
   * for some operations (i.e. sort, swap).
   */
  array->array = MemNew0(sizeof(ArrayDataT) + (reserved + 1) * elemSize, NULL);
  array->array->size = 0;

  return array;
}

ArrayT *NewPtrArray(size_t reserved, bool autoFree) {
  ArrayT *array = NewArray(reserved, sizeof(PtrT), TRUE);

  if (autoFree)
    ArraySetFreeFunc(array, (FreeFuncT)MemUnref);
  
  return array;
}

void ArraySetCompareFunc(ArrayT *self, CompareFuncT func) {
  self->compareFunc = func;
}

void ArraySetFreeFunc(ArrayT *self, FreeFuncT func) {
  self->freeFunc = func;
}

ArrayDataT *ArrayGetData(ArrayT *self asm("a0")) {
  return self->array;
}

/*
 * @brief Get a pointer to an element without extra checks.
 *
 * Assumes that index is non-negative.  Can return an invalid pointer.
 */
PtrT ArrayGetFast(ArrayT *self asm("a0"), size_t index asm("d0")) {
  return &self->array->data[self->elemSize * index];
}

/*
 * @brief Swap two elements without extra checks.
 *
 * Assumes that fst != snd.
 */
static void ArraySwapFast(ArrayT *self asm("a0"), PtrT fst asm("a1"), PtrT snd asm("a2")) {
  PtrT tmp = ArrayGetFast(self, self->array->size);

  memcpy(tmp, fst, self->elemSize);
  memcpy(fst, snd, self->elemSize);
  memcpy(snd, tmp, self->elemSize);
}

static void ArrayClearRange(ArrayT *self, size_t first, size_t last) {
  if (self->zeroed)
    bzero(ArrayGetFast(self, first), self->elemSize * (last - first + 1));
}

static void ArrayFreeRange(ArrayT *self, size_t first, size_t last) {
  if (self->freeFunc) {
    PtrT item = ArrayGetFast(self, first);

    while (first++ <= last) {
      self->freeFunc(item);
      item += self->elemSize;
    }
  }
}

static void ArrayMoveRange(ArrayT *self, size_t index, size_t first, size_t last) {
  size_t remainding = last - first + 1;

  memmove(ArrayGetFast(self, index),
          ArrayGetFast(self, first),
          self->elemSize * remainding);
}

/*
 * @brief Change maximum number of element the array can hold.
 *
 * 1) newSize > current size => extra space will be allocated.
 * 2) newSize < current size => some elements will be removed and
 *    reserved space will be shrinked.
 */
static void ArrayDataResize(ArrayT *self, size_t newSize) {
  size_t newReserved = sizeof(ArrayDataT) + (newSize + 1) * self->elemSize;
  ArrayDataT *array = MemDupGC(self->array, newReserved, NULL);

  MemUnref(self->array);
  self->array = array;
}

void ArrayResize(ArrayT *self, size_t newSize) {
  if (!self->array) {
    self->array = MemNew(sizeof(ArrayDataT) + newSize * self->elemSize, NULL);
    self->array->size = 0;
    ArrayClearRange(self, 0, newSize - 1);
  } else {
    if (newSize > self->reserved) {
      ArrayDataResize(self, newSize);
      ArrayClearRange(self, self->reserved, newSize - 1);
    }
   
    if (newSize < self->reserved) {
      if (newSize < self->array->size) {
        ArrayFreeRange(self, newSize, self->array->size - 1);
        self->array->size = newSize;
      }
      ArrayDataResize(self, newSize);
    }
  }

  self->reserved = newSize;
}

#define MIN_SIZE 16

size_t NearestPow2(size_t num) {
  size_t i = 1;<commit_msg>Simplify array resize action.<commit_after>#include <strings.h>

#include "std/debug.h"
#include "std/memory.h"
#include "std/array.h"

struct _Array {
  ArrayDataT *array;
  size_t elemSize;
  size_t reserved;
  bool zeroed;
  FreeFuncT freeFunc;
  CompareFuncT compareFunc;

  PtrT temporary;
};

static void DeleteArray(ArrayT *self) {
  if (self->freeFunc)
    ArrayForEach(self, (IterFuncT)self->freeFunc, NULL);
  MemUnref(self->array);
}

ArrayT *NewArray(size_t reserved, size_t elemSize, bool zeroed) {
  ArrayT *array = NewRecordGC(ArrayT, (FreeFuncT)DeleteArray);

  array->elemSize = elemSize;
  array->zeroed = zeroed;
  array->reserved = 0;

  ArrayResize(array, reserved);

  return array;
}

ArrayT *NewPtrArray(size_t reserved, bool autoFree) {
  ArrayT *array = NewArray(reserved, sizeof(PtrT), TRUE);

  if (autoFree)
    ArraySetFreeFunc(array, (FreeFuncT)MemUnref);
  
  return array;
}

void ArraySetCompareFunc(ArrayT *self, CompareFuncT func) {
  self->compareFunc = func;
}

void ArraySetFreeFunc(ArrayT *self, FreeFuncT func) {
  self->freeFunc = func;
}

ArrayDataT *ArrayGetData(ArrayT *self asm("a0")) {
  return self->array;
}

/*
 * @brief Get a pointer to an element without extra checks.
 *
 * Assumes that index is non-negative.  Can return an invalid pointer.
 */
PtrT ArrayGetFast(ArrayT *self asm("a0"), size_t index asm("d0")) {
  return &self->array->data[self->elemSize * index];
}

/*
 * @brief Swap two elements without extra checks.
 *
 * Assumes that fst != snd.
 */
static void ArraySwapFast(ArrayT *self asm("a0"), PtrT fst asm("a1"), PtrT snd asm("a2")) {
  PtrT tmp = self->temporary;
  size_t elemSize = self->elemSize;

  memcpy(tmp, fst, elemSize);
  memcpy(fst, snd, elemSize);
  memcpy(snd, tmp, elemSize);
}

static void ArrayClearRange(ArrayT *self, size_t first, size_t last) {
  if (self->zeroed)
    bzero(ArrayGetFast(self, first), self->elemSize * (last - first + 1));
}

static void ArrayFreeRange(ArrayT *self, size_t first, size_t last) {
  if (self->freeFunc) {
    PtrT item = ArrayGetFast(self, first);

    while (first++ <= last) {
      self->freeFunc(item);
      item += self->elemSize;
    }
  }
}

static void ArrayMoveRange(ArrayT *self, size_t index, size_t first, size_t last) {
  size_t remainding = last - first + 1;

  memmove(ArrayGetFast(self, index),
          ArrayGetFast(self, first),
          self->elemSize * remainding);
}

/*
 * @brief Change maximum number of element the array can hold.
 *
 * 1) newSize > current size => extra space will be allocated.
 * 2) newSize < current size => some elements will be removed and
 *    reserved space will be shrinked.
 *
 * Note: Allocates one more element that will serve the purpose of temporary
 * element for some operations (i.e. sort, swap).
 */
void ArrayResize(ArrayT *self, size_t newSize) {
  if (self->array) {
    if (newSize == self->array->size)
      return;

    if (newSize < self->array->size) {
      ArrayFreeRange(self, newSize, self->array->size - 1);
      self->array->size = newSize;
    }
  }

  {
    size_t elemSize = self->elemSize;
    size_t bytes = sizeof(ArrayDataT) + (newSize + 1) * elemSize;

    if (!self->array) {
      self->array = MemNew(bytes, NULL);
      self->array->size = 0;
    } else {
      ArrayDataT *oldArray = self->array;
      self->array = MemDupGC(oldArray, bytes, NULL);
      MemUnref(oldArray);
    }

    if (newSize > self->reserved)
      ArrayClearRange(self, self->reserved, newSize);

    self->reserved = newSize;
    self->temporary = &self->array->data[newSize * elemSize];
  }
}

#define MIN_SIZE 16

size_t NearestPow2(size_t num) {
  size_t i = 1;
{'fraction_non_alphanumeric': 0.13501543416991008, 'fraction_numerical': 0.005502617098376057, 'mean_word_length': 3.672100313479624, 'pattern_counts': {'":': 0, '<': 12, '<?xml version=': 0, '>': 100, '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': '4062271', 'n_tokens_mistral': 2643, 'n_tokens_neox': 2571, 'n_words': 677}