The Perl Toolchain Summit needs more sponsors. If your company depends on Perl, please support this very important event.
%prototype SMOP__S1P__Array
%prefix smop_s1p_array
%RI.id Lowlevel array

%attr  unsigned int elems
%attr  unsigned int size
%attr  SMOP__Object** content

%include <string.h>,"array.h"

%{
SMOP__Object* SMOP__S1P__Array_create(SMOP__Object* interpreter) {
  smop_s1p_array_struct* ret = (smop_s1p_array_struct*) smop_nagc_alloc(sizeof(smop_s1p_array_struct));
  ret->RI = (SMOP__ResponderInterface*) RI;
  ret->size = 0;
  ret->elems = 0;
  ret->content = NULL;
  return (SMOP__Object*) ret;
}


void SMOP__S1P__Array_set_elems(SMOP__Object* interpreter,SMOP__Object* array_uncast,int elems) {
  smop_s1p_array_struct* array = ((smop_s1p_array_struct*)array_uncast);
  if (elems > array->size) {
    int new_size = elems;
    //printf("new_size:%d amortized size:%d\n",new_size,1<<(floor_log2(new_size))+1);
    array->content = realloc(array->content,(new_size * sizeof(void*)));
    int i;
    for ( i = array->size ; i < new_size ; i++) {
      array->content[i] = NULL;
    }
    array->size = new_size;
  }
  if (elems < array->elems) {
    /* TODO */
    abort();
  }
  array->elems = elems;
}

int SMOP__S1P__Array_get_elems(SMOP__Object* interpreter,SMOP__Object* array) {
   return ((smop_s1p_array_struct*)array)->elems;
}

void SMOP__S1P__Array_set_elem(SMOP__Object* interpreter,SMOP__Object* array_uncast,int i,SMOP__Object* value) {
  smop_s1p_array_struct* array = ((smop_s1p_array_struct*)array_uncast);
  if (array->elems <= i) SMOP__S1P__Array_set_elems(interpreter,array_uncast,i+1);
  SMOP__Object* prev = array->content[i];
  if (prev) SMOP_RELEASE(interpreter,prev);
  array->content[i] = value;
}

SMOP__Object* SMOP__S1P__Array_get_elem(SMOP__Object* interpreter,SMOP__Object* array,int i) {
   return ((smop_s1p_array_struct*)array)->content[i];
}

#if 0

static int floor_log2(unsigned int n) {
  int pos = 0;
  if (n >= 1<<16) { n >>= 16; pos += 16; }
  if (n >= 1<< 8) { n >>=  8; pos +=  8; }
  if (n >= 1<< 4) { n >>=  4; pos +=  4; }
  if (n >= 1<< 2) { n >>=  2; pos +=  2; }
  if (n >= 1<< 1) {           pos +=  1; }
  return ((n == 0) ? (-1) : pos);
}

#endif

/*
  } else if (identifier == SMOP__ID__Iterator) {
    ret = SMOP__S1P__Array_Iterator_create(SMOP_REFERENCE(interpreter,(SMOP__Object*)invocant));
*/
%}

%method new
  ret = SMOP__S1P__Array_create(interpreter);

%method postcircumfix:[ ](index)
  int i = SMOP__NATIVE__int_fetch(index);

  SMOP_RELEASE(interpreter,index);

  ret = SMOP__S1P__ArrayProxy_create(SMOP_REFERENCE(interpreter,invocant),i);



%method unshift(value)
    smop_s1p_array_struct* array = ((smop_s1p_array_struct*)invocant);

    SMOP__S1P__Array_set_elems(interpreter, invocant, array->elems + 1);
    memmove(array->content+1, array->content, (array->elems-1) * sizeof(void*));
    array->content[0] = value;

%method shift
    smop_s1p_array_struct* array = ((smop_s1p_array_struct*)invocant);

    if (array->elems) {
      ret = array->content[0];
      memmove(array->content, array->content+1, array->elems * sizeof(void*));
      array->elems--;
      if (!ret) ret = SMOP__NATIVE__bool_false;
    }

%method elems
    ret = SMOP__NATIVE__int_create(SMOP__S1P__Array_get_elems(interpreter,invocant));

%method push(value)
    smop_s1p_array_struct* array = ((smop_s1p_array_struct*)invocant);

    SMOP__S1P__Array_set_elems(interpreter, invocant, array->elems + 1);
    array->content[array->elems-1] = value;

%method FETCH
    ___VALUE_FETCH___

%method true
    ret = SMOP__NATIVE__bool_true;

%DESTROYALL {
    smop_s1p_array_struct* array = (smop_s1p_array_struct*)invocant;
    int i;for (i=0;i < array->elems;i++) {
      if (array->content[i]) SMOP_RELEASE(interpreter,array->content[i]);
    }
    free(array->content);
%}