blob: 053a75457ea1a53a72851d057ed4c9e66048974f [file] [log] [blame]
// Licensed to the Apache Software Foundation (ASF) under one
// or more contributor license agreements. See the NOTICE file
// distributed with this work for additional information
// regarding copyright ownership. The ASF licenses this file
// to you under the Apache License, Version 2.0 (the
// "License"); you may not use this file except in compliance
// with the License. You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing,
// software distributed under the License is distributed on an
// "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
// KIND, either express or implied. See the License for the
// specific language governing permissions and limitations
// under the License.
#include "DFPlatform.h"
#include "DFArray.h"
#include "DFCommon.h"
#include <assert.h>
#include <stdlib.h>
#include <string.h>
struct DFArray {
size_t retainCount;
DFCopyFunction copyFun;
DFFreeFunction freeFun;
void **items;
size_t count;
size_t alloc;
};
DFArray *DFArrayNew(DFCopyFunction copy, DFFreeFunction free)
{
DFArray *array = (DFArray *)xcalloc(1,sizeof(DFArray));
array->retainCount = 1;
array->copyFun = copy;
array->freeFun = free;
array->items = NULL;
array->count = 0;
array->alloc = 0;
return array;
}
DFArray *DFArrayRetain(DFArray *array)
{
if (array != NULL)
array->retainCount++;
return array;
}
void DFArrayRelease(DFArray *array)
{
if ((array == NULL) || (--array->retainCount > 0))
return;
if (array->freeFun != NULL) {
for (size_t i = 0; i < array->count; i++)
array->freeFun(array->items[i]);
}
free(array->items);
free(array);
}
size_t DFArrayCount(DFArray *array)
{
return array->count;
}
void *DFArrayItemAt(DFArray *array, size_t index)
{
assert(index < array->count);
return array->items[index];
}
void DFArrayRemove(DFArray *array, size_t index)
{
assert(index < array->count);
memmove(&array->items[index],&array->items[index+1],(array->count-index-1)*sizeof(void *));
array->count--;
}
void DFArrayAppend(DFArray *array, void *item)
{
if (array->copyFun != NULL)
item = array->copyFun(item);
if (array->alloc == array->count) {
if (array->alloc == 0)
array->alloc = 1;
else
array->alloc *= 2;
array->items = (void **)xrealloc(array->items,array->alloc*sizeof(void *));
}
array->items[array->count++] = item;
}
void DFArraySort(DFArray *array, void *thunk, int (*compar)(void *, const void *, const void *))
{
DFSort(array->items,array->count,sizeof(void *),thunk,compar);
}
static void DFSortInternal(char *base, size_t nel, size_t width,
void *thunk, int (*compar)(void *, const void *, const void *),
char *work)
{
if (nel < 2) {
return;
}
size_t mid = nel/2;
char *base1 = base;
size_t nel1 = mid;
char *base2 = base + nel1*width;
size_t nel2 = nel - mid;
DFSortInternal(base1,nel1,width,thunk,compar,work);
DFSortInternal(base2,nel2,width,thunk,compar,work + width * nel1);
size_t pos1 = 0;
size_t pos2 = 0;
for (size_t outpos = 0; outpos < nel; outpos++) {
if ((pos2 >= nel2) || ((pos1 < nel1) && (compar(thunk,base1+pos1*width,base2+pos2*width) <= 0)))
memcpy(work+outpos*width,base1+width*(pos1++),width);
else
memcpy(work+outpos*width,base2+width*(pos2++),width);
}
memcpy(base,work,nel*width);
}
void DFSort(void *base, size_t nel, size_t width, void *thunk, int (*compar)(void *, const void *, const void *))
{
void *work = xmalloc(nel*width);
DFSortInternal(base,nel,width,thunk,compar,work);
free(work);
}