| // 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); |
| } |