/*
******** airArrayLenPreSet()
**
** allocates the array to hold up to given length, without 
** actually changing the length.  In order for this to be 
** useful, this also turns on noReallocWhenSmaller
**
** NB: this used to have a "boolean" return to indicate allocation
** error, but nothing in Teem actually did the error checking.  Now
** conscientious users can look at NULL-ity of a->data to detect such
** an error.
*/
void
airArrayLenPreSet(airArray *a, unsigned int newlen) {
  unsigned int newsize;
  void *newdata;

  if (!a) {
    return;
  }

  if (newlen == 0) {
    /* there is no pre-set length, turn off noReallocWhenSmaller */
    a->noReallocWhenSmaller = AIR_FALSE;
  } else {
    newsize = (newlen-1)/a->incr + 1;
    if (newsize > a->size) {
      newdata = calloc(newsize*a->incr, a->unit);
      if (!newdata) {
        free(a->data);
        _airSetData(a, NULL);
        return;
      }
      memcpy(newdata, a->data, AIR_MIN(a->len*a->unit, 
                                       newsize*a->incr*a->unit));
      free(a->data);
      _airSetData(a, newdata);
      a->size = newsize;
    }
    a->noReallocWhenSmaller = AIR_TRUE;
  }

  return;
}
/*
******** airArrayNew()
**
** creates a new airArray struct and returns a pointer to it.
** dataP is a pointer to the user's data pointer
** lenP is a pointer to the user's array length variable (optional)
** unit is the size (in bytes) of one element in the array
** incr is the number of units by which the array will grow or shrink
**
** returns NULL on error, or the new airArray pointer if okay
** errors: bogus arguments, or couldn't alloc airArray struct
**
** --> The user CAN NOT change the pointer variable (of which *dataP
** is the address) after this is called, or else everything will
** get all bolloxed up.  The same goes for the array length
** variable, if its address is passed- though in that case the
** correct value will over-write any other.
*/
airArray *
airArrayNew(void **dataP, unsigned int *lenP, size_t unit, unsigned int incr) {
  airArray *a;

  if (unit<=0 || incr<=0) {
    return NULL;
  }
  
  a = (airArray *)calloc(1, sizeof(airArray));
  if (!a) {
    return NULL;
  }

  a->dataP = dataP;
  _airSetData(a, NULL);
  a->lenP = lenP;
  _airLenSet(a, 0);
  a->incr = incr;
  a->unit = unit;
  a->noReallocWhenSmaller = AIR_FALSE;

  a->allocCB = NULL;
  a->freeCB = NULL;
  a->initCB = NULL;
  a->doneCB = NULL;

  return a;
}
Example #3
0
/*
******** airArrayLenPreSet()
**
** allocates the array to hold up to given length, without
** actually changing the length.  In order for this to be
** useful, this also turns on noReallocWhenSmaller
**
** NB: this used to have a "boolean" return to indicate allocation
** error, but nothing in Teem actually did the error checking.  Now
** conscientious users can look at NULL-ity of a->data to detect such
** an error.
*/
void
airArrayLenPreSet(airArray *a, unsigned int newlen) {
  /* char me[]="airArrayLenPreSet"; */
  unsigned int newsize;
  void *newdata;

  if (!a) {
    return;
  }

  if (newlen == 0) {
    /* there is no pre-set length, turn off noReallocWhenSmaller */
    a->noReallocWhenSmaller = AIR_FALSE;
  } else {
    newsize = (newlen-1)/a->incr + 1;
    /*
    fprintf(stderr, "!%s: newlen = %u, incr = %u -> newsize = %u\n", me,
            newlen, a->incr, newsize);
    fprintf(stderr, "!%s: a->size = %u, a->len = %u, a->unit = %u\n", me,
            a->size, a->len, a->unit);
    */
    if (newsize > a->size) {
      newdata = calloc(newsize*a->incr, a->unit);
      /*
      fprintf(stderr, "!%s: a->data = %p, newdata = %p\n", me,
              a->data, newdata);
      */
      if (!newdata) {
        free(a->data);
        _airSetData(a, NULL);
        return;
      }
      if (a->data) {
        memcpy(newdata, a->data, AIR_MIN(a->len*a->unit,
                                         newsize*a->incr*a->unit));
        free(a->data);
      }
      _airSetData(a, newdata);
      a->size = newsize;
    }
    a->noReallocWhenSmaller = AIR_TRUE;
  }

  /* fprintf(stderr, "!%s: returning data %p\n", me, a->data); */
  return;
}
/*
******** airArrayLenSet()
**
** Set the length of the array, allocating or freeing as needed
** 
** returns 1 on error, otherwise 0 if okay
** possible errors: bogus arguments, or couldn't allocate new memory segment
**
** In case we can't allocate the new space, the old space is left untouched,
** however if the new length is smaller, the free/done callbacks will
** have been called on invalidated elements 
**
** NB: this used to have a "boolean" return to indicate allocation
** error, but almost nothing in Teem actually did the error checking.
** Now conscientious users can look at NULL-ity of a->data to detect
** such an error.
*/
void
airArrayLenSet(airArray *a, unsigned int newlen) {
  unsigned int newsize;
  int ii;
  void *addr, *newdata;
  
  if (!a) {
    /* user is a moron, what can you do */
    return;
  }

  if (newlen == a->len) {
    /* nothing to do */
    return;
  }

  /* call freeCB/doneCB on all the elements which are going bye-bye */
  if (newlen < a->len && (a->freeCB || a->doneCB)) {
    for (ii=a->len-1; ii>=(int)newlen; ii--) {
      addr = (char*)(a->data) + ii*a->unit;
      if (a->freeCB) {
        (a->freeCB)(*((void**)addr));
      } else {
        (a->doneCB)(addr);
      }
    }
  }

  newsize = newlen ? (newlen-1)/a->incr + 1 : 0;
  if (newsize != a->size) {
    /* we have to change the size of the array */
    if (newsize) {
      /* array should be bigger or smaller, but not zero-length */
      if (newsize > a->size
          || (newsize < a->size && !(a->noReallocWhenSmaller)) ) {
        newdata = calloc(newsize*a->incr, a->unit);
        if (!newdata) {
          free(a->data);
          _airSetData(a, NULL);
          return;
        }
        memcpy(newdata, a->data, AIR_MIN(a->len*a->unit, 
                                         newsize*a->incr*a->unit));
        free(a->data);
        _airSetData(a, newdata);
        a->size = newsize;
      }
    } else {
      /* array should be zero-length */
      free(a->data);
      _airSetData(a, NULL);
      a->size = newsize;
    }
  }
  /* else new size is still within current allocated length,
     and neither "size" nor "data" need to change */

  /* call allocCB/initCB on newly created elements */
  if (newlen > a->len && (a->allocCB || a->initCB)) {
    for (ii=newlen; ii<(int)(a->len); ii++) {
      addr = (char*)(a->data) + ii*a->unit;
      if (a->allocCB) {
        *((void**)addr) = (a->allocCB)();
      } else {
        (a->initCB)(addr);
      }
    }
  }
  _airLenSet(a, newlen);

  return;
}