Never use doxygen again

Arrays and strings are simple things. Made simpler in c

  • By being safe: buffer overflow and other errors give clear messages
  • generic: arrays can have any datatype
  • fast: optionally uses less memory too
  • and simple: as first priority
Quick example:
char* arr = NULL;
aAppend(&arr, 'I', ' ', 'w', 'a', 'n', 't');
aMap(arr, capitalize_char); // capitalizes each char
arr[3] = 'O';        // standard assignment
aAt2(arr, 5, ' ');   // same as arr[5] = ' ', but overflow safe
// Append a null terminated array and 5 items from a second array
aAppendArray(&arr, SIZE_MAX, "chunky ", 5, "bacon, francis");
// At position 0 replace 1 item with a null terminated array
aReplaceArray(&arr, 0, 1, SIZE_MAX, "Everyone");
aWrite(arr); // prints "Everyone WON chunky bacon"
aFree(&arr);

That char* could equally be int* or an array of pointers; and still transparently be passed as a c array

Some disadvantages are:

  • It is impossible to implement aArray without macros. They are side-effect safe, and pre-reduced; so you see the minimum. But compiler messages due to missing commas, or type mismatches are still less than helpful. Thankfully these are easy to fix, and more problematic errors, such as buffer overflow, are clear and can be extended with backtraces:
example_error.c:300: out of bounds (length=8 but pos=10)
  • Because aArray is generic, some return values get type cast to reflect the array type. Sadly -pedantic now enables -Wno-unused-value, and some functions may need (void) placed infront of them to silence this warning: (void)aLength2(array, newlen)
  • This library has only been used in a few programs. But passes unittests, valgrind, has been fuzzed, passes static analysis, and even bootstraps itself. The unitests loc is just over 2x the source code

It runs as c99 under clang, gcc, and tcc; on DragonFly, Linux, macOS, and Windows in 32 and 64bit. It compiles with -pedantic -Wall -Wextra -Weverything

This page is self-contained documention for aArray.h release (14 Sep 2020)

Public domain. No restriction, no need to accredit. “As freely as you have received, freely give” Jesus

Even when writing aArray, I wasn't aware it would be possible; so the library has slowly transformed over several of years

Here are some comments on how it all works. Implementation details come from bithacks, hackersdelight, BonzaiThePenguin, and the initial idea from sglib

How can c functions take an unknown number of arguments?

Normally functions with a variable number of arguments need a marker to show how many arguments they're given, such as with stdargs.h or varargs.h

aArray functions don't need a marker, yet their number of arguments is known. Allowing them to be allocated and memcpy'd in one go, rather than iterated. This means less effort for the programmer, and a faster runtime

It is side-effect safe and done through __VA_ARGS__. This exapnds to a list of a macro's arguments, which (type[]){__VA_ARGS__} turns into an array, and sizeof((type[]){__VA_ARGS__}) / sizeof(type) uses to calculate the array length

How can c functions be polymorphic?

Different types take up different amounts of space, and so specialized functions are required for each type. But aAppend can take any type

How much space each item of an array takes can be calculated with sizeofType = sizeof(*array). So we can have a function for each type; then select the correct one with typed_functions[sizeofType] Polymorphism and variable number of arguments combine together something like this:

// get number of var-arg arguments, and make them generic
// results in:  arrayLength, (type[]){array}
#define AARRAY_Args(sizeofType, ...) \
  (sizeofType==1? sizeof((int8_t []){__VA_ARGS__}) / sizeof(int8_t ) : \
   sizeofType==2? sizeof((int16_t[]){__VA_ARGS__}) / sizeof(int16_t) : \
   sizeofType==4? sizeof((int32_t[]){__VA_ARGS__}) / sizeof(int32_t) : \
                  sizeof((int64_t[]){__VA_ARGS__}) / sizeof(int64_t)), \
  (sizeofType==1? (void*)(int8_t []){__VA_ARGS__} : \
   sizeofType==2? (void*)(int16_t[]){__VA_ARGS__} : \
   sizeofType==4? (void*)(int32_t[]){__VA_ARGS__} : \
                  (void*)(int64_t[]){__VA_ARGS__})
// select the correctly typed function from an array
#define aExample(arr, ...) \
  AARRAY_aExample_typed_functions[sizeof(*arr)](arr, \
  AARRAY_Args(sizeof(*arr), __VA_ARGS__))

This code selects which function to call, then passes it both arrayLength, and the typecast array. It should get compile time reduced to a single function call

How can aArrays be zero-indexed c arrays and aArrays at the same time?

In memory, a c array looks like {item0, item1, item2, ...}

And an aArray looks like {length, item0, item1, item2, ...}

Which can't be zero-indexed. But rather than returning a pointer to aArray's beginning, the api returns a pointer to item0; making it appear the same as an array, so long as realloc/free isn't used

Then when aArray needs to get an array's length; it simply moves the pointer back to the true beginning

How can arrays only store their length — what about their capacity?

Capacity tells us the length each array can grow to. But this makes arrays larger; since an extra variable is needed

Happily capacity can be safely guessed from an array's length

The NOCAPACITY variant of aArrays does this by growing in a fixed progression. Their capacity is always one of 8, 16, 32, 64, 128, etc. This means we can assume a NOCAPACITY aArray is its length rounded up to the next number in the progression, i.e. a length of 7 means the aArray's capacity must be at least 8, while a length of 9 fits into a capacity of 16

If the NOCAPACITY aArray length drops a lot, then goes up a little; it may well cause a realloc; since the length now fits into a smaller capacity

You could call this an unnecessary realloc, or you could call not doing it an unnecessary waste of space

The default aArray does not do this: it stores and doubles capacity. Only reducing to smaller memory sizes with aMem

How does aSearch work?

aSearch is standard binary search

aSearchP though is arguably a new. I like to call it pingpong, because it works like table-tennis. The ball is secant — a poor man’s version of newton-raphson’s method — this bounces around, using the last two bounces (array lookups), to predict where it should bounce next

This normally finds the answer in less steps than binary search. But has the less than helpful property that it may also bounce for ever, or even bounce off the table. Pingpong solves this by adding two bats. These provide a reducing range, squeezing the ball in at every bounce; so it will always find an answer, and with less array lookups than secant alone

So pingpong uses many less array lookups than binary search... But also spends a lot longer deciding where to look... Which is faster in a real sense is a very hard question to answer

You would think that arrays of integers would be a worst case for pingpong — but even here 32bit integers can barely express a random enough distribution to throw off pingpong. Binary search is only a safe bet with very short arrays

Tell me something fun

aArray bootstraps itself with a cppp 'pre-pre-processor'. In no way related to ppap

silly film

Internally aArray functions are written out many times for each type. For instance aFold is written out 48 times: once for each array type * each return type * 3. The 3 because it can be passed a c function, block, or c++ lambda. This duplication is most easily done with macros

But when a syntax error occurs, the compiler would print out all of those macros — more than a little messy! — so cppp pre-pre-processes them away before the compiler sees them

And since cppp is written using aArray.h, and aArray.h is written using cppp, we have a bootstrap loop, which forms part of the unittests each time aArray is regenerated

Thought for compiler writers: a #pragma silentmacro would help improve error messages

std::sort is slower

This shows the relative speed of different functions on macOS. They are tested against 10 different types of dataset, and the average score is taken. This is why qsort is slightly slower that mergesort. For datasets above 30000 items: mergesort becomes faster than aSort when the data is pre-ordered, and qsort becomes faster when the data has many duplicates. In general though aSort performs extremely well at all array lengths, and is the fastest across a range of datasets

It was written by BonzaiThePenguin. He's done seriously good work. It is a stable sort and operates in a fixed amount of memory

##define AARRAY_sortCache fixes the memory to 512, but you can redefine this to larger values; possibly improving aSort's performance for larger datasets

Now lets compare search using bsearch from Linux and BSD, and aSearch from aArray. The arrays graphed are of maximally random sorted integers. 64bit and 32bit ints respectively

aSearch is fastest aSearchP is fastest

I've profiled a range of situations and hardware, but the writers of the other algorithms will of done so aswell, so aSearch may look fast, but the difference with BSD is small

aSearchP though does the worst in the first graph, and best in the second. Actually both graphs attempt to put it in the worst light possible... It is an algorithm I like to call pingpong which should be worth using as arrays become longer, comparisons become slower, or as the dataset becomes more uniform

These graphs are of shorter arrays, and faster comparisons — the first graph using random int64_t integers, and the second random int32_t. Pingpong is still the fastest on the second, and easily fastest for int16_t. It is much better at searching less random distributions, such as pointers, rather than rand()

Please be careful using a custom cmp() with either binary or pingpong. This is not safe: aSearchPF(array, &index, key, ^(int a, int b){ return a-b; }). See aSearchF for more details

If that was fun, I'd like to suggest an alternative search algorithm that I haven't implemented, but may be faster still:

Binary search jumps through large arrays in a set order. Each iteration loading disparate parts of the array into memory (which is slow). What you could do is reorder the array; not from lowest to highest; but into the order taken by binary search. It is still binary search, but the first index tested is no-longer the middle, but the first. The second index tested would be either the second or third. Then from the second it would test either the 4th or 5th, and from the third it would test either the 6th or 7th

As this sequence becomes longer than a cacheline, you would split off the child search locations into a new block (with that block still placed into the same array, but so the cachelines get minmally loaded, and maximally used)

I would be surprized if that was not faster than existing binary search — and 5 years later I find out that it is; 3-5x faster, and called Eytzinger search invented in the 16th century. Note the remaining difference. Binary is depth first order, Eytzinger is breadth fist, and we are breadth first, but in cacheline chunks. This would be a more complex algorithm, but giving 2-5 branches for every cacheline, whereas Eytzinger gets that for the first, and only single branches per cacheline thereafter...

In comparisons of aAppend v.s. std::vector, or kvec.h, etc; gcc puts aArray equal with std::vector for int64_t* arrays, and ahead for int16_t* arrays. Sadly however clang gives aAppend a 13% slow down compared to gcc

Latest features

  • 2020 09 — removed need for maths.h
  • 2020 07 — aCapacity added
  • 2020 07 — fix aArray_NOCAPACITY lengths
  • 2020 04 — aSort now defaults to unsigned ordering
  • 2020 04 — Stride variant for pingpong search
  • 2019 10 — fix printing "%i64" for INT64_MIN

Missing features

  • aArray for 128bit integers? (Not doing)
  • Reduce macro usage? (Blows up size of aArray.h)

No known bugs...

LICENSE

The goal is not to limit, but to bless and benefit you as best I can

To that end, I place no restriction

Public domain. No restriction. No need to accredit

May the peace that passes understanding dwell in you. And you, rooted and grounded in love, may you know even the breadth length height and depth of his love for you, that surpasses knowledge – filling you to all the measure of the fullness of God

And to him who is able to do far more abundantly than all that we can ask or imagine, whatever you have faced and in every situation, may he protect you heart and your mind, unto eternity

NOCAPACITY

NOCAPACITY functions stop arrays from tracking their capacity. This saves about 8 bytes per array and occasionally causes the array to resize, reducing its length

NOCAPACITY (and STATIC) functions are simply variants of aAppend, aReplace, aAppendArray, aReplaceArray, aDelete, aConcat, aMulti, aMem, aArray, and aFree (aAppend_NOCAPACITY, aReplace_NOCAPACITY, ...)

You cannot mix NOCAPACITY, STATIC and normal api functions on the same array. An array created with a NOCAPACITY function must continue to use them, until it is freed with aFree_NOCAPACITY

STATIC

Sometimes you may want to handle memory yourself. You can get this by using the aAppend_STATIC aConcat_STATIC, etc variants of the normal api functions

They throw "out of capacity" if the array would extend beyond the capacity set when they were created or last updated by aArray_STATIC

char*arrSTATIC = aArray_STATIC(data, sizeof(size_t)*2 + 4, true);
aAppend_STATIC(&arrSTATIC, 1); // throws "out of capacity"
char*arrSTATIC = aArray_STATIC(data, sizeof(size_t)*2 + 4, true);
aLength2(arrSTATIC, 0);
aAppend_STATIC(&arrSTATIC, 1); // this is fine

It is not safe to mix STATIC NOCAPACITY and normal functions on the same array

aAppend_STATIC(&arrSTATIC, 1, 2, 3, 4);
aReplaceArray(&arrSTATIC, 0, 1, 5, replacement); // undetected memory corruption!!!

But you can convert between the array types, for instance with aConcat aConcat_STATIC and aConcat_NOCAPACITY

AARRAY_NOTYPEOF

aArray functions can return a mixture of types. Which would require manual type casting; but aArray assumes your compiler supports __typeof (or __decltype for c++). This allows the function's return type to be automatically fixed

If your compiler doesn't support __typeof or __decltype, then you can disable this automatic fixing with ##define AARRAY_NOTYPEOF

clang and gcc support __typeof, but will also sometimes emit warnings about unused returns. You can silence these warnings by placing (void) infront of the function, for instance

(void)aAt2(somewhere, 1, over_the_rainbow);

AARRAY_WARN

aArray functions can also recieve a mixture of types. Which would require manual type casting; aArray silences the specific clang and msvc warnings for just those parameters. But this is not possible for gcc. If you prefer to type cast manually for all compilers, then you can set ##define AARRAY_WARN

If you then have a lot of manual type casts, you may prefer AARRAY_nowarn_start

AARRAY_nowarn_start

Anything between AARRAY_nowarn_start/AARRAY_nowarn_end has their C4047 differing level of indirection warning suppressed (for msvc), or -Wconversion, -Wint-conversion, -Wpointer-to-int-cast, and -Wbad-function-cast (for clang and gcc). They don't both need these, but it's simpler if they both get the same

This may save some casts when using gcc or AARRAY_WARN

For example bad-function-cast is disabled even under -Wall and -Wextra. Enabling it has no effect on gcc but clang would then require aAt(mystructs, N)->this to be rewritten as ((mystruct)aAt((uintptr_t*)mystructs, N))->this

If compiling for clang with c++ then you may also want AARRAY_nowarn_pedantic_cpp_start/AARRAY_nowarn_pedantic_cpp_end. But in general don't use aArray with c++

aArray aims to use the same function calls for different array types, but c++ restricts function type casts. For instance f(int) to f(unsigned int), and f(char*) to f(void*) is undefined behavior in c++. So while aArray does unittest for c++ conformity, it is not something I advise. Using c does not have this issue (or any other known UB, etc problems)

AARRAY_UNSAFE

Defining this before including aArray.h removes the bounds and other safety checks, for a possible speed increase

AARRAY_c and AARRAY_h

aArray.h can be included as a single header. But if you prefer, it can also be a dual header/implementation pair

#include "aArray.h"

Becomes

#define AARRAY_h
#include "aArray.h"

And a separately compiled .c file contains

#define AARRAY_c
#include "aArray.h"

AARRAY_NOCONVENIENCE

Under the assumption that you use aArray so much it becomes tiresome to see it everywhere, some mnemonics are defined for your convenience. These can be turned off with ##define AARRAY_NOCONVENIENCE

The most useful is probably aStr("string") which converts "string" into an aArray string. Note that the terminating NULL is dropped. This simplifies concatenation, but means you probably want to print them with aWrite, or aFmt with "%v%c", or append '\0' by hand with aA(&str, '\0')

Also aMap aFilter aFold aLoop aSortF aSearchF aSearchPF and aSearchPS can take either c-functions, blocks, or c++ lambdas. They do this with their underlying aMap_FUNC, aMap_BLOCK, and aMap_LAMBDA. You can call them explicitly, or use aMap — which simply links to whichever of those is enabled by your compiler settings. So if blocks are enabled, but you are passing a c-function, you will need to be explicit and call aMap_FUNC, since aMap will link to aMap_BLOCK

Then for those of us who like acronyms, there are:
aA → aAppend
aR → aReplace
aAA → aAppendArray
aRA → aReplaceArray
aD → aDelete
aC → aConcat

aL → aLength
aL2 → aLength2
aZL2 → aZLength2

aF → aFmt
aFE → aFmtE
aFF → aFmtF
aFA → aFmtA
aW → aWrite
aWE → aWriteE
aWF → aWriteF

In the compiler I'm writing, 65.5% of function calls are from aArray. So this library is surprizingly useful; and the above acronyms help keep my code succinct

This would not of been possible without my family. I wouldn't even of begun programming without them. And thankyou to my lovely wife who is so generous to me

Many tools were used in creating aArray. Particularly helpful ones include BeautifulSoup, ninja, afl (especially the rabbit photos), fossil (safety+usability), DragonFlyBSD, and Kakoune

My life

Our pastor imprisoned, for ‘attempting to overthrow the government’ Joy in prison
We could see them running around, screaming... There was nothing I could do Lira’s rain
My first animated short, of some simple miracles Animation
Genesis is different. Vegetarianism explains why Creative Snails

any * aAppend (any **aArray, any items,...)
 
any * aReplace (any **aArray, size_t pos, size_t removeAmount, any items,...)
 
any * aAppendArray (any **aArray, size_t arrayLen, any *array,...)
 
any * aReplaceArray (any **aArray, size_t pos, size_t removeAmount, size_t arrayLen, any *array,...)
 
any * aDelete (any **aArray, size_t pos, size_t amount)
 
any * aConcat (any **aArray, any *next_aArray,...)
 
any * aMulti (any **aArray, size_t pos, size_t removeAmount, size_t arrayTimes, size_t arrayLen, any *array,...)
 
any * aMem (any *aArray)
 
any * aArray (any *memptr, size_t size, bool maximize)
 
void aFree (any **aArray)
 
size_t aLength (any *aArray)
 
any aLength2 (any *aArray, size_t len)
 
any aZLength2 (any *aArray, size_t len)
 
any aCapacity (any *aArray)
 
any aAt (any *aArray, size_t pos)
 
any aZAt (any *aArray, size_t pos)
 
any aAt2 (any *aArray, size_t pos, any newItem)
 
any aZAt2 (any *aArray, size_t pos, any newItem)
 
any * aAtPtr (any *aArray, size_t pos)
 
any * aZAtPtr (any *aArray, size_t pos)
 
size_t aIndexOf (any *aArray, any item)
 
size_t aZIndexOf (any *aArray, any item)
 
void aMap (any *aArray, void(*f)(any *item)))
 
any * aFilter (any *aArray, int(*f)(any item))
 
anyB aFold (any *aArray, anyB base, anyB(*f)(anyB base, any item))
 
int aLoop (any *aArray, size_t startPos, int(*f)(size_t pos))
 
int aCmp (any *aArray, any *next_aArray,...)
 
any * aSort (any *aArray)
 
any * aSortF (any *aArray, int(*f)(any *key, any *item))
 
int aSearch (any *aArray, size_t *index, any key)
 
int aSearchF (any *aArray, size_t *index, any key, int64_t(*f)(any key, any item))
 
int aSearchPS (any *aArray, size_t *index, any *key, int64_t(*f)(any *key, any *item), size_t stride)
 
int aFmt (char *format,...)
 
int aFmtE (char *format,...)
 
int aFmtF (FILE *file, char *format,...)
 
int aFmtA (char **aArray, char *format,...)
 
int aWrite (any *aArray,...)
 
void aError (char *errorLocation, char *errorMsg)
 
any* aAppend ( any **  aArray,
any  items,
  ... 
)

Appends one or more items to aArray

any represents any type other than void upto 8 bytes in width; be it char, double, clock_t, FILE*, long long, etc

If aArray is NULL, it will be initialized. A zero-length aArray is equivalent to a NULL aArray — as in api calls on either have the same effect. This should result in less NULL pointer checking, as it is a safe value

aAppend can take an arbitrary number of items. It is not necessary to give the number of arguments, or mark their end

Returns
The aArray, with new items added. If the aArray had to be moved in memory (to accommodate the new items) then *aArray is also updated to point to it
Exceptions
"array type too wide", "out of memory"

Exceptions are not c++ exceptions. "array type too wide" is a compile-time error. "out of memory" is passed to the aError handler

int *arr = NULL;
aAppend(&arr, 1, 2);
aAppend(&arr, 99, 100);
aFmt("{%v, %i}", arr); // prints "{+1, +2, +99, +100}"
any* aReplace ( any **  aArray,
size_t  pos,
size_t  removeAmount,
any  items,
  ... 
)

Replaces removeAmount items at position pos in aArray with one or more items

Returns
The updated aArray, and *aArray now pointing to it
Exceptions
"array type too wide", "out of memory", "out of bounds", "removal is out of bounds"
unsigned int *joy = aAppend((unsigned int**)NULL, 10, 5, 0, -5, -20);
aFmt("[%v, %u]", aReplace(&joy, 2, 3, 10, 20)); // prints "[10, 5, 10, 20]"
any* aAppendArray ( any **  aArray,
size_t  arrayLen,
any *  array,
  ... 
)

Appends one or more arrays to the end of aArray

arrayLen is the number of array items to be appended. If arrayLen is SIZE_MAX then array is appended upto but not including the first NULL. This makes it easy to append char* strings for instance

Multiple arrays can be passed to aAppendArray; each array must be preceded by it's own arrayLen

Returns
The updated aArray, and *aArray now pointing to it
Exceptions
"array type too wide", "out of memory", "wrong arg count", "array is NULL"

Three of those exceptions simply check parameter validity

int ages[3] = {0, 5, 10};
aAppendArray((int**)NULL,
  3, ages,
  3, ages,
  2, (int[]){12, 14}); // (int*){0, 5, 10, 0, 5, 10, 12, 14}

There are convenience macros that abbreviate aAppendArray to aAA and for instance aReplace to aR

You can switch them off by defining AARRAY_NOCONVENIENCE. But there is also an abbreviation of aAppendArray to aStr, which simplifies strings

char* hi = aStr("hello world");
aR(&hi, 0, 1, 'j'); // "jello world"
any* aReplaceArray ( any **  aArray,
size_t  pos,
size_t  removeAmount,
size_t  arrayLen,
any *  array,
  ... 
)

Replaces removeAmount items at position pos in aArray with one or more arrays

arrayLen is the number of array items to be inserted

Multiple arrays can be passed; each must be preceded by it's own arrayLen

Returns
The updated aArray, and *aArray now pointing to it
Exceptions
"array type too wide", "out of memory", "out of bounds", "removal is out of bounds", "wrong arg count", "array is NULL"

Passing repeats of aArray, or pointers into aArray are safe for all aArray manipulating functions, though the data is overwritten from left to right

int* nums = NULL;
aAppend(&nums, 1, 2, 3, 4, 100);
aReplaceArray(&nums, 2, 2,
  1, nums,
  2, aAtPtr(nums, 1)); // {1, 2, 1, 2, 1, 100}
any* aDelete ( any **  aArray,
size_t  pos,
size_t  amount 
)

Deletes amount items from aArray at position pos

Returns
The updated aArray, and *aArray now pointing to it
Exceptions
"array type too wide", "out of bounds", "removal is out of bounds"
long* medalsWonBy_aArray = aAppend((long**)NULL, 15, 26, (long)-1);
aDelete(&medalsWonBy_aArray, 0, 3);
// length of array is now sadly zero
any* aConcat ( any **  aArray,
any *  next_aArray,
  ... 
)

Appends one or more next_aArrays to the end of aArray

Really this is a simple convenience – it does the same as aAppendArray, but without needing to specify each next_aArray length

Returns
The updated aArray, and *aArray now pointing to it
Exceptions
"array type too wide", "out of memory"
char* example = aStr("A ");
char* silly = aStr("silly ");
aConcat(&example, silly, silly, example, example);
// "A silly silly A A "
any* aMulti ( any **  aArray,
size_t  pos,
size_t  removeAmount,
size_t  arrayTimes,
size_t  arrayLen,
any *  array,
  ... 
)

Other than making your code look complex, aMulti lets you

  1. Create un-initialized aArrays
  2. Create aArrays with repeating items
  3. Combine multiple aArray updates into a single step

arrayTimes is the amount of times to insert arrayLen from array into aArray

If arrayTimes is 0 then arrayLen un-initialized items will be inserted

Returns
The updated aArray, and *aArray now pointing to it
Exceptions
"array type too wide", "out of memory", "out of bounds", "removal is out of bounds", "wrong arg count", "array is NULL"
// length=200, every item is 0
aMulti(&data, 0, 0, 200, 1, (int8_t[]){0});
  
// length=200, every item is uninitialized
aMulti(&data, 0, 0, 0, 200, NULL);

Also

// Combine aArray updates reduced to a single call
unsigned int* va = NULL;
aAppend(&va, 1, 2, 3);
aReplace(&va, 0, 0, -2, -1, 0);
aReplaceArray(&va, 1, 3, 1, (unsigned int[]){5});
aDelete(&va, aLength(va)-1, 1);
// va now {-2, 5, 2}
unsigned int* vb = NULL;
aMulti(&vb,
  0, 0, 1, 3, (unsigned int[]){1, 2, 3},
  0, 0, 1, 3, (unsigned int[]){-2, -1, 0},
  1, 3, 1, 1, (unsigned int[]){5},
  3, 1, 0, 0, NULL);
// vb now {-2, 5, 2}, but done in one malloc
any* aMem ( any *  aArray)

Converts aArray to a typed memory pointer

Returns
Pointer to aArray's memory
Exceptions
"array type too wide"
// shrink memory to arr length
size_t limit = sizeof(size_t)*2 + aL(arr);
arr = aArray(realloc(aMem(arr), limit), limit, false);
// manipulate memory
size_t length;
char*data = serialize(aMem(arr), &length);
arr = deserialize(aArray(data, length, false));
any* aArray ( any *  memptr,
size_t  size,
bool  maximize 
)

Converts type-cast memptr of length size into an aArray

If maximize or aArray would overflow, then it's length is set to the maximum within size

This allows the STATIC variant of aArrays to resize, or for aArrays to be backed by mmap, aalloc, etc

Returns
an any* aArray
Exceptions
"array type too wide", "array is NULL", "out of capacity"

Default and STATIC aArrays require an extra sizeof(size_t)*2 bytes. NOCAPACITY aArrays require an extra sizeof(size_t) bytes. The "out of capacity exception" is for when these minimums are not met

char*x = aArray((char*)malloc(200), 200, true);
aF("%uz", aL(x)); // prints 184
aF("%c", aAt(x, 0)); // prints uninitialized byte
free(aMem(x));
// STATIC aArrays do not realloc,
// instead they throw "out of capacity"
x = aArray_STATIC((char*)malloc(1000), sizeof(size_t)*2 + 3, false);
aL2(x, 0); // length now 0
aAppend_STATIC(&x, 1, 2, 3); // at max length
// set capacity to 4
x = aArray_STATIC(aMem(x), sizeof(size_t)*2 + 4, false);
if(aL(x)==3) aAppend_STATIC(&x, 4); // [1, 2, 3, 4]
void aFree ( any **  aArray)

Frees aArray, setting *aArray to NULL

Note
I used to forget & de-referencing the pointer to aArray, so now it forces a compiler error
any* myArr = aAppend((any**)NULL, 'x');
aFree(&myArr); // myArr is now NULL
size_t aLength ( any *  aArray)
Returns
The length of aArray

aLength(nullvar) returns 0 — since NULL is considered equivalent to a zero-length aArray

any aLength2 ( any *  aArray,
size_t  len 
)

Sets aArray length to an equal or shorter len

Returns
The last item still in aArray. I.e. aArray[len-1], or 0 if len is 0
Exceptions
"array type too wide", "out of bounds"
int* fib = NULL; aAppend(&fib, 1, 1, 2, 3, 5);
aFmt("Prev fib = %uz", aLength2(fib, aLength(fib)-1));
// fib length reduced by one, and 3 printed
  
aFmt("\nlen = %uz", aLength(fib)); // 4
aLength2(fib, 2);
aFmt("\nlen = %uz", aLength(fib)); // 2
any aZLength2 ( any *  aArray,
size_t  len 
)

Reduces aArray length by len

Returns
The last item still in aArray. I.e. aArray[new_length-1], or 0 if new length would be 0
Exceptions
"array type too wide", "out of bounds"

aZL2(array, 1) abbreviates aZLength2 and is a variation on "`pop()`".

int* fib = NULL; aAppend(&fib, 1, 1, 2, 3, 12);
aZLength2(fib, 1); // removes 12
aFmt("last item = %u", aZLength2(fib, 1)); // removes 3, prints 'last item = 2'
any aCapacity ( any *  aArray)
Returns
The capacity of aArray
// 2*sizeof(size_t) is where aArray stores capacity+length
size_t size = 15 + 2*sizeof(size_t);
char* blah = aArray((char*)malloc(size), size, true);
aFA(&out, "%uz ", aCapacity(blah)); // 15
aL2(blah, 3); // aka aLength2
aFA(&out, "%uz ", aCapacity(blah)); // 15
aFree(&blah);
blah = aArray_STATIC((char*)malloc(size), size, true);
aFA(&out, "%uz ", aCapacity_STATIC(blah)); // 15
aL2(blah, 3);
aFA(&out, "%uz ", aCapacity_STATIC(blah)); // 15
aFree_STATIC(&blah);
size = 15 + sizeof(size_t);
blah = aArray_NOCAPACITY((char*)malloc(size), size, true);
// capacity is lowest power-of-two that fits
aFA(&out, "%uz ", aCapacity_NOCAPACITY(blah)); // 8
aL2(blah, 3);
aFA(&out, "%uz ", aCapacity_NOCAPACITY(blah)); // 4
aFree_NOCAPACITY(&blah);
any aAt ( any *  aArray,
size_t  pos 
)
Returns
The item at position pos in aArray, indexing from zero
Exceptions
"array type too wide", "out of bounds"

A pos past the end of aArray throws an exception. Otherwise aArray[pos] is identical

char* equal = aAppend((char**)NULL, 'a', 'b');
// NOTE: cast not needed if your compiler has __typeof or __decltype
if(equal[0] == (char)aAt(equal, 0)) printf("equal"); // "equal"
any aZAt ( any *  aArray,
size_t  pos 
)
Returns
The item at position pos from the end of aArray, indexing from zero
Exceptions
"array type too wide", "out of bounds"

A pos past the beginning of aArray throws an exception

char* letters = aAppend((char**)NULL, 'a', 'r', 't');
aReplace(&letters, 0, 0, aZAt(letters, 0));
aFmt("%v %c", letters); // "t a r t"
any aAt2 ( any *  aArray,
size_t  pos,
any  newItem 
)

Sets the item at position pos in aArray to newItem

Returns
newItem
Exceptions
"array type too wide", "out of bounds"
char* letters = aAppend((char**)NULL, 'a', 'b');
aAt2(letters, 1, 'd'); // ['a', 'd']
any aZAt2 ( any *  aArray,
size_t  pos,
any  newItem 
)

Sets the item at position pos from the end of aArray to newItem

Returns
newItem
Exceptions
"array type too wide", "out of bounds"
char* letters = aAppend((char**)NULL, 'a', 'b');
aZAt2(letters, 0, 'd'); // 'a', 'd'
any* aAtPtr ( any *  aArray,
size_t  pos 
)
Returns
A pointer to the item at position pos in aArray
Exceptions
"array type too wide", "out of bounds"
char* equal = aAppend((char**)NULL, 'a', 'b');
// NOTE: casts not needed if your compiler has __typeof or __decltype
*(char*)aAtPtr(equal, 0) = 'b';
if(equal[0] == (char)aAt(equal, 1)) aFmt("equal"); // "equal"
any* aZAtPtr ( any *  aArray,
size_t  pos 
)
Returns
A pointer to the item at position pos from the end of aArray
Exceptions
"array type too wide", "out of bounds"
char* letters = aAppend((char**)NULL, 'n', 'o', '\0');
*(char*)aZAtPtr(letters, 2) = 'l';
printf(letters); // "lo"
size_t aIndexOf ( any *  aArray,
any  item 
)

Finds the first index of item in aArray

Returns
first index of item in aArray, or -1
Exceptions
"array type too wide"
int* PPS_array = aAppendArray((int**)NULL, numPidgeons, pidgeonPeckSpeed_data);
aIndexOf(PPS_array, 200); // first occuring pidgeon with a peck speed of 200
size_t aZIndexOf ( any *  aArray,
any  item 
)

Finds the last index of item in aArray

Returns
last index of item in aArray, or -1
Exceptions
"array type too wide"
int* PPS_array = aAppendArray((int**)NULL, numPidgeons, pidgeonPeckSpeed_data);
aZIndexOf(PPS_array, 190); // last occuring pidgeon with a peck speed of 190
void aMap ( any *  aArray,
void(*)(any *item)  f 
)

Apply f to every item in aArray

f can be a block, c++11 lambda, or function-pointer

Optionally use: void aMap(any*, void(*f)(any*,void*data), void*data)

Exceptions
"array type too wide", "parameter is NULL"

There are actually 3 api functions here. aMap_BLOCK, aMap_LAMBDA, aMap_FUNC. aMap simply maps to the first of those available. If the environment has blocks, then aMap_BLOCK, otherwise if lambdas, then aMap_LAMBDA, and otherwise aMap_FUNC. You can always call the specific function directly if you prefer

aFilter, aFold, and aLoop handle blocks, lambdas, and function-pointers in the same way

// ride every pony!
pony**my_little_ponies = ...;
void (*ride_a_pony)(pony**) = oh_what_fun_function;
aMap_FUNC(my_little_ponies, ride_a_pony);
char*rider_says = "Yesss!";
aMap_BLOCK(my_little_ponies,
  ^(pony**p, void*data){
    printf("ride %s? %s", (*p)->name, (char*)data); },
  rider_says);
any* aFilter ( any *  aArray,
int(*)(any item)  f 
)

Apply f to every item in aArray. Keep the item in aArray if f returns true

f can be a block, c++11 lambda, or function-pointer

Optionally use: any* aFilter(any*, int(*f)(any,void*data), void*data)

Exceptions
"array type too wide", "parameter is NULL"
int* n1 = aAppend((int**)NULL, 4,5,6,7,8);
aFilter_FUNC(n1, isEven);  // n1 = [4,6,8]
aFilter_BLOCK(n1, ^(int item){ return item > 5; });  // n1 = [6,8]
aFilter_LAMBDA(n1, [](int item){ return item != 8; });  // n1 = [6]
anyB aFold ( any *  aArray,
anyB  base,
anyB(*)(anyB base, any item)  f 
)

Do base = f(base, item) for every item in aArray

f can be a block, c++11 lambda, or function-pointer

Optionally use: anyB aFold(any*, anyB, anyB(*f)(anyB,any,void*data), void*data)

Returns
the final base
Exceptions
"array type too wide", "parameter is NULL"

This is a nice simple way to combine every item of an aArray into a single result

int* numbers = aAppendArray((int**)NULL, 10, numbersArray);
aFmt("\nSum     = %u64", aFold_FUNC(numbers, 0, add_function, NULL));
aFmt("\nProduct = %u64", aFold_BLOCK(numbers, (size_t)1, ^(size_t base, int item){ return base*item; }));
auto f = [](bool base, int item) { return base&&item; };
aFmt("\nAllTrue = %u8", (uintptr_t)aFold_LAMBDA(numbers, true, f));
char* baseB = NULL;
aFmt("\nString  = %v%c", *aFold_BLOCK(numbers, &baseB,
  ^(char** baseBPtr, int item){ (void)aAppend(baseBPtr, (char)(item+64)); return baseBPtr; }));
int aLoop ( any *  aArray,
size_t  startPos,
int(*)(size_t pos)  f 
)

This is a while loop that hopefully keeps your code safer and cleaner

Starting from startPos, and until out of bounds, or f returns 0, do pos += f(pos)

f can be a block, c++11 lambda, or function-pointer

Optionally use: int aLoop(any*, size_t, int(*f)(size_t,void*data), void*data)

Returns
f's last returned value
Exceptions
"array type too wide", "parameter is NULL"

aLoop handles the rarer issues of integer sign conversion and overflow at pos += f(pos); aswell as buffer overflow. With blocks it becomes:

aLoop(aArray, startPos, ^(size_t pos){
  // do my stuff
  return deltaPos; } );
For instance:
unsigned int* a = aAppend((unsigned int**)NULL, 1, 2, 3, 4);
// print index 0 and 2
aLoop(a, 0, ^(size_t n) {
  // (uintptr_t) cast here even for clang, because it can miss _Pragmas
  aFmt((uintptr_t)"a[%ull] == %ui\n", n, aAt(a, n)); return 2; });
// print index 3 and 1, then set them to new values
aLoop(a, 3, ^(size_t n){
  aFmt((uintptr_t)"Doing a[%ull] = %ui\n", n, aAt(a, n-1));
  (void)aAt2(a, n, aAt(a, n-1));
  return -2; }); // a becomes {1, 1, 3, 3}
int aCmp ( any *  aArray,
any *  next_aArray,
  ... 
)

Compares aArray against one or more next_Arrays

The any type width is assumed to be the same – i.e. both char*, or short*, etc

Returns
1 if equal, 0 otherwise
Exceptions
"array type too wide"
int
  *black = NULL,
  *white = NULL;
if(aCmp(black, white)) aFmt("We are all family");
any* aSort ( any *  aArray)

Orders array items as ascending unsigned integers

Returns
The re-ordered array
Exceptions
"array type too wide"

Requires <math.h> linking for the sqrt function

int* filmBoredomLevel = aAppend((int**)NULL, 300, 600, 200, 100);
aSort(filmBoredomLevel);
aFmt("[%v, %ui]", filmBoredomLevel); // prints "[100, 200, 300, 600]"
any* aSortF ( any *  aArray,
int(*)(any *key, any *item)  f 
)

Orders array items according to the function f

f must return true/false, i.e. using < or >

f can be a block, c++11 lambda, or function-pointer

Returns
The re-ordered array
Exceptions
"array type too wide"
int sort_strcmp(char*a, char*b) { return strcmp(a,b) < 0; }
// ...
char** verses = NULL;
aAppend(&verses, "There is no greater love", "You are my beloved", "Because of His great love");
aSortF_FUNC(verses, sort_strcmp);
aFmt("%v\n%s", verses);
int aSearch ( any *  aArray,
size_t *  index,
any  key 
)

Searches a sorted aArray for key

If key is present, then index is set to its position, otherwise index is set to the last searched position. Where key==2, and aArray is [2, 2] or [1, 3]: index will be set to either 0 or 1, since both answers are correct

The aArray items must be ordered as ascending unsigned integers

Returns
1 if key found, 0 otherwise. And updates *index
Exceptions
"array type too wide"

aSearchP is an alternative to @aSearch that uses pingpong, rather than binary search. It's here for your enjoyment

size_t index;
if(aSearch(filmBoredomLevel, &index, 600))
  printf("Most boring film 'Peppa Pig Goes on Holiday' is at index %zu", index);
int aSearchF ( any *  aArray,
size_t *  index,
any  key,
int64_t(*)(any key, any item)  f 
)

Searches a sorted aArray for key

If key is present, then index is set to its position, otherwise index is set to the last searched position

f can be a block, c++11 lambda, or function-pointer

f must return less than, equal, or greater than 0, as item is less than, equal, or greater than key. It is common to see examples such as aSearchF(arr, &i, 5, ^(int a, int b){ return a-b; }). But this is incorrect, as the difference a-b is an unsigned int, and so overflows the sign bit. Either use an if statment, or cast to a larger int, i.e. ^(int a, int b){ return ((int64_t)a - (int64_t)b); }

Returns
1 if key found, 0 otherwise. And updates *index
Exceptions
"array type too wide"

aSearchPF is an alternative to aSearchF that uses pingpong, rather than binary search

For aSearchPF, f should return the degree of difference, i.e. item - key. Note that strcmp does this, but it is not a great example as it only returns a byte of difference. The same sign bit overflow issue applies

int64_t search_strcmp(char*a, char*b) { return strcmp(a,b); }
// ...
size_t index;
char* key = "He gives power to the weak and strength to the powerless";
if(aSearchPF_FUNC(verses, &index, key, search_strcmp))
  printf("found verse at %zu", index);
aSearchPF_BLOCK(doors, &index, key, ^(uint64_t a, uint64_t b){
  // avoid overflow into the sign bit
  if((a^b)>(UINT64_MAX>>1)) return a<b? INT64_MIN : INT64_MAX;
  // alternative method
  // if(a-b>(UINT64_MAX>>1)||b-a>(UINT64_MAX>>1)) return a<b? INT64_MIN : INT64_MAX;
  return (int64_t)(a-b); });
if(index < aL(doors) && doors[index] < key) index++;
aReplace(&doors, index, 0, key);
aF("inserted key into door %uz", index);
int aSearchPS ( any *  aArray,
size_t *  index,
any *  key,
int64_t(*)(any *key, any *item)  f,
size_t  stride 
)

Searches a sorted aArray for key

The underlying algorithm is pingpong, so f preferably returns the degree of difference

The array is assumed to hold aLength(aArray)/stride items. f is passed pointers at stride offsets

So if aArray is (uint8_t*), then stride is measured in bytes

Returns
1 if key found, 0 otherwise. And updates *index
Exceptions
"array type too wide"
struct person { char*name; };
struct person key = { "myself" };
uint8_t*people = aArray((uint8_t*)malloc(200),200,true); aL2(people, sizeof(struct person));
memcpy(people, &key, sizeof(struct person));
size_t index;
if(aSearchPS_FUNC(people, &index, &key, f, sizeof(struct person)))
  aF("egomania is at %uz", index);
// printed "egomania is at 0"
int aFmt ( char *  format,
  ... 
)

Prints aArrays; aswell as chars, strings, integers, and floats, according to format

format can contain plain text, or:

  • %% for %
  • %c for characters
  • %s for strings
aFmt("%s%c%s", "plat", 'y', "pus"); // prints 'platypus'
  • %AAiBB for integers
  • %AAuBB for unsigned integers

AA is any number from 2 - 64, and defaults to 10. It is the base to print in, such as binary or hex

BB is the integer's type, and defaults to (int). It can be: 8, 16, 32, 64, or c (char), s (short), i (int), l (long), ll (long long), z (size_t), m (intmax_t), p (intptr_t). So (unsigned long long) in base 16 would be %16ull; (uint32_t) in binary would be %2u32; and (signed short) in base 10 would be %is, though %i will always print the sign, whether + or -

aFmt("h%cpp%c %u8", 'i', 'o', (uint8_t)2); // prints 'hippo 2'
  • %f for floats
  • %d for doubles
float fa=0.01, fb=2.22;
double da=2.22*1000000;
// prints '0.01 2.22 -- 2.22e+06'
aF("%f %f -- %d",
    *(int32_t*)&fa,*(int32_t*)&fb,
    *(int64_t*)&da); // stop float->int conversion warnings
  • %vAA%BB for aArrays

AA is the text to print between each item. BB can be any of the % formatters, except %v. So '%v, %i' would print a comma separated list of ints

Returns
0 on success, -1 on I/O error
Exceptions
"format requires more arguments", "format is malformed", "parameter is NULL"
char* abc = aAppend((char**)NULL, 'a', 'b', 'c');
aFmt("<%v, %c>", abc); //prints '<a, b, c>'
int* nums = aAppend((int**)NULL, 0, 1, 2);
aFmt("[%v | %2i]", nums); //prints '[+0 | +1 | +10]'
aFree(&abc); aFree(&nums);
int aFmtE ( char *  format,
  ... 
)

Prints aArrays, etc in format to stderr. First stdout, then stderr is flushed

This can be useful for quick debugging. Assuming no define AARRAY_NOCONVENIENCE we even save a whole two letters, abbreviating it to aFE

Returns
0 on success, -1 on I/O error
Exceptions
"format requires more arguments", "format is malformed", "parameter is NULL"
// prints base 2, base 3, then base 4
aFmtE("as easy as %2ic %3is %4ii", (char)1, (short)2, (int)3);
int aFmtF ( FILE *  file,
char *  format,
  ... 
)

Prints aArrays, etc in format to file

Returns
0 on success, -1 on I/O error
Exceptions
"format requires more arguments", "format is malformed", "parameter is NULL"
// aStr("") is simply a convenience to convert a string to an aArray
char* word = aStr("imperturbablorbably");
FILE* file = fopen("hope.txt", "w");
aFmtF(file, "Let me spell it out for you: %v, %c", word);
fclose(file); // contains "Let me spell it out for you: i, m, p, e, r, t, u, r, b...."
int aFmtA ( char **  aArray,
char *  format,
  ... 
)

Prints aArrays, etc in format to a (char*) aArray — no '\0' appended

‘'X’‘ is placed where the ’\0' would be. This helps catch errors. Defining AARRAY_UNSAFE turns this feature off

Returns
0 on success, -1 on I/O error
Exceptions
"format requires more arguments", "format is malformed", "parameter is NULL", "out of memory"
char*out = NULL;
aFmtA(&out, "%ui %ui miss a few %ii %ii", 1, 2, 99, 100);
aA(&out, '\0'); // append \0
int aWrite ( any *  aArray,
  ... 
)

Prints the full contents of aArray and any subsequent aArrays as char* text to file

Subsequent aArrays should have the same any type width as the first

It is faster than printf and does not require aArrays to be NULL terminated

Returns
0 on success, -1 on I/O error
Exceptions
"parameter is NULL"

There is also WriteE, aWriteF, corresponding to aFmtE and aFmtF

aAppendArray(&string,
  SIZE_MAX, "A wonderful story of how",
  SIZE_MAX, ", my saviour died for me");
FILE* file = fopen("hope.txt", "w");
aWrite(string); // writes string to stdout
aWriteE(string); // writes string to stderr
aWriteF(file, string); // writes string to file
void aError ( char *  errorLocation,
char *  errorMsg 
)

The error handler. Prints error details and aborts, but can be replaced with a custom error handler

This error handler must be set per translation unit

errorLocation is where the error occurred in your code, i.e.: "file:lineNumber"

errorMsg is one of:
      "out of memory (allocating=...)",
      "out of capacity (size=. but ...)",
      "out of bounds (length=. but ...)",
      "removal is out of bounds (length=. but ...)",
      "array is NULL (array no=...)",
      "parameter is NULL",
      "array type too wide (max 8 bytes)",
      "wrong arg count (args=. but ...)", and
      "infinite loop (jump=0)",
      "format requires more arguments",
      "format is malformed"

If errorMsg formatting fails then (...) will be (no info). Except for a small easter egg, for when you truly manage to run out of memory

Here's a little game. It shows errors being thrown and caught using longjmp

#include "aArray.h"
#include <setjmp.h>
#include <time.h>
jmp_buf array_err;
void aError_jmp(char* line, char* msg) {
  // our custom error handler
  printf("Error at %s: %s\n", line, msg);
  // choices are exit or longjmp...
  longjmp(array_err, 1); }
int main() {
  printf("Lets play guess the array length\n");
  // guess too high, and an "out of bounds" exception will lose you the game
  srand(time(NULL));
  char* array = aArray((char*)malloc(100), rand() % 100, true);
  // aError exceptions are caught here
  aError = &aError_jmp;
  if(setjmp(array_err))
    printf("Oops, too far! Goodbye\n"), aFree(&array), exit(0);
  
  for(;;) {
    printf("Guess a length: ");
    size_t guess;
    int input_err = scanf("%zu", &guess);
    if (input_err == 0 || input_err == EOF)
      printf("Oh dear, I didn't understand! Goodbye\n"), aFree(&array), exit(0);
    
    // if guess is out of bounds, aAt will call aError_jmp
    // and aError_jmp behaves like an exception
    // i.e. it longjmps to setjmp(array_err) where the error is handled
    aAt(array, guess);
    
    // good luck with winning
    printf("The array might be longer...\n"); } }
It produces something like:
cc game.c && ./a.out
Lets play guess the array length
Guess a length: 20
The array might be longer...
Guess a length: 30
The array might be longer...
Guess a length: 40
Error at game.c:35: out of bounds (length=36 but pos=40)
Oops, too far! Goodbye
1  /**\
2  /*/
3 /* Public domain. No restriction, no need to accredit
4 ** "As freely as you have received, freely give" -- Jesus
5 **
6 \* An array and string library. Generated: $exec date -u +"%d %b %Y" | perl -pe "s/\\n//"
7  \*\
8  \**/
9 
10 
11 
12 
13 #if !defined(AARRAY_define)
14 
15 #include <stdint.h>
16 #include <stdlib.h>
17 #include <stdio.h>
18 #include <string.h> /* for memcmp */
19 #if defined(_MSC_VER)
20 #include <malloc.h> /* for msvc realloc */
21 #endif
22 #if defined(__cplusplus)
23 #include <functional> /* for lambda */
24 #endif
25 
26 /* $$defines are for pre-pre-processed macros
27  * this simplifies end-user compiler messages
28  * if this is aArray.h, they will have already reduced to the final exposed api
29  */
30 
31 
32 
33 
34 /* handle warnings
35  * many parameters take an arbitrary mix of pointers/integers
36  * so optionally suppress warnings only for those parameters
37  */
38 $define pragmaWarnings(NAME)
39  /* these are slightly redundant, but handle both clang and gcc */
40  #if defined(__cplusplus)
41  #define AARRAY_nowarn_start \
42  _Pragma("NAME diagnostic push") \
43  _Pragma("NAME diagnostic ignored \"-Wconversion\"") \
44  _Pragma("NAME diagnostic ignored \"-Wconversion-null\"") \
45  _Pragma("NAME diagnostic ignored \"-Woverflow\"") /* older versions of gcc */ \
46  _Pragma("NAME diagnostic ignored \"-Wnarrowing\"")
47  #else
48  #define AARRAY_nowarn_start \
49  _Pragma("NAME diagnostic push") \
50  _Pragma("NAME diagnostic ignored \"-Wconversion\"") \
51  _Pragma("NAME diagnostic ignored \"-Wint-conversion\"") \
52  _Pragma("NAME diagnostic ignored \"-Wpointer-to-int-cast\"") \
53  _Pragma("NAME diagnostic ignored \"-Wbad-function-cast\"")
54  #endif
55  #define AARRAY_nowarn_end _Pragma("NAME diagnostic pop")
56 
57 /* c++ is available but not advertised and not advised
58  * start-end block suppresses some c++ warnings
59  * i.e. (cast) not being static_cast<cast>(), c++98-compat, etc
60  */
61 #define AARRAY_nowarn_pedantic_cpp_start
62 #define AARRAY_nowarn_pedantic_cpp_end
63 #if defined(__clang__)
64  pragmaWarnings(clang)
65  #if defined(__cplusplus)
66  #undef AARRAY_nowarn_pedantic_cpp_start
67  #define AARRAY_nowarn_pedantic_cpp_start_helper \
68  _Pragma("clang diagnostic push") \
69  _Pragma("clang diagnostic ignored \"-Wc99-extensions\"") \
70  _Pragma("clang diagnostic ignored \"-Wc++98-compat-pedantic\"") \
71  _Pragma("clang diagnostic ignored \"-Wold-style-cast\"") \
72  _Pragma("clang diagnostic ignored \"-Wcast-qual\"")
73  #if __clang_major__ < 5
74  #define AARRAY_nowarn_pedantic_cpp_start \
75  AARRAY_nowarn_pedantic_cpp_start_helper
76  #else
77  #define AARRAY_nowarn_pedantic_cpp_start \
78  AARRAY_nowarn_pedantic_cpp_start_helper \
79  _Pragma("clang diagnostic ignored \"-Wzero-as-null-pointer-constant\"")
80  #endif
81  #undef AARRAY_nowarn_pedantic_cpp_end
82  #define AARRAY_nowarn_pedantic_cpp_end _Pragma("clang diagnostic pop")
83  #endif
84 #elif defined(__GNUC__)
85  pragmaWarnings(GCC)
86  #if defined(__cplusplus)
87  #undef AARRAY_nowarn_pedantic_cpp_start
88  #undef AARRAY_nowarn_pedantic_cpp_end
89  #define AARRAY_nowarn_pedantic_cpp_start \
90  _Pragma("GCC diagnostic push") \
91  _Pragma("GCC diagnostic ignored \"-Wpedantic\"")
92  #define AARRAY_nowarn_pedantic_cpp_end _Pragma("GCC diagnostic pop")
93  #endif
94 #elif defined(_MSC_VER)
95  #define AARRAY_nowarn_start \
96  __pragma(warning(push)) \
97  __pragma(warning(disable:4047))
98  #define AARRAY_nowarn_end __pragma(warning(pop))
99 #else
100  /* don't hide int-pointer conversion warnings for this compiler */
101  #define AARRAY_nowarn_start
102  #define AARRAY_nowarn_end
103 #endif
104 
105 #if defined(__cplusplus)
106  AARRAY_nowarn_pedantic_cpp_start
107  #define AARRAY_move std::move
108 #else
109  #define AARRAY_move
110 #endif
111 
112 
113 
114 
115 /* compile as .c .h, or as a single header with 'static inline' functions */
116 #if defined(AARRAY_c)
117 #define AARRAY_define(name, ...) name __VA_ARGS__
118 #elif defined(AARRAY_h)
119 #define AARRAY_define(name, ...) extern name;
120 #else
121 #define AARRAY_define(name, ...) static inline name __VA_ARGS__
122 #endif
123 
124 /* general compiler compatibility */
125 #if !defined(__has_feature)
126 #define __has_feature(x) 0
127 #endif
128 #if !defined(__has_extension)
129 /* pre-3.0 clang */
130 #define __has_extension __has_feature
131 #endif
132 
133 #if defined(__builtin_prefetch)
134 #define AARRAY_prefetch(A, B, C) __builtin_prefetch(A, B, C)
135 #else
136 #define AARRAY_prefetch(A, B, C)
137 #endif
138 
139 /* switch on/off safety checks */
140 #if defined(AARRAY_UNSAFE)
141 #define AARRAY_safety(UNSAFE, ...) UNSAFE
142 #else
143 #define AARRAY_safety(UNSAFE, ...) __VA_ARGS__
144 #endif
145 
146 /* switch on/off type warnings for generics */
147 #if defined(AARRAY_WARN) || (defined(__GNUC__) && !defined(__clang__))
148  /* gcc can't handle pragmas within expressions, and so misses out */
149  #define AARRAY_nowarn_internal_start
150  #define AARRAY_nowarn_internal_end
151 #else
152  #define AARRAY_nowarn_internal_start AARRAY_nowarn_start
153  #define AARRAY_nowarn_internal_end AARRAY_nowarn_end
154 #endif
155 
156 /* set the size of aSort's cache */
157 #if !defined(AARRAY_sortCache)
158  #define AARRAY_sortCache 512
159 #endif
160 
161 
162 
163 
164 /* error handling */
165 AARRAY_define(__attribute((noreturn))
166 void AARRAY_aError(char errLocation[], char errMsg[]), {
167  fflush(stdout); fprintf(stderr, "%s: %s\n", errLocation, errMsg); abort(); })
168 /* set the default handler */
169 #if defined(AARRAY_c)
170 void (*aError)(char[], char[]) = &AARRAY_aError;
171 #elif defined(AARRAY_h)
172 extern void (*aError)(char[], char[]);
173 #else
174 static void (*aError)(char[], char[]) = &AARRAY_aError;
175 #endif
176 
177 /* generate "file.c:line_number" for error messages */
178 #define AARRAY_STRINGIFY(x) #x
179 #define AARRAY_TOSTRING(x) AARRAY_STRINGIFY(x)
180 #define AARRAY_LINE (char*)__FILE__ ":" AARRAY_TOSTRING(__LINE__)
181 
182 /* generate error messages */
183 #define AARRAY_aError_MsgLen 52 + 3*20 + 1 /* 52 characters + 3*size_t + NULL */
184 #define AARRAY_aError_CALL(MSG) { aError(errLoc, MSG); abort(); }
185 #define AARRAY_Error_OutOfMemory(SIZE) \
186  { char AARRAY_aError_Msg[AARRAY_aError_MsgLen]; \
187  if(0>snprintf(AARRAY_aError_Msg, AARRAY_aError_MsgLen, \
188  "out of memory (allocating=%zu)", \
189  SIZE)) \
190  AARRAY_aError_CALL((char*)"out of memory " \
191  "(can I interest you in a banana instead? 🍌)") \
192  else AARRAY_aError_CALL(AARRAY_aError_Msg) }
193 #define AARRAY_Error_OutOfBounds(LENGTH, POS) \
194  { char AARRAY_aError_Msg[AARRAY_aError_MsgLen]; \
195  if(0>snprintf(AARRAY_aError_Msg, AARRAY_aError_MsgLen, \
196  "out of bounds (length=%zu but pos=%zu)", \
197  LENGTH, POS)) \
198  AARRAY_aError_CALL((char*)"out of bounds (no info)") \
199  else AARRAY_aError_CALL(AARRAY_aError_Msg) }
200 #define AARRAY_Error_RemovalIsOutOfBounds(LENGTH, POS, RLEN) \
201  { char AARRAY_aError_Msg[AARRAY_aError_MsgLen]; \
202  if(0>snprintf(AARRAY_aError_Msg, AARRAY_aError_MsgLen, \
203  "removal is out of bounds (length=%zu but pos=%zu removal=%zu)", \
204  LENGTH, POS, RLEN)) \
205  AARRAY_aError_CALL((char*)"removal is out of bounds (no info)") \
206  else AARRAY_aError_CALL(AARRAY_aError_Msg) }
207 #define AARRAY_Error_OutOfCapacity(CAPACITY, REQ) \
208  { char AARRAY_aError_Msg[AARRAY_aError_MsgLen]; \
209  if(0>snprintf(AARRAY_aError_Msg, AARRAY_aError_MsgLen, \
210  "out of capacity (size=%zu but require=%zu)", CAPACITY, REQ)) \
211  AARRAY_aError_CALL((char*)"array is STATIC (no info)") \
212  else AARRAY_aError_CALL(AARRAY_aError_Msg) }
213 #define AARRAY_Error_ArrayIsNull(ARRAY_NO) \
214  { char AARRAY_aError_Msg[AARRAY_aError_MsgLen]; \
215  if(0>snprintf(AARRAY_aError_Msg, AARRAY_aError_MsgLen, \
216  "array is NULL (array no=%zu)", ARRAY_NO)) \
217  AARRAY_aError_CALL((char*)"array is NULL (no info)") \
218  else AARRAY_aError_CALL(AARRAY_aError_Msg) }
219 #define AARRAY_Error_ArrayIsWide \
220  (aError(AARRAY_LINE, (char*)"array type too wide (max 8 bytes)"), 0)
221 #define AARRAY_Error_WrongArgCount(ARG_NUM, MULTIPLE, ADDITION) \
222  { char AARRAY_aError_Msg[AARRAY_aError_MsgLen]; \
223  if(0>snprintf(AARRAY_aError_Msg, AARRAY_aError_MsgLen, \
224  "wrong arg count (args=%zu but should be %i + multiple of %i)", \
225  ARG_NUM, ADDITION, MULTIPLE)) \
226  AARRAY_aError_CALL((char*)"wrong arg count (no info)") \
227  else AARRAY_aError_CALL(AARRAY_aError_Msg) }
228 #define AARRAY_Error_InfiniteLoop \
229  AARRAY_aError_CALL((char*)"infinite loop (jump=0)")
230 #define AARRAY_Error_FormatStringArgs \
231  AARRAY_aError_CALL((char*)"format requires more arguments")
232 #define AARRAY_Error_FormatStringMalformed \
233  AARRAY_aError_CALL((char*)"format is malformed")
234 #define AARRAY_Error_NullParameter \
235  AARRAY_aError_CALL((char*)"parameter is NULL")
236 
237 
238 
239 
240 /* foundations for array allocation */
241 AARRAY_define(size_t AARRAY_upper_power_of_two(size_t v), {
242  /* from: graphics.stanford.edu/~seander/bithacks.html#RoundUpPowerOf2
243  * very slightly faster than: 1<<(64-AARRAY_BUILTIN_LL(clz,v-1))
244  */
245  v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8;
246  v |= v >> 16; if(sizeof(size_t)==8) v |= v >> 32; v++; return v; })
247 /* cross platform count-leading-zeros */
248 #if defined(__GNUC__)
249 #define AARRAY_builtin_ll(name,with) \
250  (sizeof(with)<=sizeof(int)?__builtin_##name(with) : \
251  (sizeof(with)<=sizeof(long)?__builtin_##name##l(with) : \
252  __builtin_##name##ll(with)))
253 AARRAY_define(int AARRAY_clz(size_t value), {
254  if(!value) return sizeof(value)*8;
255  return AARRAY_builtin_ll(clz,value); })
256 #elif defined(_MSC_VER)
257 #include <intrin.h>
258 #if defined(_WIN64)
259 #pragma intrinsic(_BitScanReverse,_BitScanReverse64)
260 AARRAY_define(int AARRAY_clz(size_t value), {
261  unsigned long result;
262  return (int)(sizeof(size_t) <= 4?
263  (_BitScanReverse(&result, (unsigned long)value)? 31-result : 32) :
264  _BitScanReverse64(&result, value)? 63-result : 64); })
265 #else
266 #pragma intrinsic(_BitScanReverse)
267 AARRAY_define(int AARRAY_clz(size_t value), {
268  unsigned long result;
269  return (int)(_BitScanReverse(&result, value)? 31-result : 32); })
270 #endif
271 #else
272 /* from www.hackersdelight.org/hdcodetxt/nlz.c.txt */
273 AARRAY_define(int AARRAY_clz(size_t x), {
274  int n = 0;
275  if(sizeof(size_t)==8 &&
276  x <= 0x00000000FFFFFFFF) { n += 32; x <<= 32; }
277  if(x <= 0x0000FFFFFFFFFFFF) { n += 16; x <<= 16; }
278  if(x <= 0x00FFFFFFFFFFFFFF) { n += 8; x <<= 8; }
279  if(x <= 0x0FFFFFFFFFFFFFFF) { n += 4; x <<= 4; }
280  if(x <= 0x3FFFFFFFFFFFFFFF) { n += 2; x <<= 2; }
281  if(x <= 0x7FFFFFFFFFFFFFFF) { n += 1; x <<= 1; }
282  return n; })
283 #endif
284 
285 /* array allocators, for 3 types of array
286  * fix pointers to realloced memory, to point back into memory
287  */
288 #define AARRAY_FIX_POINTERS(TYPE) \
289  if(!*vec) *length = 0; \
290  else if(vecsIncr) { \
291  /* parameters can contain pointers \
292  so update any that overlaped vec's old position */ \
293  size_t m = vecsIncr==5? 2: vecsIncr-1; \
294  while(m < vecsCount) { \
295  if(vecs[m] >= (uintptr_t)(*vec) && \
296  vecs[m] < (uintptr_t)(*vec)+(*length)*sizeof(TYPE)) \
297  vecs[m] += \
298  (uintptr_t)length-(uintptr_t)(*(size_t**)vec-1); \
299  m += vecsIncr; } }
300 
301 /* calculate capacity from length */
302 #define AARRAY_ALLOC_NOCAPACITY(TYPE) \
303  size_t curSize = (*length) * sizeof(TYPE) + sizeof(size_t); \
304  size_t newSize = ((*length) + (ilen-rlen)) * sizeof(TYPE) + sizeof(size_t); \
305  if((!*vec || AARRAY_clz(newSize-1) < AARRAY_clz(curSize-1))) { \
306  length = (size_t*)realloc(!*vec? NULL : length, \
307  AARRAY_upper_power_of_two(newSize)); \
308  AARRAY_safety(, if(!length) AARRAY_Error_OutOfMemory(newSize)); \
309  AARRAY_FIX_POINTERS(TYPE) } \
310  *vec = (TYPE*)(length+1);
311 
312 /* error if allocation required */
313 #define AARRAY_ALLOC_STATIC(TYPE) \
314  (void)vecsIncr; (void)vecsCount; (void)vecs; \
315  size_t curSize = *vec? *(*(size_t**)vec-2) : 0; \
316  size_t newSize = ((*length) + (ilen-rlen)) * sizeof(TYPE) + sizeof(size_t) * 2; \
317  if(!*vec) AARRAY_Error_OutOfCapacity((size_t)0, newSize); \
318  AARRAY_safety((void)curSize;, \
319  if(newSize>curSize) \
320  AARRAY_Error_OutOfCapacity(curSize, newSize))
321 
322 /* store capacity
323  * alternative growth strategies might be
324  * size += (size >> 3) + (size < 9 ? 3 : 6);
325  * size += size >> 1; // *1.5
326  * size = AARRAY_upper_power_of_two(size)
327  */
328 #define AARRAY_ALLOC_STD(TYPE) \
329  size_t curSize = *vec? *(*(size_t**)vec-2) : 0; \
330  size_t newSize = ((*length) + (ilen-rlen)) * sizeof(TYPE) + sizeof(size_t) * 2; \
331  if((!*vec || newSize > curSize)) { \
332  newSize += newSize >> 1; \
333  length = (size_t*)realloc(!*vec? NULL : length-1, newSize); \
334  AARRAY_safety(, if(!length) AARRAY_Error_OutOfMemory(newSize)); \
335  *length = newSize; \
336  length += 1; \
337  AARRAY_FIX_POINTERS(TYPE) } \
338  *vec = (TYPE*)(length+1);
339 
340 /* handle array allocation */
341 #define AARRAY_Expand(TYPE, GROWTH) \
342  /* use rlen (remove length) and ilen (insert length), \
343  to setup vec ready for any new data to be inserted/appended \
344  -- essentially a realloc + a memmove */ \
345  size_t lengthHolder = 0, *length = &lengthHolder; \
346  if(*vec) length = *(size_t**)vec-1; \
347  AARRAY_safety((void)errLoc;, \
348  if(pos > *length) AARRAY_Error_OutOfBounds(*length, pos) \
349  if(rlen > (*length) - pos) \
350  AARRAY_Error_RemovalIsOutOfBounds(*length, pos, rlen)) \
351  if(rlen > ilen && (*length)-(pos+rlen)) \
352  /* move when still have items (before realloc clips them) */ \
353  memmove(&((*vec)[pos+ilen]), &((*vec)[pos+rlen]), \
354  sizeof(TYPE) * ((*length) - (pos+rlen))); \
355  /* calculate curSize and newSize */ \
356  AARRAY_ALLOC_##GROWTH(TYPE) \
357  if(rlen < ilen && (*length)-(pos+rlen)) { \
358  /* move when have space to put items (after realloc creates it) */ \
359  memmove(&((*vec)[pos+ilen]), &((*vec)[pos+rlen]), \
360  sizeof(TYPE) * ((*length) - (pos+rlen))); }
361 
362 
363 
364 
365 /* generate type specific and growth-strategy specific functions */
366 $define AARRAY_Replace(TYPE, GROWTH,)
367 AARRAY_define(TYPE*AARRAY_Replace_$##GROWTH$##_$##TYPE(char errLoc[],
368  TYPE*vec[], size_t pos, size_t rlen, size_t ilen, TYPE items[]), {
369  /* replaces section of a array with N items */
370  if(vec) { AARRAY_prefetch((size_t*)*vec-1, 1, 1); }
371  /* vecs is {array1 ... arrayN}, but doesn't contain pointers;
372  so vsIncr skipped with setting it to 0 */
373  size_t vecsCount = 1; size_t vecsIncr = 0;
374  uintptr_t*vecs = (uintptr_t*)(void*)items;
375  TYPE*vecHolder = NULL; if(!vec) vec = &vecHolder;
376  AARRAY_Expand(TYPE, GROWTH);
377  if(*vec) {
378  if(ilen) memcpy(&((*vec)[pos]), vecs, sizeof(TYPE) * ilen);
379  *((*(size_t**)vec)-1) += ilen-rlen; }
380  return *vec; })
381 
382 /* GENERATE_GENERICS creates functions for each data type,
383  * FTYPE also make it specific to a block|lambda|function-pointer
384  * These functions are then put into an array,
385  * letting us select the right one at compile time
386  */
387 $define GENERATE_GENERICS(GENERATOR, GROWTH, FTYPE)
388 GENERATOR(uint8_t, GROWTH, FTYPE)
389 GENERATOR(uint16_t, GROWTH, FTYPE)
390 GENERATOR(uint32_t, GROWTH, FTYPE)
391 GENERATOR(uint64_t, GROWTH, FTYPE)
392 static void(*const GENERATOR$##_$##GROWTH$##_FUNCTIONS[9])(void) = {
393  NULL,
394  (void(*)(void))&GENERATOR$##_$##GROWTH$##_uint8_t,
395  (void(*)(void))&GENERATOR$##_$##GROWTH$##_uint16_t, 0,
396  (void(*)(void))&GENERATOR$##_$##GROWTH$##_uint32_t, 0, 0, 0,
397  (void(*)(void))&GENERATOR$##_$##GROWTH$##_uint64_t };
398 
399 $define GENERATE_GENERICS_GROWTH(FNAME)
400 GENERATE_GENERICS(AARRAY_$##FNAME,NOCAPACITY)
401 GENERATE_GENERICS(AARRAY_$##FNAME,STATIC)
402 GENERATE_GENERICS(AARRAY_$##FNAME,STD)
403 
404 GENERATE_GENERICS_GROWTH(Replace)
405 
406 $define AARRAY_Append(TYPE, GROWTH,)
407 AARRAY_define(TYPE*AARRAY_Append_$##GROWTH$##_$##TYPE(char errLoc[],
408  TYPE*vec[], size_t ilen, TYPE items[]), {
409  size_t pos = vec && *vec?
410  /* get array length */
411  *(*(size_t**)vec-1) : 0;
412  return AARRAY_Replace_$##GROWTH$##_$##TYPE(
413  errLoc, vec, pos, 0, ilen, items); })
414 
415 GENERATE_GENERICS_GROWTH(Append)
416 
417 $define AARRAY_Concat(TYPE, GROWTH,)
418 AARRAY_define(TYPE*AARRAY_Concat_$##GROWTH$##_$##TYPE(char errLoc[],
419  TYPE*vec[], size_t vecsCount, TYPE*vecs_[]), {
420  if(vec) { AARRAY_prefetch((size_t*)*vec-1, 1, 1); }
421  uintptr_t*vecs = (uintptr_t*)vecs_;
422  size_t rlen = 0; size_t ilen = 0;
423  size_t n = (size_t)-1;
424  while(++n < vecsCount) if(vecs[n])
425  ilen += *((size_t*)vecs[n]-1);
426  /* vecs is {vec0, ... ,vecN}, so vsIncr is 1 */
427  size_t vecsIncr = 1;
428  TYPE*vecHolder = NULL; if(!vec) vec = &vecHolder;
429  size_t pos = *vec? *(*(size_t**)vec-1) : 0;
430  AARRAY_Expand(TYPE, GROWTH);
431  if(*vec) {
432  size_t vLen = *(*(size_t**)vec-1);
433  n = (size_t)-1; while(++n < vecsCount) {
434  if(!vecs[n]) continue;
435  size_t ns = (size_t)-1, vsnLen;
436  vsnLen = *((size_t*)vecs[n]-1);
437  while(++ns < vsnLen) (*vec)[vLen+ns] = vecs_[n][ns];
438  vLen += vsnLen; }
439  *(*(size_t**)vec-1) += ilen; }
440  return *vec; })
441 
442 GENERATE_GENERICS_GROWTH(Concat)
443 
444 $define AARRAY_GenericArray(TYPE, GROWTH,)
445 AARRAY_define(TYPE*AARRAY_GenericArray_$##GROWTH$##_$##TYPE(char errLoc[],
446  TYPE*vec[], size_t pos, size_t rlen, size_t vecsCount, uintptr_t vecs[]), {
447  size_t n = 0; size_t alen, ilen = 0;
448  size_t vecsIncr = 2;
449  while(n < vecsCount) {
450  alen = vecs[n];
451  AARRAY_safety(, if(alen && vecs[n+1]==(uintptr_t)NULL)
452  AARRAY_Error_ArrayIsNull((n+2)/2));
453  if(alen==SIZE_MAX) { while(((TYPE*)vecs[n+1])[++alen]) { }
454  vecs[n] = alen; }
455  ilen += alen; n+=vecsIncr; }
456  /* vecs is {len0, array0, ... lenN, arrayN}, so vsIncr is 2 */
457  TYPE*vecHolder = NULL; if(!vec) vec = &vecHolder;
458  AARRAY_Expand(TYPE, GROWTH);
459  if(*vec) {
460  n = 0; while(n < vecsCount) {
461  alen = vecs[n];
462  if(alen) {
463  memcpy(&((*vec)[pos]), (void*)vecs[n+1], sizeof(TYPE)*alen);
464  pos += alen; } n+=vecsIncr; }
465  *(*(size_t**)vec-1) += ilen-rlen; }
466  return *vec; })
467 
468 GENERATE_GENERICS_GROWTH(GenericArray)
469 
470 $define AARRAY_ReplaceArray(TYPE, GROWTH,)
471 AARRAY_define(TYPE*AARRAY_ReplaceArray_$##GROWTH$##_$##TYPE(char errLoc[],
472  TYPE*vec[], size_t pos, size_t rlen, size_t vecsCount, uintptr_t vecs[]), {
473  if(vec) { AARRAY_prefetch((size_t*)*vec-1, 1, 1); }
474  AARRAY_safety(, if((vecsCount+3) % 2 != 1)
475  AARRAY_Error_WrongArgCount(vecsCount+3, 2, 3));
476  return AARRAY_GenericArray_$##GROWTH$##_$##TYPE(
477  errLoc, vec, pos, rlen, vecsCount, vecs); })
478 
479 GENERATE_GENERICS_GROWTH(ReplaceArray)
480 
481 $define AARRAY_AppendArray(TYPE, GROWTH,)
482 AARRAY_define(TYPE*AARRAY_AppendArray_$##GROWTH$##_$##TYPE(char errLoc[],
483  TYPE*vec[], size_t vecsCount, uintptr_t vecs[]), {
484  if(vec) { AARRAY_prefetch((size_t*)*vec-1, 1, 1); }
485  AARRAY_safety(, if((vecsCount+1) % 2 != 1)
486  AARRAY_Error_WrongArgCount(vecsCount+1, 2, 1));
487  size_t pos = vec && *vec? *(*(size_t**)vec-1) : 0;
488  return AARRAY_GenericArray_$##GROWTH$##_$##TYPE(
489  errLoc, vec, pos, 0, vecsCount, vecs); })
490 
491 GENERATE_GENERICS_GROWTH(AppendArray)
492 
493 $define AARRAY_Multi(TYPE, GROWTH,)
494 AARRAY_define(TYPE*AARRAY_Multi_$##GROWTH$##_$##TYPE(char errLoc[],
495  TYPE*vec[], size_t pos, size_t rlen, size_t vecsCount, uintptr_t vecs[]), {
496  if(vec) { AARRAY_prefetch((size_t*)*vec-1, 1, 1); }
497  size_t lengthHolder = 0, *length = &lengthHolder;
498  if(vec && *vec) length = *(size_t**)vec-1;
499  size_t n = 0, alen, ilen = 0, atimes, newlen = *length, maxlen = newlen;
500  size_t saved_pos = pos, saved_rlen = rlen;
501  size_t vecsIncr = 5;
502  AARRAY_safety(, if((vecsCount+3) % 5 != 1)
503  AARRAY_Error_WrongArgCount(vecsCount+3, 5, 1));
504  while(n < vecsCount) {
505  atimes = vecs[n]; alen = vecs[n+1];
506  AARRAY_safety(, if(atimes && alen && !vecs[n+2])
507  AARRAY_Error_ArrayIsNull(n/5+1));
508  if(alen==SIZE_MAX) { while(((TYPE*)vecs[n+2])[++alen]) { }
509  vecs[n+1] = alen; }
510  /* check input, and work out max length required for array */
511  if(n) { pos = vecs[n-2]; rlen = vecs[n-1]; }
512  if(pos > newlen) AARRAY_Error_OutOfBounds(*length, pos)
513  if(rlen > newlen - pos) AARRAY_Error_RemovalIsOutOfBounds(newlen, pos, rlen)
514  ilen = atimes? atimes * alen : alen;
515  newlen += ilen - rlen;
516  if(newlen > maxlen) maxlen = newlen;
517  n+=vecsIncr; }
518  ilen = maxlen - *length; rlen = 0;
519  /* vecs is {times0, len0, array0, ... timesN, lenN, arrayN}, so vsIncr is 3 */
520  TYPE*vecHolder = NULL; if(!vec) vec = &vecHolder;
521  AARRAY_ALLOC_$##GROWTH(TYPE)
522  if(*vec) {
523  n = 0; pos = saved_pos; rlen = saved_rlen;
524  do {
525  atimes = vecs[n]; alen = vecs[n+1];
526  if(n) { pos = vecs[n-2]; rlen = vecs[n-1]; }
527  ilen = atimes? atimes * alen : alen;
528  if(ilen-rlen) {
529  memmove(&((*vec)[pos+ilen]), &((*vec)[pos+rlen]),
530  sizeof(TYPE) * ((*length) - (pos+rlen)));
531  *length += ilen-rlen; }
532  if(!atimes) {}
533  else while(atimes--) {
534  memcpy(&((*vec)[pos]), (void*)vecs[n+2], sizeof(TYPE) * alen);
535  pos += alen; }
536  n+=vecsIncr;
537  } while(n < vecsCount); }
538  return *vec; })
539 
540 GENERATE_GENERICS_GROWTH(Multi)
541 
542 $define AARRAY_Mem(TYPE, GROWTH,)
543 AARRAY_define(TYPE*AARRAY_Mem_$##GROWTH$##_$##TYPE(
544  char errLoc[], size_t vec[]), {
545  (void)errLoc;
546  if(!vec) return NULL;
547  if($exec [ GROWTH = NOCAPACITY ] && echo '1) {' || echo '0) {'
548  return (TYPE*)(vec-1); }
549  return (TYPE*)(vec-2); })
550 
551 GENERATE_GENERICS_GROWTH(Mem)
552 
553 $define AARRAY_Array(TYPE, GROWTH,)
554 AARRAY_define(TYPE*AARRAY_Array_$##GROWTH$##_$##TYPE(
555  char errLoc[], size_t vec[], size_t sizebytes, int maximize), {
556  AARRAY_safety((void)errLoc;, if(!vec) AARRAY_Error_ArrayIsNull((size_t)0));
557  if($exec [ GROWTH = NOCAPACITY ] && echo '1) {' || echo '0) {'
558  AARRAY_safety(,if(sizebytes < sizeof(size_t) ) AARRAY_Error_OutOfCapacity(sizebytes, sizeof(size_t) ))
559  /* greatest len power-of-two that fits sizebytes */
560  size_t len = ((size_t)1)<<(63-AARRAY_clz((sizebytes-sizeof(size_t))/sizeof(TYPE)));
561  if(maximize || len < *vec) *vec = len;
562  return (TYPE*)(vec+1); }
563  else {
564  AARRAY_safety(,if(sizebytes < sizeof(size_t)*2) AARRAY_Error_OutOfCapacity(sizebytes, sizeof(size_t)*2))
565  size_t len = (sizebytes - sizeof(size_t)*2) / sizeof(TYPE);
566  if(maximize || len < *(vec+1)) *(vec+1) = len;
567  *vec = sizebytes;
568  return (TYPE*)(vec+2); } })
569 
570 GENERATE_GENERICS_GROWTH(Array)
571 
572 
573 
574 
575 /* get the number of var-arg arguments, and make them generic */
576 $define AARRAY_Args(sizeofType, ...) AARRAY_nowarn_internal_start \
577  (sizeofType==1? sizeof((uint8_t []){(uint8_t)(uintptr_t)__VA_ARGS__}) : \
578  sizeofType==2? sizeof((uint16_t[]){(uint16_t)(uintptr_t)__VA_ARGS__}) : \
579  sizeofType<=4? sizeof((uint32_t[]){(uint32_t)(uintptr_t)__VA_ARGS__}) : \
580  sizeof((uint64_t[]){(uint64_t)(uintptr_t)__VA_ARGS__})) / sizeofType, \
581  (sizeofType==1? (void*)AARRAY_move((uint8_t []){(uint8_t)(uintptr_t)__VA_ARGS__}) : \
582  sizeofType==2? (void*)AARRAY_move((uint16_t[]){(uint16_t)(uintptr_t)__VA_ARGS__}) : \
583  sizeofType<=4? (void*)AARRAY_move((uint32_t[]){(uint32_t)(uintptr_t)__VA_ARGS__}) : \
584  (void*)AARRAY_move((uint64_t[]){(uint64_t)(uintptr_t)__VA_ARGS__})) \
585  AARRAY_nowarn_internal_end
586 
587 /* as above, but for 64 bit only, such as aFmt */
588 $define AARRAY_64bitArgs(...) AARRAY_nowarn_internal_start \
589 sizeof((uint64_t[]){(uint64_t)__VA_ARGS__}) / sizeof(uint64_t), \
590  (uint64_t*)AARRAY_move((uint64_t[]){(uint64_t)(uintptr_t)__VA_ARGS__}) \
591  AARRAY_nowarn_internal_end
592 
593 /* make c++ happy */
594 $define AARRAY_PtrArgs_WARN(...) \
595  sizeof((void*[]){(void*)__VA_ARGS__}) / sizeof(void*), \
596  (uintptr_t*)AARRAY_move((void*[]){(void*)__VA_ARGS__})
597 
598 /* as above, but hide compiler warnings for mixed int/pointer arrays
599  * uintptr_t conversion of first arg resolves gcc issue
600  */
601 $define AARRAY_PtrArgs(...) AARRAY_nowarn_internal_start \
602  sizeof((uintptr_t[]){(uintptr_t)__VA_ARGS__}) / sizeof(uintptr_t), \
603  (uintptr_t*)AARRAY_move((uintptr_t[]){(uintptr_t)__VA_ARGS__}) \
604  AARRAY_nowarn_internal_end
605 
606 /* get around requirement for __VA_ARGS__ to not be empty */
607 #define AARRAY_ArgsTail(A, ...) __VA_ARGS__
608 
609 #if defined(AARRAY_NOTYPEOF) \
610  || (defined(_MSC_VER) && !__has_feature(cxx_decltype))
611 /* create api functions without type-casts */
612 #define AARRAY_typeof(TYPE, EXPR) EXPR
613 #elif __has_feature(cxx_decltype)
614 /* +0 resolves c++ compliance */
615 #define AARRAY_typeof(TYPE, EXPR) (__decltype(TYPE+0))(EXPR)
616 #else
617 #define AARRAY_typeof(TYPE, EXPR) \
618  AARRAY_nowarn_internal_start (__typeof(TYPE))(EXPR) AARRAY_nowarn_internal_end
619 #endif
620 
621 $define TEST_width(type) sizeof(type) > 8 ? AARRAY_Error_ArrayIsWide : sizeof(type)
622 
623 /* generate the main apis for c, c++, and compilers without __typeof support */
624 $define GENERATE_api(NAME, GROWTH)
625 #define aAppend$##NAME(vec, ...) \
626  (AARRAY_typeof(*vec, (void*(*)(char[], void**, size_t, void*)) \
627  AARRAY_Append_$##GROWTH$##_FUNCTIONS[TEST_width(**vec)]) \
628  (AARRAY_LINE, (void**)vec, AARRAY_Args(sizeof(**vec), __VA_ARGS__)))
629 #define aReplace$##NAME(vec, pos, rlen, ...) \
630  (AARRAY_typeof(*vec, (void*(*)( \
631  char[], void**, size_t, size_t, size_t, void*)) \
632  AARRAY_Replace_$##GROWTH$##_FUNCTIONS[TEST_width(**vec)]) \
633  (AARRAY_LINE, (void**)vec, pos, rlen, \
634  AARRAY_Args(sizeof(**vec), __VA_ARGS__)))
635 #define aDelete$##NAME(vec, pos, rlen) \
636  (AARRAY_typeof(*vec, (void*(*)( \
637  char[], void**, size_t, size_t, size_t, void*)) \
638  AARRAY_Replace_$##GROWTH$##_FUNCTIONS[TEST_width(**vec)]) \
639  (AARRAY_LINE, (void**)vec, pos, rlen, 0, NULL))
640 #define aConcat$##NAME(vec, ...) \
641  (AARRAY_typeof(*vec, (void*(*)(char[], void**, size_t, uintptr_t*)) \
642  AARRAY_Concat_$##GROWTH$##_FUNCTIONS[TEST_width(**vec)]) \
643  (AARRAY_LINE, (void**)vec, AARRAY_PtrArgs_WARN(__VA_ARGS__)))
644 #define aAppendArray$##NAME(vec, ...) \
645  (AARRAY_typeof(*vec, (void*(*)(char[], void**, size_t, uintptr_t*)) \
646  AARRAY_AppendArray_$##GROWTH$##_FUNCTIONS[TEST_width(**vec)]) \
647  (AARRAY_LINE, (void**)vec, AARRAY_PtrArgs(__VA_ARGS__)))
648 #define aReplaceArray$##NAME(vec, pos, rlen, ...) \
649  (AARRAY_typeof(*vec, (void*(*)( \
650  char[], void**, size_t, size_t, size_t, uintptr_t*)) \
651  AARRAY_ReplaceArray_$##GROWTH$##_FUNCTIONS[TEST_width(**vec)]) \
652  (AARRAY_LINE, (void**)vec, pos, rlen, AARRAY_PtrArgs(__VA_ARGS__)))
653 #define aMulti$##NAME(vec, pos, rlen, arrTimes, ...) \
654  (AARRAY_typeof(*vec, (void*(*)( \
655  char[], void**, size_t, size_t, size_t, uintptr_t*)) \
656  AARRAY_Multi_$##GROWTH$##_FUNCTIONS[TEST_width(**vec)]) \
657  (AARRAY_LINE, (void**)vec, pos, rlen, \
658  AARRAY_PtrArgs(arrTimes, __VA_ARGS__)))
659 #define aMem$##NAME(vec) \
660  (AARRAY_typeof(vec, (void*(*)(char[], void*)) \
661  AARRAY_Mem_$##GROWTH$##_FUNCTIONS[TEST_width(*vec)]) \
662  (AARRAY_LINE, (void*)vec))
663 #define aArray$##NAME(vec, size, maximize) \
664  (AARRAY_typeof(vec, (void*(*)(char[], void*, size_t, int)) \
665  AARRAY_Array_$##GROWTH$##_FUNCTIONS[TEST_width(*vec)]) \
666  (AARRAY_LINE, (void*)vec, size, maximize))
667 
668 GENERATE_api(_NOCAPACITY, NOCAPACITY)
669 GENERATE_api(_STATIC, STATIC)
670 GENERATE_api(, STD)
671 
672 /* make pointer casts safer: ensuring data can become (void$##stars)data */
673 $define safe_void(stars, data)
674 0?(void$##stars)(uintptr_t)sizeof( \
675  stars$##data/* stars$##ptr check failed --- use (type**) --- */ \
676  ):(void$##stars)data
677 
678 AARRAY_define(void AARRAY_Free(void*vec[]), {
679  if(*vec) { free((size_t*)*vec-2); *vec = NULL; } })
680 AARRAY_define(void AARRAY_Free_STATIC(void*vec[]), {
681  AARRAY_Free(vec); }) /* to make stack traces clearer */
682 AARRAY_define(void AARRAY_Free_NOCAPACITY(void*vec[]), {
683  if(*vec) { free((size_t*)*vec-1); *vec = NULL; } })
684 #define aFree(vec) \
685  AARRAY_Free(safe_void(**,vec))
686 #define aFree_STATIC(vec) \
687  AARRAY_Free_STATIC(safe_void(**,vec))
688 #define aFree_NOCAPACITY(vec) \
689  AARRAY_Free_NOCAPACITY(safe_void(**,vec))
690 
691 
692 
693 
694 /* supporting api */
695 AARRAY_define(size_t AARRAY_aCapacity(void*vec), {
696  return !vec? 0 : *((size_t*)vec-2) - sizeof(size_t)*2; })
697 AARRAY_define(size_t AARRAY_aCapacity_STATIC(void*vec), {
698  return AARRAY_aCapacity(vec); })
699 AARRAY_define(size_t AARRAY_aCapacity_NOCAPACITY(void*vec), {
700  return !vec? 0 : ((size_t)1) << (64-AARRAY_clz((*((size_t*)vec-1))-1)); })
701 #define aCapacity(vec) (AARRAY_aCapacity(safe_void(*,vec))/sizeof(*vec))
702 #define aCapacity_STATIC(vec) (AARRAY_aCapacity_STATIC(safe_void(*,vec))/sizeof(*vec))
703 #define aCapacity_NOCAPACITY(vec) AARRAY_aCapacity_NOCAPACITY(safe_void(*,vec))
704 
705 AARRAY_define(size_t AARRAY_aLength(void*vec), {
706  return !vec? 0 : *((size_t*)vec-1); })
707 #define aLength(vec) AARRAY_aLength(safe_void(*,vec))
708 
709 $define AARRAY_Length2(TYPE, ...)
710 AARRAY_define(TYPE AARRAY_Length2__$##TYPE(
711  char errLoc[], TYPE vec[], size_t pos), {
712  if(!vec) AARRAY_safety(return 0; (void)errLoc;,
713  { if(pos==0) return 0; else AARRAY_Error_OutOfBounds(aLength(vec), pos); })
714  size_t*length = (size_t*)(void*)vec-1;
715  AARRAY_safety(, if(pos > *length)
716  AARRAY_Error_OutOfBounds(aLength(vec), pos));
717  *length = pos;
718  /* if(pos==0) { pos-1 would index into *length (which is 0);
719  so vec[pos-1] is safe and returns 0 } */
720  if(pos==0) return 0; /* but keep it sanitizer safe */
721  return vec[pos-1]; })
722 
723 GENERATE_GENERICS(AARRAY_Length2)
724 #define aLength2(vec, len) \
725  AARRAY_typeof(*vec, (uint64_t(*)(char[], void*, size_t)) \
726  AARRAY_Length2__FUNCTIONS[TEST_width(*vec)]) \
727  (AARRAY_LINE, (void*)vec, len)
728 
729 $define AARRAY_ZLength2(TYPE, ...)
730 AARRAY_define(TYPE AARRAY_ZLength2__$##TYPE(
731  char errLoc[], TYPE vec[], size_t pos), {
732  return AARRAY_Length2__$##TYPE(errLoc, vec, aLength(vec) - pos); })
733 
734 GENERATE_GENERICS(AARRAY_ZLength2)
735 #define aZLength2(vec, len) \
736  (AARRAY_typeof(*vec, (uint64_t(*)(char[], void*, size_t)) \
737  AARRAY_ZLength2__FUNCTIONS[TEST_width(*vec)]) \
738  (AARRAY_LINE, (void*)vec, len))
739 
740 $define AARRAY_AtPtr(TYPE, ...)
741 AARRAY_define(TYPE*AARRAY_AtPtr__$##TYPE(
742  char errLoc[], TYPE vec[], size_t pos), {
743  AARRAY_safety((void)errLoc;,
744  if(pos >= aLength(vec)) AARRAY_Error_OutOfBounds(aLength(vec), pos));
745  return &(vec[pos]); })
746 
747 GENERATE_GENERICS(AARRAY_AtPtr)
748 #define aAtPtr(vec, pos) \
749  (AARRAY_typeof(vec, (uint64_t*(*)(char[], void*, size_t)) \
750  AARRAY_AtPtr__FUNCTIONS[TEST_width(*vec)]) \
751  (AARRAY_LINE, (void*)vec, pos))
752 
753 $define AARRAY_ZAtPtr(TYPE, ...)
754 AARRAY_define(TYPE*AARRAY_ZAtPtr__$##TYPE(
755  char errLoc[], TYPE vec[], size_t pos), {
756  return AARRAY_AtPtr__$##TYPE(errLoc, vec, aLength(vec) - (pos+1)); })
757 
758 GENERATE_GENERICS(AARRAY_ZAtPtr)
759 #define aZAtPtr(vec, pos) \
760  (AARRAY_typeof(vec, (uint64_t*(*)(char[], void*, size_t)) \
761  AARRAY_ZAtPtr__FUNCTIONS[TEST_width(*vec)]) \
762  (AARRAY_LINE, (void*)vec, pos))
763 
764 $define AARRAY_At(TYPE, ...)
765 AARRAY_define(TYPE AARRAY_At__$##TYPE(
766  char errLoc[], TYPE vec[], size_t pos), {
767  AARRAY_safety((void)errLoc;,
768  if(pos >= aLength(vec)) AARRAY_Error_OutOfBounds(aLength(vec), pos));
769  return vec[pos]; })
770 
771 GENERATE_GENERICS(AARRAY_At)
772 #define aAt(vec, pos) \
773  (AARRAY_typeof(*vec, (uint64_t(*)(char[], void*, size_t)) \
774  AARRAY_At__FUNCTIONS[TEST_width(*vec)]) \
775  (AARRAY_LINE, (void*)vec, pos))
776 
777 $define AARRAY_ZAt(TYPE, ...)
778 AARRAY_define(TYPE AARRAY_ZAt__$##TYPE(
779  char errLoc[], TYPE vec[], size_t pos), {
780  return AARRAY_At__$##TYPE(errLoc, vec, aLength(vec) - (pos+1)); })
781 
782 GENERATE_GENERICS(AARRAY_ZAt)
783 #define aZAt(vec, pos) \
784  (AARRAY_typeof(*vec, (uint64_t(*)(char[], void*, size_t)) \
785  AARRAY_ZAt__FUNCTIONS[TEST_width(*vec)]) \
786  (AARRAY_LINE, (void*)vec, pos))
787 
788 $define AARRAY_At2(TYPE, ...)
789 AARRAY_define(TYPE AARRAY_At2__$##TYPE(
790  char errLoc[], TYPE vec[], size_t pos, TYPE item), {
791  AARRAY_safety((void)errLoc;,
792  if(pos >= aLength(vec)) AARRAY_Error_OutOfBounds(aLength(vec), pos));
793  vec[pos] = item;
794  return item; })
795 
796 GENERATE_GENERICS(AARRAY_At2)
797 #define aAt2(vec, pos, item) \
798  (AARRAY_typeof(*vec, (uint64_t(*)(char[], void*, size_t, uint64_t)) \
799  AARRAY_At2__FUNCTIONS[TEST_width(*vec)]) \
800  (AARRAY_LINE, (void*)vec, pos, \
801  AARRAY_nowarn_internal_start (uint64_t)item AARRAY_nowarn_internal_end))
802 
803 $define AARRAY_ZAt2(TYPE, ...)
804 AARRAY_define(TYPE AARRAY_ZAt2__$##TYPE(
805  char errLoc[], TYPE vec[], size_t pos, TYPE item), {
806  return AARRAY_At2__$##TYPE(errLoc, vec, aLength(vec) - (pos+1), item); })
807 
808 GENERATE_GENERICS(AARRAY_ZAt2)
809 #define aZAt2(vec, pos, item) \
810  (AARRAY_typeof(*vec, (uint64_t(*)(char[], void*, size_t, uint64_t)) \
811  AARRAY_ZAt2__FUNCTIONS[TEST_width(*vec)]) \
812  (AARRAY_LINE, (void*)vec, pos, \
813  AARRAY_nowarn_internal_start item AARRAY_nowarn_internal_end))
814 
815 $define AARRAY_Cmp(TYPE, ...)
816 AARRAY_define(int AARRAY_Cmp__$##TYPE(
817  TYPE vec[], size_t n, TYPE*vecs[]), {
818  while(n--) {
819  if(vec == vecs[n]) continue;
820  if(aLength(vec) != aLength(vecs[n])) return 0;
821  if(aLength(vec)==0) continue;
822  /* surely memcmp would work, but this upsets MSan
823  memcmp(((size_t*)(uintptr_t)vec-1), ((size_t*)(uintptr_t)vecs[n]-1),
824  aLength(vec)*sizeof(TYPE)+sizeof(size_t)); */
825  size_t m = SIZE_MAX; while(++m < aLength(vec)) if(vec[m]!=vecs[n][m]) return 0; }
826  return 1; })
827 
828 GENERATE_GENERICS(AARRAY_Cmp)
829 #define aCmp(vec, ...) \
830  (((int(*)(void*, size_t, void*)) \
831  AARRAY_Cmp__FUNCTIONS[TEST_width(*vec)]) \
832  ((void*)vec, AARRAY_PtrArgs_WARN(__VA_ARGS__)))
833 
834 $define AARRAY_IndexOf(TYPE, ...)
835 AARRAY_define(size_t AARRAY_IndexOf__$##TYPE(TYPE vec[], TYPE item), {
836  size_t length = aLength(vec), i = (size_t)-1;
837  while(++i < length) if(vec[i]==item) return i;
838  return (size_t)-1; })
839 
840 GENERATE_GENERICS(AARRAY_IndexOf,)
841 #define aIndexOf(vec, item) \
842  ((size_t(*)(void*, uint64_t)) \
843  AARRAY_IndexOf__FUNCTIONS[TEST_width(*vec)])(vec, \
844  AARRAY_nowarn_internal_start item AARRAY_nowarn_internal_end)
845 
846 $define AARRAY_ZIndexOf(TYPE, ...)
847 AARRAY_define(size_t AARRAY_ZIndexOf__$##TYPE(TYPE vec[], TYPE item), {
848  size_t i = aLength(vec);
849  while(i--) if(vec[i]==item) return i;
850  return (size_t)-1; })
851 
852 GENERATE_GENERICS(AARRAY_ZIndexOf,)
853 #define aZIndexOf(vec, item) \
854  ((size_t(*)(void*, uint64_t)) \
855  AARRAY_ZIndexOf__FUNCTIONS[TEST_width(*vec)])(vec, \
856  AARRAY_nowarn_internal_start item AARRAY_nowarn_internal_end)
857 
858 
859 
860 
861 $define AARRAY_Map(TYPE, FNAME, FTYPE)
862 AARRAY_define(void AARRAY_Map_$##FNAME$##_$##TYPE(
863  char errLoc[], TYPE vec[], FTYPE(TYPE)), {
864  AARRAY_safety((void)errLoc, if(!f) AARRAY_Error_NullParameter);
865  size_t n = (size_t)-1;
866  /* only FUNC versions use extra data parameter */
867  while(++n < aLength(vec)) f(&(vec[n]) $exec case 'FTYPE()' in *'data') echo ', data';; esac; echo '); })'
868 
869 $define AARRAY_Loop(TYPE, FNAME, FTYPE)
870 AARRAY_define(int AARRAY_Loop_$##FNAME$##_$##TYPE(
871  char errLoc[], TYPE vec[], size_t pos, FTYPE), {
872  AARRAY_safety((void)errLoc, if(!f) AARRAY_Error_NullParameter);
873  int offset = 0;
874  while(pos < aLength(vec)) {
875  if((offset > 0 && pos < (size_t)offset) ||
876  (offset < 0 && pos > (size_t)offset)) return offset;
877  offset = f(pos $exec case 'FTYPE' in *'data') echo ', data';; esac; echo ');'
878  if(!offset) return 0;
879  /* play safe with int promotion */
880  if(offset > 0) pos += (size_t) offset;
881  else pos -= (size_t)-offset; }
882  return offset; })
883 
884 $define AARRAY_Filter(TYPE, FNAME, FTYPE)
885 AARRAY_define(TYPE* AARRAY_Filter_$##FNAME$##_$##TYPE(
886  char errLoc[], TYPE vec[], FTYPE(TYPE)), {
887  AARRAY_safety((void)errLoc, if(!f) AARRAY_Error_NullParameter);
888  size_t n = (size_t)-1, nn = (size_t)-1;
889  while(++n < aLength(vec)) {
890  if(f(vec[n] $exec case 'FTYPE()' in *'data') echo ', data';; esac; echo '))'
891  vec[++nn] = vec[n]; }
892  (void)aLength2(vec, nn+1);
893  return vec; })
894 
895 $define FUNC_void_ptrT__D(TYPE) void(*f)(TYPE*, void*), void*data
896 
897 $define FUNC_void_ptrT(TYPE) void(*f)(TYPE*)
898 
899 GENERATE_GENERICS(AARRAY_Map, FUNC_3, FUNC_void_ptrT__D)
900 GENERATE_GENERICS(AARRAY_Map, FUNC_2, FUNC_void_ptrT)
901 #define AARRAY_aMap_FUNC_3(vec, f, data) \
902  ((void(*)(char[], void*, void(*)(void), void*)) \
903  AARRAY_Map_FUNC_3_FUNCTIONS[TEST_width(*vec)])(AARRAY_LINE, vec, (void(*)(void))f, data)
904 #define AARRAY_aMap_FUNC_2(vec, f) \
905  ((void(*)(char[], void*, void(*)(void))) \
906  AARRAY_Map_FUNC_2_FUNCTIONS[TEST_width(*vec)])(AARRAY_LINE, vec, (void(*)(void))f)
907 $define FUNC_int_size__D int(*f)(size_t, void*), void*data
908 
909 GENERATE_GENERICS(AARRAY_Loop, FUNC_4, FUNC_int_size__D)
910 GENERATE_GENERICS(AARRAY_Loop, FUNC_3, int(*f)(size_t))
911 #define AARRAY_aLoop_FUNC_4(vec, pos, f, data) \
912  ((int(*)(char[], void*, size_t, int(*)(size_t, void*), void*)) \
913  AARRAY_Loop_FUNC_4_FUNCTIONS[TEST_width(*vec)])(AARRAY_LINE, vec, pos, f, data)
914 #define AARRAY_aLoop_FUNC_3(vec, pos, f) \
915  ((int(*)(char[], void*, size_t, int(*)(size_t))) \
916  AARRAY_Loop_FUNC_3_FUNCTIONS[TEST_width(*vec)])(AARRAY_LINE, vec, pos, f)
917 $define FUNC_int_T__D(TYPE) int(*f)(TYPE, void*), void*data
918 
919 $define FUNC_int_T(TYPE) int(*f)(TYPE)
920 
921 GENERATE_GENERICS(AARRAY_Filter, FUNC_3, FUNC_int_T__D)
922 GENERATE_GENERICS(AARRAY_Filter, FUNC_2, FUNC_int_T)
923 #define AARRAY_aFilter_FUNC_3(vec, f, data) \
924  (AARRAY_typeof(vec, (uint64_t*(*)(char[], void*, void(*)(void), void*)) \
925  AARRAY_Filter_FUNC_3_FUNCTIONS[TEST_width(*vec)]) \
926  (AARRAY_LINE, vec,(void(*)(void))f, data))
927 #define AARRAY_aFilter_FUNC_2(vec, f) \
928  (AARRAY_typeof(vec, (uint64_t*(*)(char[], void*, void(*)(void))) \
929  AARRAY_Filter_FUNC_2_FUNCTIONS[TEST_width(*vec)]) \
930  (AARRAY_LINE, vec,(void(*)(void))f))
931 
932 #if __has_extension(blocks)
933 $define BLOCK_void_ptrT__D(TYPE) void(^f)(TYPE*, void*), void*data
934 
935 $define BLOCK_void_ptrT(TYPE) void(^f)(TYPE*)
936 
937 GENERATE_GENERICS(AARRAY_Map, BLOCK_3, BLOCK_void_ptrT__D)
938 GENERATE_GENERICS(AARRAY_Map, BLOCK_2, BLOCK_void_ptrT)
939 #define AARRAY_aMap_BLOCK_3(vec, f, data) \
940  ((void(*)(char[], void*, void(^)(void*, void*), void*)) \
941  AARRAY_Map_BLOCK_3_FUNCTIONS[TEST_width(*vec)]) \
942  (AARRAY_LINE, vec, (void(^)(void*, void*))f, data)
943 #define AARRAY_aMap_BLOCK_2(vec, f) \
944  ((void(*)(char[], void*, void(^)(void*))) \
945  AARRAY_Map_BLOCK_2_FUNCTIONS[TEST_width(*vec)]) \
946  (AARRAY_LINE, vec, (void(^)(void*))f)
947 $define BLOCK_int_size__D int(^f)(size_t, void*), void*data
948 
949 GENERATE_GENERICS(AARRAY_Loop, BLOCK_4, BLOCK_int_size__D)
950 GENERATE_GENERICS(AARRAY_Loop, BLOCK_3, int (^f)(size_t))
951 #define AARRAY_aLoop_BLOCK_4(vec, pos, f, data) \
952  ((int(*)(char[], void*, size_t, int(^)(size_t, void*), void*)) \
953  AARRAY_Loop_BLOCK_4_FUNCTIONS[TEST_width(*vec)])(AARRAY_LINE, vec, pos, f, data)
954 #define AARRAY_aLoop_BLOCK_3(vec, pos, f) \
955  ((int(*)(char[], void*, size_t, int(^)(size_t))) \
956  AARRAY_Loop_BLOCK_3_FUNCTIONS[TEST_width(*vec)])(AARRAY_LINE, vec, pos, f)
957 $define BLOCK_int_T__D(TYPE) int(^f)(TYPE, void*), void*data
958 
959 $define BLOCK_int_T(TYPE) int(^f)(TYPE)
960 
961 GENERATE_GENERICS(AARRAY_Filter, BLOCK_3, BLOCK_int_T__D)
962 GENERATE_GENERICS(AARRAY_Filter, BLOCK_2, BLOCK_int_T)
963 #define AARRAY_aFilter_BLOCK_3(vec, f, data) \
964  (AARRAY_typeof(vec, (uint64_t*(*)(char[], void*, int(^)(uint64_t, void*), void*)) \
965  AARRAY_Filter_BLOCK_3_FUNCTIONS[TEST_width(*vec)]) \
966  (AARRAY_LINE, vec,(int(^)(uint64_t, void*))f, data))
967 #define AARRAY_aFilter_BLOCK_2(vec, f) \
968  (AARRAY_typeof(vec, (uint64_t*(*)(char[], void*, int(^)(uint64_t))) \
969  AARRAY_Filter_BLOCK_2_FUNCTIONS[TEST_width(*vec)]) \
970  (AARRAY_LINE, vec,(int(^)(uint64_t))f))
971 #endif
972 
973 #if defined(__cplusplus)
974 $define LAMBDA_void_ptrT__D(TYPE) std::function<void(TYPE*, void*)> f, void*data
975 
976 $define LAMBDA_void_ptrT(TYPE) std::function<void(TYPE*)> f
977 
978 GENERATE_GENERICS(AARRAY_Map, LAMBDA_3, LAMBDA_void_ptrT__D)
979 GENERATE_GENERICS(AARRAY_Map, LAMBDA_2, LAMBDA_void_ptrT)
980 #define AARRAY_aMap_LAMBDA_3(vec, f, data) \
981  ((void(*)(char[], void*, std::function<void(void*, void*)>, void*)) \
982  AARRAY_Map_LAMBDA_3_FUNCTIONS[TEST_width(*vec)])(AARRAY_LINE, vec, f, data)
983 #define AARRAY_aMap_LAMBDA_2(vec, f) \
984  ((void(*)(char[], void*, std::function<void(void*)>)) \
985  AARRAY_Map_LAMBDA_2_FUNCTIONS[TEST_width(*vec)])(AARRAY_LINE, vec, f)
986 $define LAMBDA_int_size__D std::function<int(size_t, void*)> f, void*data
987 
988 GENERATE_GENERICS(AARRAY_Loop, LAMBDA_4, LAMBDA_int_size__D)
989 GENERATE_GENERICS(AARRAY_Loop, LAMBDA_3, std::function<int(size_t)> f)
990 #define AARRAY_aLoop_LAMBDA_4(vec, pos, f, data) \
991  ((int(*)(char[], void*, size_t, std::function<int(size_t, void*)>, void*)) \
992  AARRAY_Loop_LAMBDA_4_FUNCTIONS[TEST_width(*vec)])(AARRAY_LINE, vec, pos, f, data)
993 #define AARRAY_aLoop_LAMBDA_3(vec, pos, f) \
994  ((int(*)(char[], void*, size_t, std::function<int(size_t)>)) \
995  AARRAY_Loop_LAMBDA_3_FUNCTIONS[TEST_width(*vec)])(AARRAY_LINE, vec, pos, f)
996 $define LAMBDA_int_T__D(TYPE) std::function<int(TYPE, void*)> f, void*data
997 
998 $define LAMBDA_int_T(TYPE) std::function<int(TYPE)> f
999 
1000 GENERATE_GENERICS(AARRAY_Filter, LAMBDA_3, LAMBDA_int_T__D)
1001 GENERATE_GENERICS(AARRAY_Filter, LAMBDA_2, LAMBDA_int_T)
1002 #define AARRAY_aFilter_LAMBDA_3(vec, f, data) \
1003  (AARRAY_typeof(vec, (uint64_t*(*)(char[], void*, std::function<int(uint64_t, void*)>, void*))\
1004  AARRAY_Filter_LAMBDA_3_FUNCTIONS[TEST_width(*vec)])(AARRAY_LINE, vec, f, data))
1005 #define AARRAY_aFilter_LAMBDA_2(vec, f) \
1006  (AARRAY_typeof(vec, (uint64_t*(*)(char[], void*, std::function<int(uint64_t)>))\
1007  AARRAY_Filter_LAMBDA_2_FUNCTIONS[TEST_width(*vec)])(AARRAY_LINE, vec, f))
1008 #endif
1009 
1010 /* aFold is generic over array_type, function_type, AND base_type
1011  * Rather than make previous cppp macros more generic, we treat aFold as unique
1012  * Though it's possible to create macros that genericize any c function
1013  * Which would be useful...
1014  */
1015 $define AARRAY_Fold(TYPEB, TYPE, FNAME, FTYPE)
1016 AARRAY_define(TYPEB AARRAY_Fold_$##FNAME$##_$##TYPEB$##_$##TYPE(
1017  char errLoc[], TYPE*vec, TYPEB base,
1018  FTYPE(TYPEB,TYPE)), {
1019  AARRAY_safety((void)errLoc, if(!f) AARRAY_Error_NullParameter);
1020  size_t n = (size_t)-1;
1021  while(++n < aLength(vec)) base = f(base,vec[n] $exec case 'FTYPE(,)' in *'data') echo ', data';; esac; echo ');'
1022  return base; })
1023 
1024 $define AARRAY_Fold_TYPEB(TYPE, FNAME, FTYPE)
1025 AARRAY_Fold(uint8_t, TYPE, FNAME, FTYPE)
1026 AARRAY_Fold(uint16_t, TYPE, FNAME, FTYPE)
1027 AARRAY_Fold(uint32_t, TYPE, FNAME, FTYPE)
1028 AARRAY_Fold(uint64_t, TYPE, FNAME, FTYPE)
1029 
1030 $define AARRAY_Fold_FNAME(FNAME, FTYPE)
1031 AARRAY_Fold_TYPEB(uint8_t, FNAME, FTYPE)
1032 AARRAY_Fold_TYPEB(uint16_t, FNAME, FTYPE)
1033 AARRAY_Fold_TYPEB(uint32_t, FNAME, FTYPE)
1034 AARRAY_Fold_TYPEB(uint64_t, FNAME, FTYPE)
1035 static void(*const AARRAY_Fold_$##FNAME$##_FUNCTIONS[9][9])(void) = { {
1036  NULL }, {
1037  NULL,
1038  (void(*)(void))&AARRAY_Fold_$##FNAME$##_uint8_t_uint8_t,
1039  (void(*)(void))&AARRAY_Fold_$##FNAME$##_uint8_t_uint16_t, 0,
1040  (void(*)(void))&AARRAY_Fold_$##FNAME$##_uint8_t_uint32_t, 0, 0, 0,
1041  (void(*)(void))&AARRAY_Fold_$##FNAME$##_uint8_t_uint64_t }, {
1042  NULL,
1043  (void(*)(void))&AARRAY_Fold_$##FNAME$##_uint16_t_uint8_t,
1044  (void(*)(void))&AARRAY_Fold_$##FNAME$##_uint16_t_uint16_t, 0,
1045  (void(*)(void))&AARRAY_Fold_$##FNAME$##_uint16_t_uint32_t, 0, 0, 0,
1046  (void(*)(void))&AARRAY_Fold_$##FNAME$##_uint16_t_uint64_t }, {0}, {
1047  NULL,
1048  (void(*)(void))&AARRAY_Fold_$##FNAME$##_uint32_t_uint8_t,
1049  (void(*)(void))&AARRAY_Fold_$##FNAME$##_uint32_t_uint16_t, 0,
1050  (void(*)(void))&AARRAY_Fold_$##FNAME$##_uint32_t_uint32_t, 0, 0, 0,
1051  (void(*)(void))&AARRAY_Fold_$##FNAME$##_uint32_t_uint64_t }, {0}, {0}, {0}, {
1052  NULL,
1053  (void(*)(void))&AARRAY_Fold_$##FNAME$##_uint64_t_uint8_t,
1054  (void(*)(void))&AARRAY_Fold_$##FNAME$##_uint64_t_uint16_t, 0,
1055  (void(*)(void))&AARRAY_Fold_$##FNAME$##_uint64_t_uint32_t, 0, 0, 0,
1056  (void(*)(void))&AARRAY_Fold_$##FNAME$##_uint64_t_uint64_t } };
1057 
1058 $define AARRAY_FUNCTION_TB_TB_T__D(TYPEB, TYPE) TYPEB(*f)(TYPEB,TYPE, void*), void*data
1059 
1060 $define AARRAY_FUNCTION_TB_TB_T(TYPEB, TYPE) TYPEB(*f)(TYPEB,TYPE)
1061 
1062 AARRAY_Fold_FNAME(FUNC_4, AARRAY_FUNCTION_TB_TB_T__D)
1063 AARRAY_Fold_FNAME(FUNC_3, AARRAY_FUNCTION_TB_TB_T)
1064 #define AARRAY_aFold_FUNC_4(vec, base, f, data) \
1065  (AARRAY_typeof(base, (uint64_t(*)(char[], void*, uint64_t, void(*)(void), void*)) \
1066  AARRAY_Fold_FUNC_4_FUNCTIONS[TEST_width(base)][TEST_width(*vec)]) \
1067  (AARRAY_LINE, vec, (uint64_t)base, (void(*)(void))f, data))
1068 #define AARRAY_aFold_FUNC_3(vec, base, f) \
1069  (AARRAY_typeof(base, (uint64_t(*)(char[], void*, uint64_t, void(*)(void))) \
1070  AARRAY_Fold_FUNC_3_FUNCTIONS[TEST_width(base)][TEST_width(*vec)]) \
1071  (AARRAY_LINE, vec, (uint64_t)base, (void(*)(void))f))
1072 
1073 #if __has_extension(blocks)
1074 $define AARRAY_BLOCK_TB_TB_T__D(TYPEB, TYPE) TYPEB(^f)(TYPEB,TYPE, void*), void*data
1075 
1076 $define AARRAY_BLOCK_TB_TB_T(TYPEB, TYPE) TYPEB(^f)(TYPEB,TYPE)
1077 
1078 AARRAY_Fold_FNAME(BLOCK_4, AARRAY_BLOCK_TB_TB_T__D)
1079 AARRAY_Fold_FNAME(BLOCK_3, AARRAY_BLOCK_TB_TB_T)
1080 #define AARRAY_aFold_BLOCK_4(vec, base, f, data) \
1081  (AARRAY_typeof(base, (uint64_t(*)(char[], void*, uint64_t, \
1082  uint64_t(^)(uint64_t,uint64_t,void*), void*)) \
1083  AARRAY_Fold_BLOCK_4_FUNCTIONS[TEST_width(base)][TEST_width(*vec)]) \
1084  (AARRAY_LINE, vec, (uint64_t)base, (uint64_t(^)(uint64_t,uint64_t,void*))f, data))
1085 #define AARRAY_aFold_BLOCK_3(vec, base, f) \
1086  (AARRAY_typeof(base, (uint64_t(*)(char[], void*, uint64_t, \
1087  uint64_t(^)(uint64_t,uint64_t))) \
1088  AARRAY_Fold_BLOCK_3_FUNCTIONS[TEST_width(base)][TEST_width(*vec)]) \
1089  (AARRAY_LINE, vec, (uint64_t)base, (uint64_t(^)(uint64_t,uint64_t))f))
1090 #endif
1091 #if defined(__cplusplus)
1092 $define AARRAY_LAMBDA_TB_TB_T__D(TYPEB, TYPE) std::function<TYPEB(TYPEB,TYPE, void*)>f, void*data
1093 
1094 $define AARRAY_LAMBDA_TB_TB_T(TYPEB, TYPE) std::function<TYPEB(TYPEB,TYPE)>f
1095 
1096 AARRAY_Fold_FNAME(LAMBDA_4, AARRAY_LAMBDA_TB_TB_T__D)
1097 AARRAY_Fold_FNAME(LAMBDA_3, AARRAY_LAMBDA_TB_TB_T)
1098 #define AARRAY_aFold_LAMBDA_4(vec, base, f, data) \
1099  (AARRAY_typeof(base, (uint64_t(*)(char[], void*, uint64_t, \
1100  std::function<uint64_t(uint64_t,uint64_t,void*)>, void*)) \
1101  AARRAY_Fold_LAMBDA_4_FUNCTIONS[TEST_width(base)][TEST_width(*vec)]) \
1102  (AARRAY_LINE, vec, (uint64_t)base, f, data))
1103 #define AARRAY_aFold_LAMBDA_3(vec, base, f) \
1104  (AARRAY_typeof(base, (uint64_t(*)(char[], void*, uint64_t, \
1105  std::function<uint64_t(uint64_t,uint64_t)>)) \
1106  AARRAY_Fold_LAMBDA_3_FUNCTIONS[TEST_width(base)][TEST_width(*vec)]) \
1107  (AARRAY_LINE, vec, (uint64_t)base, f))
1108 #endif
1109 
1110 /* make void*data parameter optional */
1111 #define AARRAY_ARGS_(_10, _9, _8, _7, _6, _5, _4, _3, _2, _1, N, ...) N
1112 #define AARRAY_ARGS(...) AARRAY_ARGS_(__VA_ARGS__, 10, 9, 8, 7, 6, 5, 4, 3, 2, 1, 0)
1113 #define AARRAY_CONCAT(a, b) a##b
1114 #define AARRAY_CONCAT_EXPAND(a, b) AARRAY_CONCAT(a, b)
1115 #define aMap_FUNC(...) AARRAY_CONCAT_EXPAND(AARRAY_aMap_FUNC_, AARRAY_ARGS(__VA_ARGS__))(__VA_ARGS__)
1116 #define aMap_BLOCK(...) AARRAY_CONCAT_EXPAND(AARRAY_aMap_BLOCK_, AARRAY_ARGS(__VA_ARGS__))(__VA_ARGS__)
1117 #define aMap_LAMBDA(...) AARRAY_CONCAT_EXPAND(AARRAY_aMap_LAMBDA_, AARRAY_ARGS(__VA_ARGS__))(__VA_ARGS__)
1118 #define aLoop_FUNC(...) AARRAY_CONCAT_EXPAND(AARRAY_aLoop_FUNC_, AARRAY_ARGS(__VA_ARGS__))(__VA_ARGS__)
1119 #define aLoop_BLOCK(...) AARRAY_CONCAT_EXPAND(AARRAY_aLoop_BLOCK_, AARRAY_ARGS(__VA_ARGS__))(__VA_ARGS__)
1120 #define aLoop_LAMBDA(...) AARRAY_CONCAT_EXPAND(AARRAY_aLoop_LAMBDA_, AARRAY_ARGS(__VA_ARGS__))(__VA_ARGS__)
1121 #define aFilter_FUNC(...) AARRAY_CONCAT_EXPAND(AARRAY_aFilter_FUNC_, AARRAY_ARGS(__VA_ARGS__))(__VA_ARGS__)
1122 #define aFilter_BLOCK(...) AARRAY_CONCAT_EXPAND(AARRAY_aFilter_BLOCK_, AARRAY_ARGS(__VA_ARGS__))(__VA_ARGS__)
1123 #define aFilter_LAMBDA(...) AARRAY_CONCAT_EXPAND(AARRAY_aFilter_LAMBDA_, AARRAY_ARGS(__VA_ARGS__))(__VA_ARGS__)
1124 #define aFold_FUNC(...) AARRAY_CONCAT_EXPAND(AARRAY_aFold_FUNC_, AARRAY_ARGS(__VA_ARGS__))(__VA_ARGS__)
1125 #define aFold_BLOCK(...) AARRAY_CONCAT_EXPAND(AARRAY_aFold_BLOCK_, AARRAY_ARGS(__VA_ARGS__))(__VA_ARGS__)
1126 #define aFold_LAMBDA(...) AARRAY_CONCAT_EXPAND(AARRAY_aFold_LAMBDA_, AARRAY_ARGS(__VA_ARGS__))(__VA_ARGS__)
1127 
1128 
1129 
1130 /* search and sort
1131  * aSort needs a whole bunch of helper macros and functions
1132  * thanks goes to: https://github.com/BonzaiThePenguin/WikiSort
1133  */
1134 $define AARRAY_swap(TYPE, a, b) { TYPE temp = a;
1135  a = b;
1136  b = temp; }
1137 
1138 $define AARRAY_SWAP(TYPE, x, y) \
1139  if(f(array[sRange+y], array[sRange+x]) ||
1140  (order[x] > order[y] && !f(array[sRange+x], array[sRange+y]))) {
1141  AARRAY_swap(TYPE, array[sRange+x], array[sRange+y]);
1142  AARRAY_swap(uint8_t, order[x], order[y]); }
1143 
1144 $define AARRAY_blockSwap(TYPE, array, start1, start2, block_size)
1145  for(size_t n = 0; n < block_size; n++)
1146  AARRAY_swap(TYPE, array[start1+n], array[start2+n])
1147 
1148 $define AARRAY_PULL(_to) \
1149  pull[pull_index].sRange = sA; \
1150  pull[pull_index].eRange = eB; \
1151  pull[pull_index].count = count; \
1152  pull[pull_index].from = index; \
1153  pull[pull_index].to = _to;
1154 
1155 $define AARRAY_sortFindFirstForward(FNAME, value, start, end, unique)
1156  if(end-start == 0) index = start;
1157  else {
1158  int indexSet = 0;
1159  size_t skip = (end-start)/(unique);
1160  if(!skip) skip = 1;
1161  for(index = start+skip; f(array[index-1], value); index += skip)
1162  if(index >= end-skip) {
1163  index = AARRAY_aSortBinaryFirst_$##FNAME(array, value, index, end, f);
1164  indexSet = 1; break; }
1165  if(!indexSet) index =
1166  AARRAY_aSortBinaryFirst_$##FNAME(array, value, index-skip, index, f); }
1167 
1168 $define AARRAY_sortFindLastForward(FNAME, value, start, end, unique)
1169  if(end-start == 0) index = start;
1170  else {
1171  int indexSet = 0;
1172  size_t skip = (end-start)/(unique);
1173  if(!skip) skip = 1;
1174  for(index = start+skip; !f(value, array[index-1]); index += skip)
1175  if(index >= end-skip) {
1176  index = AARRAY_aSortBinaryLast_$##FNAME(array, value, index, end, f);
1177  indexSet = 1; break; }
1178  if(!indexSet) index =
1179  AARRAY_aSortBinaryLast_$##FNAME(array, value, index-skip, index, f); }
1180 
1181 $define AARRAY_sortFindFirstBackward(FNAME, value, start, end, unique)
1182  if(end-start == 0) index = start;
1183  else {
1184  int indexSet = 0;
1185  size_t skip = (end-start)/(unique);
1186  if(!skip) skip = 1;
1187  for(index = end-skip; index > start
1188  && !f(array[index-1], value); index -= skip)
1189  if(index < start+skip) {
1190  index = AARRAY_aSortBinaryFirst_$##FNAME(array, value, start, index, f);
1191  indexSet = 1; break; }
1192  if(!indexSet) index =
1193  AARRAY_aSortBinaryFirst_$##FNAME(array, value, index, index+skip, f); }
1194 
1195 $define AARRAY_sortFindLastBackward(FNAME, value, start, end, unique)
1196  if(end-start == 0) index = start;
1197  else {
1198  int indexSet = 0;
1199  size_t skip = (end-start)/(unique);
1200  if(!skip) skip = 1;
1201  for(index = end-skip; index > start
1202  && f(value, array[index-1]); index -= skip)
1203  if(index < start+skip) {
1204  index = AARRAY_aSortBinaryLast_$##FNAME(array, value, start, index, f);
1205  indexSet = 1; break; }
1206  if(!indexSet) index =
1207  AARRAY_aSortBinaryLast_$##FNAME(array, value, index, index+skip, f); }
1208 
1209 $define AARRAY_sortReverse(TYPE, ...)
1210 AARRAY_define(void AARRAY_sortReverse__$##TYPE(
1211  TYPE vec[], size_t start, size_t end), {
1212  for(size_t n = (end-start)/2; n > 0; n--) {
1213  TYPE temp = vec[start+n-1];
1214  vec[start+n-1] = vec[end-n];
1215  vec[end-n] = temp; } })
1216 
1217 $define AARRAY_sortBinaryFirst(TYPE, FNAME, FTYPE)
1218 AARRAY_define(size_t AARRAY_sortBinaryFirst_$##FNAME$##_$##TYPE(
1219  const TYPE array[], const TYPE value,
1220  size_t start, size_t end, FTYPE(TYPE)), {
1221  size_t rend = end;
1222  end -= 1;
1223  if(start >= rend) return start;
1224  while(start < end) {
1225  size_t mid = start+(end-start)/2;
1226  if(f(array[mid], value)) start = mid+1;
1227  else end = mid; }
1228  if(start == rend-1 && f(array[start], value)) start++;
1229  return start; })
1230 
1231 $define AARRAY_sortBinaryLast(TYPE, FNAME, FTYPE)
1232 AARRAY_define(size_t AARRAY_sortBinaryLast_$##FNAME$##_$##TYPE(
1233  const TYPE array[], const TYPE value,
1234  size_t start, size_t end, FTYPE(TYPE)), {
1235  size_t rend = end;
1236  end -= 1;
1237  if(start >= rend) return end;
1238  while(start < end) {
1239  size_t mid = start+(end-start)/2;
1240  if(!f(value, array[mid])) start = mid+1;
1241  else end = mid; }
1242  if(start == rend-1 && !f(value, array[start])) start++;
1243  return start; })
1244 
1245 typedef struct {
1246  size_t size, power_of_two;
1247  size_t numerator, decimal;
1248  size_t denominator, decimal_step, numerator_step; } AARRAY_sortIt;
1249 $define AARRAY_sortNextRange(TYPE, ...)
1250 AARRAY_define(void AARRAY_sortNextRange__$##TYPE(
1251  AARRAY_sortIt*it, size_t*start, size_t*end), {
1252  *start = it->decimal;
1253  it->decimal += it->decimal_step;
1254  it->numerator += it->numerator_step;
1255  if(it->numerator >= it->denominator) {
1256  it->numerator -= it->denominator;
1257  it->decimal++; }
1258  *end = it->decimal; })
1259 
1260 $define AARRAY_sortNextLevel(TYPE, ...)
1261 AARRAY_define(int AARRAY_sortNextLevel__$##TYPE(AARRAY_sortIt*it), {
1262  it->decimal_step += it->decimal_step;
1263  it->numerator_step += it->numerator_step;
1264  if(it->numerator_step >= it->denominator) {
1265  it->numerator_step -= it->denominator;
1266  it->decimal_step++; }
1267  return it->decimal_step < it->size; })
1268 
1269 GENERATE_GENERICS(AARRAY_sortReverse)
1270 #define AARRAY_aSortReverse(vec, start, end) \
1271  (((int(*)(void*, size_t, size_t)) \
1272  AARRAY_sortReverse__FUNCTIONS[TEST_width(*vec)])((void*)vec, start, end))
1273 
1274 $define AARRAY_sortRotate(TYPE, ...)
1275 AARRAY_define(void AARRAY_sortRotate__$##TYPE(
1276  TYPE array[], const size_t amount, size_t start, size_t end,
1277  TYPE cache[], const size_t cacheSize), {
1278  if(end-start == 0) return;
1279  size_t sA = start, eA = start+amount, sB = start+amount, eB = end;
1280  if(eA-sA <= eB-sB) {
1281  if(eA-sA <= cacheSize) {
1282  memcpy(&cache[0], &array[sA], (eA-sA)*sizeof(array[0]));
1283  memmove(&array[sA], &array[sB], (eB-sB)*sizeof(array[0]));
1284  memcpy(&array[sA+(eB-sB)], &cache[0], (eA-sA)*sizeof(array[0]));
1285  return; } }
1286  else {
1287  if(eB-sB <= cacheSize) {
1288  memcpy(&cache[0], &array[sB], (eB-sB)*sizeof(array[0]));
1289  memmove(&array[eB-(eA-sA)], &array[sA], (eA-sA)*sizeof(array[0]));
1290  memcpy(&array[sA], &cache[0], (eB-sB)*sizeof(array[0]));
1291  return; } }
1292  AARRAY_aSortReverse(array, sA, eA);
1293  AARRAY_aSortReverse(array, sB, eB);
1294  AARRAY_aSortReverse(array, start, end); })
1295 
1296 $define AARRAY_sortMergeInto(TYPE, FNAME, FTYPE)
1297 AARRAY_define(void AARRAY_sortMergeInto_$##FNAME$##_$##TYPE(
1298  TYPE from[], size_t sA, size_t eA, size_t sB, size_t eB,
1299  FTYPE(TYPE), TYPE into[]), {
1300  TYPE*A_index = &from[sA], *B_index = &from[sB];
1301  TYPE*A_last = &from[eA], *B_last = &from[eB];
1302  TYPE*insert_index = &into[0];
1303  while(1) {
1304  if(!f(*B_index, *A_index)) {
1305  *insert_index = *A_index;
1306  A_index++;
1307  insert_index++;
1308  if(A_index == A_last) {
1309  memcpy(insert_index, B_index, (size_t)(B_last-B_index)*sizeof(from[0]));
1310  break; } }
1311  else {
1312  *insert_index = *B_index;
1313  B_index++;
1314  insert_index++;
1315  if(B_index == B_last) {
1316  memcpy(insert_index, A_index, (size_t)(A_last-A_index)*sizeof(from[0]));
1317  break; } } } })
1318 
1319 $define AARRAY_sortMergeExternal(TYPE, FNAME, FTYPE)
1320 AARRAY_define(void AARRAY_sortMergeExternal_$##FNAME$##_$##TYPE(
1321  TYPE array[], size_t sA, size_t eA, size_t sB, size_t eB,
1322  FTYPE(TYPE), TYPE cache[]), {
1323  TYPE*A_index = &cache[0];
1324  TYPE*B_index = &array[sB];
1325  TYPE*insert_index = &array[sA];
1326  TYPE*A_last = &cache[eA-sA];
1327  TYPE*B_last = &array[eB];
1328  if(eB-sB > 0 && eA-sA > 0) {
1329  while(1) {
1330  if(!f(*B_index, *A_index)) {
1331  *insert_index = *A_index;
1332  A_index++;
1333  insert_index++;
1334  if(A_index == A_last) break; }
1335  else {
1336  *insert_index = *B_index;
1337  B_index++;
1338  insert_index++;
1339  if(B_index == B_last) break; } } }
1340  memcpy(insert_index, A_index, (size_t)(A_last-A_index)*sizeof(array[0])); })
1341 
1342 $define AARRAY_sortMergeInternal(TYPE, FNAME, FTYPE)
1343 AARRAY_define(void AARRAY_sortMergeInternal_$##FNAME$##_$##TYPE(
1344  TYPE array[], size_t sA, size_t eA, size_t sB, size_t eB,
1345  FTYPE(TYPE), size_t sBuff), {
1346  size_t A_count = 0, B_count = 0, insert = 0;
1347  if(eB-sB > 0 && eA-sA > 0) {
1348  while(1) {
1349  if(!f(array[sB+B_count], array[sBuff+A_count])) {
1350  AARRAY_swap(TYPE, array[sA+insert], array[sBuff+A_count]);
1351  A_count++;
1352  insert++;
1353  if(A_count >= eA-sA) break; }
1354  else {
1355  AARRAY_swap(TYPE, array[sA+insert], array[sB+B_count]);
1356  B_count++;
1357  insert++;
1358  if(B_count >= eB-sB) break; } } }
1359  AARRAY_blockSwap(TYPE, array, sBuff+A_count, sA+insert, (eA-sA)-A_count); })
1360 
1361 $define FUNC_int_TT(TYPE) int(*f)(TYPE,TYPE)
1362 
1363 $define BLOCK_int_TT(TYPE) int(^f)(TYPE,TYPE)
1364 
1365 $define LAMBDA_int_TT(TYPE) std::function<int(TYPE, TYPE)>f
1366 
1367 GENERATE_GENERICS(AARRAY_sortRotate)
1368 #define AARRAY_aSortRotate(vec, value, start, end, vecb, cacheSize) \
1369  (((void(*)(void*, size_t, size_t, size_t, void*, size_t)) \
1370  AARRAY_sortRotate__FUNCTIONS[TEST_width(*vec)]) \
1371  ((void*)vec, value, start, end, vecb, cacheSize))
1372 GENERATE_GENERICS(AARRAY_sortBinaryFirst, FUNC, FUNC_int_TT)
1373 GENERATE_GENERICS(AARRAY_sortBinaryLast, FUNC, FUNC_int_TT)
1374 #define AARRAY_aSortBinaryFirst_FUNC(vec, value, start, end, f) \
1375  (((size_t(*)(void*, uint64_t, size_t, size_t, void(*)(void))) \
1376  AARRAY_sortBinaryFirst_FUNC_FUNCTIONS[TEST_width(*vec)]) \
1377  ((void*)vec, value, start, end, (void(*)(void))f))
1378 #define AARRAY_aSortBinaryLast_FUNC(vec, value, start, end, f) \
1379  (((size_t(*)(void*, uint64_t, size_t, size_t, void(*)(void))) \
1380  AARRAY_sortBinaryLast_FUNC_FUNCTIONS[TEST_width(*vec)]) \
1381  ((void*)vec, value, start, end, (void(*)(void))f))
1382 
1383 #if __has_extension(blocks)
1384 GENERATE_GENERICS(AARRAY_sortBinaryFirst, BLOCK, BLOCK_int_TT)
1385 GENERATE_GENERICS(AARRAY_sortBinaryLast, BLOCK, BLOCK_int_TT)
1386 #define AARRAY_aSortBinaryFirst_BLOCK(vec, value, start, end, f) \
1387  (((size_t(*)(void*, uint64_t, size_t, size_t, void*)) \
1388  AARRAY_sortBinaryFirst_BLOCK_FUNCTIONS[TEST_width(*vec)]) \
1389  ((void*)vec, value, start, end, (void*)f))
1390 #define AARRAY_aSortBinaryLast_BLOCK(vec, value, start, end, f) \
1391  (((size_t(*)(void*, uint64_t, size_t, size_t, void*)) \
1392  AARRAY_sortBinaryLast_BLOCK_FUNCTIONS[TEST_width(*vec)]) \
1393  ((void*)vec, value, start, end, (void*)f))
1394 #endif
1395 #if defined(__cplusplus)
1396 GENERATE_GENERICS(AARRAY_sortBinaryFirst, LAMBDA, LAMBDA_int_TT)
1397 GENERATE_GENERICS(AARRAY_sortBinaryLast, LAMBDA, LAMBDA_int_TT)
1398 #define AARRAY_aSortBinaryFirst_LAMBDA(vec, value, start, end, f) \
1399  (((size_t(*)(void*, uint64_t, size_t, size_t, std::function<int(int,int)>)) \
1400  AARRAY_sortBinaryFirst_LAMBDA_FUNCTIONS[TEST_width(*vec)]) \
1401  ((void*)vec, value, start, end, (std::function<int(int,int)>)f))
1402 #define AARRAY_aSortBinaryLast_LAMBDA(vec, value, start, end, f) \
1403  (((size_t(*)(void*, uint64_t, size_t, size_t, std::function<int(int,int)>)) \
1404  AARRAY_sortBinaryLast_LAMBDA_FUNCTIONS[TEST_width(*vec)]) \
1405  ((void*)vec, value, start, end, (std::function<int(int,int)>)f))
1406 #endif
1407 
1408 $define AARRAY_sortMergeInPlace(TYPE, FNAME, FTYPE)
1409 AARRAY_define(void AARRAY_sortMergeInPlace_$##FNAME$##_$##TYPE(
1410  TYPE array[], size_t sA, size_t eA, size_t sB, size_t eB,
1411  FTYPE(TYPE), TYPE cache[]), {
1412  if(eA-sA == 0 || eB-sB == 0) return;
1413  while(1) {
1414  size_t mid = AARRAY_aSortBinaryFirst_$##FNAME(array, array[sA], sB, eB, f);
1415  size_t amount = mid-eA;
1416  AARRAY_aSortRotate(array, eA-sA, sA, mid, cache, AARRAY_sortCache);
1417  if(eB == mid) break;
1418  sB = mid;
1419  sA = sA+amount; eA = sB;
1420  sA = AARRAY_aSortBinaryLast_$##FNAME(array, array[sA], sA, eA, f);
1421  if(eA-sA == 0) break; } })
1422 
1423 GENERATE_GENERICS(AARRAY_sortNextRange)
1424 GENERATE_GENERICS(AARRAY_sortNextLevel)
1425 #define AARRAY_aSortNextRange(vec, iter, start, end) \
1426  (((void(*)(AARRAY_sortIt*, size_t*, size_t*)) \
1427  AARRAY_sortNextRange__FUNCTIONS[TEST_width(*vec)])(iter, start, end))
1428 #define AARRAY_aSortNextLevel(vec, iter) \
1429  (((int (*)(AARRAY_sortIt*)) \
1430  AARRAY_sortNextLevel__FUNCTIONS[TEST_width(*vec)])(iter))
1431 GENERATE_GENERICS(AARRAY_sortMergeInto, FUNC, FUNC_int_TT)
1432 GENERATE_GENERICS(AARRAY_sortMergeExternal, FUNC, FUNC_int_TT)
1433 GENERATE_GENERICS(AARRAY_sortMergeInternal, FUNC, FUNC_int_TT)
1434 GENERATE_GENERICS(AARRAY_sortMergeInPlace, FUNC, FUNC_int_TT)
1435 #define AARRAY_aSortMergeInto_FUNC(vec, s1, s2, s3, s4, f, vecb) \
1436  (((void(*)(void*, size_t, size_t, size_t, size_t, void(*)(void), void*)) \
1437  AARRAY_sortMergeInto_FUNC_FUNCTIONS[TEST_width(*vec)]) \
1438  ((void*)vec, s1, s2, s3, s4, (void(*)(void))f, vecb))
1439 #define AARRAY_aSortMergeExternal_FUNC(vec, s1, s2, s3, s4, f, vecb) \
1440  (((void(*)(void*, size_t, size_t, size_t, size_t, void(*)(void), void*)) \
1441  AARRAY_sortMergeExternal_FUNC_FUNCTIONS[TEST_width(*vec)]) \
1442  ((void*)vec, s1, s2, s3, s4, (void(*)(void))f, vecb))
1443 #define AARRAY_aSortMergeInternal_FUNC(vec, s1, s2, s3, s4, f, s5) \
1444  (((void(*)(void*, size_t, size_t, size_t, size_t, void(*)(void), size_t)) \
1445  AARRAY_sortMergeInternal_FUNC_FUNCTIONS[TEST_width(*vec)]) \
1446  ((void*)vec, s1, s2, s3, s4, (void(*)(void))f, s5))
1447 #define AARRAY_aSortMergeInPlace_FUNC(vec, s1, s2, s3, s4, f, vecb) \
1448  (((void(*)(void*, size_t, size_t, size_t, size_t, void(*)(void), void*)) \
1449  AARRAY_sortMergeInPlace_FUNC_FUNCTIONS[TEST_width(*vec)]) \
1450  ((void*)vec, s1, s2, s3, s4, (void(*)(void))f, vecb))
1451 
1452 #if __has_extension(blocks)
1453 GENERATE_GENERICS(AARRAY_sortMergeInto, BLOCK, BLOCK_int_TT)
1454 GENERATE_GENERICS(AARRAY_sortMergeExternal, BLOCK, BLOCK_int_TT)
1455 GENERATE_GENERICS(AARRAY_sortMergeInternal, BLOCK, BLOCK_int_TT)
1456 GENERATE_GENERICS(AARRAY_sortMergeInPlace, BLOCK, BLOCK_int_TT)
1457 #define AARRAY_aSortMergeInto_BLOCK(vec, s1, s2, s3, s4, f, vecb) \
1458  (((void(*)(void*, size_t, size_t, size_t, size_t, void*, void*)) \
1459  AARRAY_sortMergeInto_BLOCK_FUNCTIONS[TEST_width(*vec)]) \
1460  ((void*)vec, s1, s2, s3, s4, (void*)f, vecb))
1461 #define AARRAY_aSortMergeExternal_BLOCK(vec, s1, s2, s3, s4, f, vecb) \
1462  (((void(*)(void*, size_t, size_t, size_t, size_t, void*, void*)) \
1463  AARRAY_sortMergeExternal_BLOCK_FUNCTIONS[TEST_width(*vec)]) \
1464  ((void*)vec, s1, s2, s3, s4, (void*)f, vecb))
1465 #define AARRAY_aSortMergeInternal_BLOCK(vec, s1, s2, s3, s4, f, s5) \
1466  (((void(*)(void*, size_t, size_t, size_t, size_t, void*, size_t)) \
1467  AARRAY_sortMergeInternal_BLOCK_FUNCTIONS[TEST_width(*vec)]) \
1468  ((void*)vec, s1, s2, s3, s4, (void*)f, s5))
1469 #define AARRAY_aSortMergeInPlace_BLOCK(vec, s1, s2, s3, s4, f, vecb) \
1470  (((void(*)(void*, size_t, size_t, size_t, size_t, void*, void*)) \
1471  AARRAY_sortMergeInPlace_BLOCK_FUNCTIONS[TEST_width(*vec)]) \
1472  ((void*)vec, s1, s2, s3, s4, (void*)f, vecb))
1473 #endif
1474 #if defined(__cplusplus)
1475 GENERATE_GENERICS(AARRAY_sortMergeInto, LAMBDA, LAMBDA_int_TT)
1476 GENERATE_GENERICS(AARRAY_sortMergeExternal, LAMBDA, LAMBDA_int_TT)
1477 GENERATE_GENERICS(AARRAY_sortMergeInternal, LAMBDA, LAMBDA_int_TT)
1478 GENERATE_GENERICS(AARRAY_sortMergeInPlace, LAMBDA, LAMBDA_int_TT)
1479 #define AARRAY_aSortMergeInto_LAMBDA(vec, s1, s2, s3, s4, f, vecb) \
1480  (((void(*)(void*, size_t, size_t, size_t, size_t, \
1481  std::function<int(int,int)>, void*)) \
1482  AARRAY_sortMergeInto_LAMBDA_FUNCTIONS[TEST_width(*vec)]) \
1483  ((void*)vec, s1, s2, s3, s4, (std::function<int(int,int)>)f, vecb))
1484 #define AARRAY_aSortMergeExternal_LAMBDA(vec, s1, s2, s3, s4, f, vecb) \
1485  (((void(*)(void*, size_t, size_t, size_t, size_t, \
1486  std::function<int(int,int)>, void*)) \
1487  AARRAY_sortMergeExternal_LAMBDA_FUNCTIONS[TEST_width(*vec)]) \
1488  ((void*)vec, s1, s2, s3, s4, (std::function<int(int,int)>)f, vecb))
1489 #define AARRAY_aSortMergeInternal_LAMBDA(vec, s1, s2, s3, s4, f, s5) \
1490  (((void(*)(void*, size_t, size_t, size_t, size_t, \
1491  std::function<int(int,int)>, size_t)) \
1492  AARRAY_sortMergeInternal_LAMBDA_FUNCTIONS[TEST_width(*vec)]) \
1493  ((void*)vec, s1, s2, s3, s4, (std::function<int(int,int)>)f, s5))
1494 #define AARRAY_aSortMergeInPlace_LAMBDA(vec, s1, s2, s3, s4, f, vecb) \
1495  (((void(*)(void*, size_t, size_t, size_t, size_t, \
1496  std::function<int(int,int)>, void*)) \
1497  AARRAY_sortMergeInPlace_LAMBDA_FUNCTIONS[TEST_width(*vec)]) \
1498  ((void*)vec, s1, s2, s3, s4, (std::function<int(int,int)>)f, vecb))
1499 #endif
1500 
1501 /* from www.hackersdelight.org/hdcodetxt/martin/src/sqrt/sqrt.c */
1502 AARRAY_define(int64_t AARRAY_sqrt(int64_t x), {
1503  /* Logically, these are unsigned. We need the sign bit to test
1504  whether (op - res - one) underflowed */
1505  int64_t op = x, res, one;
1506  res = 0;
1507  /* "one" starts at the highest power of four <= than the argument */
1508  one = ((uint64_t)1) << 62; /* second-to-top bit set */
1509  while (one > op) one >>= 2;
1510  while (one != 0) {
1511  if (op >= res + one) {
1512  op = op - (res + one);
1513  res = res + 2 * one; }
1514  res /= 2;
1515  one /= 4; }
1516  return(res); })
1517 
1518 /* alternative slow sqrt */
1519 /* AARRAY_define(uint64_t AARRAY_double_to_uint(double val), {
1520  if(val > (double)INT64_MAX) return (uint64_t)INT64_MAX;
1521  if(val < (double)INT64_MIN) return (uint64_t)INT64_MIN;
1522  return (uint64_t)(int64_t)val; })
1523 AARRAY_define(uint64_t AARRAY_sqrt(uint64_t val), {
1524  *//* bounded newton-raphson *//*
1525  if(val<=1) return val;
1526  uint64_t min = 1, max = val;
1527  uint64_t a = min+1, b = (max>>4)+2, c;
1528  int64_t fa = (int64_t)(val-a*a), fb = (int64_t)(val-b*b);
1529  while(min < max) {
1530  *//* divide by non-zero? interpolate : bisect *//*
1531  c = (uint64_t)fb-(uint64_t)fa?
1532  b - AARRAY_double_to_uint((double)fb * (double)(b-a) /
1533  (double)((uint64_t)fb-(uint64_t)fa)) :
1534  max-((max-min)>>1);
1535  *//* keep the pingpong ball on the table *//*
1536  a = b; b = c < min ? min : c >= max ? max-1 : c;
1537  fa = fb; fb = (int64_t)(val-b*b);
1538  if(fb == 0) return b;
1539  if(fb > 0) min = b+1; else max = b; }
1540  return min-1; }) */
1541 
1542 /* all that work, just to support this beast
1543  I'm glad I didn't write it myself */
1544 $define AARRAY_sort(TYPE, FNAME, FTYPE)
1545 AARRAY_define(TYPE*AARRAY_sort_$##FNAME$##_$##TYPE(
1546  TYPE array[], FTYPE(TYPE)), {
1547  size_t size = aLength(array);
1548  TYPE cache[AARRAY_sortCache];
1549  AARRAY_sortIt it;
1550  if(size < 4) {
1551  if(size == 3) {
1552  if(f(array[1], array[0])) AARRAY_swap(TYPE, array[0], array[1]);
1553  if(f(array[2], array[1])) {
1554  AARRAY_swap(TYPE, array[1], array[2]);
1555  if(f(array[1], array[0])) AARRAY_swap(TYPE, array[0], array[1]); } }
1556  else if(size == 2) {
1557  if(f(array[1], array[0])) AARRAY_swap(TYPE, array[0], array[1]); }
1558  return array; }
1559  /* new it */
1560  it.size = size;
1561  /* floor_power_of_2(size) */
1562  size_t s = size;
1563  s = s | (s >> 1); s = s | (s >> 2); s = s | (s >> 4);
1564  s = s | (s >> 8); s = s | (s >> 16);
1565  if(sizeof(size_t)==8) s = s | (s >> 32);
1566  s = s-(s >> 1);
1567  it.power_of_two = s;
1568  it.denominator = it.power_of_two/4;
1569  it.numerator_step = it.size % it.denominator;
1570  it.decimal_step = it.size/it.denominator;
1571  it.numerator = it.decimal = 0;
1572  while(!(it.decimal >= it.size)) {
1573  uint8_t order[] = { 0, 1, 2, 3, 4, 5, 6, 7 };
1574  size_t sRange, eRange;
1575  AARRAY_aSortNextRange(array, &it, &sRange, &eRange);
1576  if(eRange-sRange==8) {
1577  AARRAY_SWAP(TYPE, 0, 1); AARRAY_SWAP(TYPE, 2, 3); AARRAY_SWAP(TYPE, 4, 5);
1578  AARRAY_SWAP(TYPE, 6, 7); AARRAY_SWAP(TYPE, 0, 2); AARRAY_SWAP(TYPE, 1, 3);
1579  AARRAY_SWAP(TYPE, 4, 6); AARRAY_SWAP(TYPE, 5, 7); AARRAY_SWAP(TYPE, 1, 2);
1580  AARRAY_SWAP(TYPE, 5, 6); AARRAY_SWAP(TYPE, 0, 4); AARRAY_SWAP(TYPE, 3, 7);
1581  AARRAY_SWAP(TYPE, 1, 5); AARRAY_SWAP(TYPE, 2, 6); AARRAY_SWAP(TYPE, 1, 4);
1582  AARRAY_SWAP(TYPE, 3, 6); AARRAY_SWAP(TYPE, 2, 4); AARRAY_SWAP(TYPE, 3, 5);
1583  AARRAY_SWAP(TYPE, 3, 4); }
1584  else if(eRange-sRange==7) {
1585  AARRAY_SWAP(TYPE, 1, 2); AARRAY_SWAP(TYPE, 3, 4); AARRAY_SWAP(TYPE, 5, 6);
1586  AARRAY_SWAP(TYPE, 0, 2); AARRAY_SWAP(TYPE, 3, 5); AARRAY_SWAP(TYPE, 4, 6);
1587  AARRAY_SWAP(TYPE, 0, 1); AARRAY_SWAP(TYPE, 4, 5); AARRAY_SWAP(TYPE, 2, 6);
1588  AARRAY_SWAP(TYPE, 0, 4); AARRAY_SWAP(TYPE, 1, 5); AARRAY_SWAP(TYPE, 0, 3);
1589  AARRAY_SWAP(TYPE, 2, 5); AARRAY_SWAP(TYPE, 1, 3); AARRAY_SWAP(TYPE, 2, 4);
1590  AARRAY_SWAP(TYPE, 2, 3); }
1591  else if(eRange-sRange==6) {
1592  AARRAY_SWAP(TYPE, 1, 2); AARRAY_SWAP(TYPE, 4, 5); AARRAY_SWAP(TYPE, 0, 2);
1593  AARRAY_SWAP(TYPE, 3, 5); AARRAY_SWAP(TYPE, 0, 1); AARRAY_SWAP(TYPE, 3, 4);
1594  AARRAY_SWAP(TYPE, 2, 5); AARRAY_SWAP(TYPE, 0, 3); AARRAY_SWAP(TYPE, 1, 4);
1595  AARRAY_SWAP(TYPE, 2, 4); AARRAY_SWAP(TYPE, 1, 3); AARRAY_SWAP(TYPE, 2, 3); }
1596  else if(eRange-sRange==5) {
1597  AARRAY_SWAP(TYPE, 0, 1); AARRAY_SWAP(TYPE, 3, 4); AARRAY_SWAP(TYPE, 2, 4);
1598  AARRAY_SWAP(TYPE, 2, 3); AARRAY_SWAP(TYPE, 1, 4); AARRAY_SWAP(TYPE, 0, 3);
1599  AARRAY_SWAP(TYPE, 0, 2); AARRAY_SWAP(TYPE, 1, 3); AARRAY_SWAP(TYPE, 1, 2); }
1600  else if(eRange-sRange==4) {
1601  AARRAY_SWAP(TYPE, 0, 1); AARRAY_SWAP(TYPE, 2, 3); AARRAY_SWAP(TYPE, 0, 2);
1602  AARRAY_SWAP(TYPE, 1, 3); AARRAY_SWAP(TYPE, 1, 2); } }
1603  if(size < 8) return array;
1604  while(1) {
1605  if(it.decimal_step < AARRAY_sortCache) {
1606  if((it.decimal_step+1)*4 <= AARRAY_sortCache
1607  && it.decimal_step*4 <= size) {
1608  it.numerator = it.decimal = 0;
1609  while(!(it.decimal >= it.size)) {
1610  size_t
1611  sA1, sB1, sA2, sB2, sA3, sB3,
1612  eA1, eB1, eA2, eB2, eA3, eB3;
1613  AARRAY_aSortNextRange(array, &it, &sA1, &eA1);
1614  AARRAY_aSortNextRange(array, &it, &sB1, &eB1);
1615  AARRAY_aSortNextRange(array, &it, &sA2, &eA2);
1616  AARRAY_aSortNextRange(array, &it, &sB2, &eB2);
1617  if(f(array[eB1-1], array[sA1])) {
1618  memcpy(&cache[eB1-sB1], &array[sA1], (eA1-sA1)*sizeof(array[0]));
1619  memcpy(&cache[0], &array[sB1], (eB1-sB1)*sizeof(array[0])); }
1620  else if(f(array[sB1], array[eA1-1])) {
1621  AARRAY_aSortMergeInto_$##FNAME(
1622  array, sA1, eA1, sB1, eB1, f, &cache[0]); }
1623  else {
1624  if(!f(array[sB2], array[eA2-1])
1625  && !f(array[sA2], array[eB1-1])) continue;
1626  memcpy(&cache[0], &array[sA1], (eA1-sA1)*sizeof(array[0]));
1627  memcpy(&cache[(eA1-sA1)], &array[sB1],
1628  (eB1-sB1)*sizeof(array[0])); }
1629  eA1 = eB1;
1630  if(f(array[eB2-1], array[sA2])) {
1631  memcpy(&cache[(eA1-sA1)+(eB2-sB2)], &array[sA2],
1632  (eA2-sA2)*sizeof(array[0]));
1633  memcpy(&cache[eA1-sA1], &array[sB2], (eB2-sB2)*sizeof(array[0])); }
1634  else if(f(array[sB2], array[eA2-1])) {
1635  AARRAY_aSortMergeInto_$##FNAME(
1636  array, sA2, eA2, sB2, eB2, f, &cache[eA1-sA1]); }
1637  else {
1638  memcpy(&cache[eA1-sA1], &array[sA2], (eA2-sA2)*sizeof(array[0]));
1639  memcpy(&cache[(eA1-sA1)+(eA2-sA2)], &array[sB2],
1640  (eB2-sB2)*sizeof(array[0])); }
1641  eA2 = eB2;
1642  sA3 = 0; eA3 = eA1-sA1;
1643  sB3 = eA1-sA1; eB3 = (eA1-sA1)+(eA2-sA2);
1644  if(f(cache[eB3-1], cache[sA3])) {
1645  memcpy(&array[sA1+(eA2-sA2)], &cache[sA3],
1646  (eA3-sA3)*sizeof(array[0]));
1647  memcpy(&array[sA1], &cache[sB3], (eB3-sB3)*sizeof(array[0])); }
1648  else if(f(cache[sB3], cache[eA3-1])) {
1649  AARRAY_aSortMergeInto_$##FNAME(
1650  cache, sA3, eA3, sB3, eB3, f, &array[sA1]); }
1651  else {
1652  memcpy(&array[sA1], &cache[sA3], (eA3-sA3)*sizeof(array[0]));
1653  memcpy(&array[sA1+(eA1-sA1)], &cache[sB3],
1654  (eB3-sB3)*sizeof(array[0])); } }
1655  AARRAY_aSortNextLevel(array, &it); }
1656  else {
1657  it.numerator = it.decimal = 0;
1658  while(!(it.decimal >= it.size)) {
1659  size_t sA, eA, sB, eB;
1660  AARRAY_aSortNextRange(array, &it, &sA, &eA);
1661  AARRAY_aSortNextRange(array, &it, &sB, &eB);
1662  if(f(array[eB-1], array[sA]))
1663  AARRAY_aSortRotate(array, eA-sA, sA, eB, cache, AARRAY_sortCache);
1664  else if(f(array[sB], array[eA-1])) {
1665  memcpy(&cache[0], &array[sA], (eA-sA)*sizeof(array[0]));
1666  AARRAY_aSortMergeExternal_$##FNAME(
1667  array, sA, eA, sB, eB, f, cache); } } } }
1668  else {
1669  size_t block_size = (size_t)AARRAY_sqrt((int64_t)it.decimal_step);
1670  size_t buffer_size = it.decimal_step/block_size+1;
1671  int find_separately;
1672  size_t sBuff1, eBuff1, sBuff2, eBuff2, sA, eA, sB, eB;
1673  size_t index, last, count, find, start, pull_index = 0;
1674  struct { size_t from, to, count, sRange, eRange; } pull[2];
1675  pull[0].from = pull[0].to = pull[0].count = 0;
1676  pull[1].from = pull[1].to = pull[1].count = 0;
1677  pull[0].sRange = pull[0].eRange = 0;
1678  pull[1].sRange = pull[1].eRange = 0;
1679  sBuff1 = 0; eBuff1 = 0;
1680  sBuff2 = 0; eBuff2 = 0;
1681  find_separately = 0;
1682  find = buffer_size+buffer_size;
1683  if(block_size <= AARRAY_sortCache)
1684  find = buffer_size;
1685  else if(find > it.decimal_step) {
1686  find = buffer_size;
1687  find_separately = 1; }
1688  it.numerator = it.decimal = 0;
1689  while(!(it.decimal >= it.size)) {
1690  AARRAY_aSortNextRange(array, &it, &sA, &eA);
1691  AARRAY_aSortNextRange(array, &it, &sB, &eB);
1692  for(last = sA, count = 1; count < find; last = index, count++) {
1693  AARRAY_sortFindLastForward(
1694  FNAME, array[last], (last+1), eA, find-count);
1695  if(index == eA) break; }
1696  index = last;
1697  if(count >= buffer_size) {
1698  AARRAY_PULL(sA);
1699  pull_index = 1;
1700  if(count == buffer_size+buffer_size) {
1701  sBuff1 = sA; eBuff1 = sA+buffer_size;
1702  sBuff2 = sA+buffer_size; eBuff2 = sA+count;
1703  break; }
1704  else if(find == buffer_size+buffer_size) {
1705  sBuff1 = sA; eBuff1 = sA+count;
1706  find = buffer_size; }
1707  else if(block_size <= AARRAY_sortCache) {
1708  sBuff1 = sA; eBuff1 = sA+count;
1709  break; }
1710  else if(find_separately) {
1711  sBuff1 = sA; eBuff1 = sA+count;
1712  find_separately = 0; }
1713  else {
1714  sBuff2 = sA; eBuff2 = sA+count;
1715  break; } }
1716  else if(pull_index == 0 && count > eBuff1-sBuff1) {
1717  sBuff1 = sA; eBuff1 = sA+count;
1718  AARRAY_PULL(sA); }
1719  for(last = eB-1, count = 1; count < find; last = index-1, count++) {
1720  AARRAY_sortFindFirstBackward(
1721  FNAME, array[last], sB, last, find-count);
1722  if(index == sB) break; }
1723  index = last;
1724  if(count >= buffer_size) {
1725  AARRAY_PULL(eB);
1726  pull_index = 1;
1727  if(count == buffer_size+buffer_size) {
1728  sBuff1 = eB-count; eBuff1 = eB-buffer_size;
1729  sBuff2 = eB-buffer_size; eBuff2 = eB;
1730  break; }
1731  else if(find == buffer_size+buffer_size) {
1732  sBuff1 = eB-count; eBuff1 = eB;
1733  find = buffer_size; }
1734  else if(block_size <= AARRAY_sortCache) {
1735  sBuff1 = eB-count; eBuff1 = eB;
1736  break; }
1737  else if(find_separately) {
1738  sBuff1 = eB-count; eBuff1 = eB;
1739  find_separately = 0; }
1740  else {
1741  if(pull[0].sRange == sA) pull[0].eRange -= pull[1].count;
1742  sBuff2 = eB-count; eBuff2 = eB;
1743  break; } }
1744  else if(pull_index == 0 && count > (eBuff1-sBuff1)) {
1745  sBuff1 = eB-count; eBuff1 = eB;
1746  AARRAY_PULL(eB); } }
1747  for(pull_index = 0; pull_index < 2; pull_index++) {
1748  size_t sRange, eRange;
1749  size_t length = pull[pull_index].count;
1750  if(pull[pull_index].to < pull[pull_index].from) {
1751  index = pull[pull_index].from;
1752  for(count = 1; count < length; count++) {
1753  size_t index_ = index;
1754  AARRAY_sortFindFirstBackward(
1755  FNAME, array[index_-1], pull[pull_index].to,
1756  (pull[pull_index].from-(count-1)), length-count);
1757  sRange = index+1; eRange = pull[pull_index].from+1;
1758  AARRAY_aSortRotate(array, (eRange-sRange)-count, sRange, eRange,
1759  cache, AARRAY_sortCache);
1760  pull[pull_index].from = index+count; } }
1761  else if(pull[pull_index].to > pull[pull_index].from) {
1762  index = pull[pull_index].from+1;
1763  for(count = 1; count < length; count++) {
1764  AARRAY_sortFindLastForward(
1765  FNAME, array[index], index, pull[pull_index].to, length-count);
1766  sRange = pull[pull_index].from; eRange = index-1;
1767  AARRAY_aSortRotate(
1768  array, count, sRange, eRange, cache, AARRAY_sortCache);
1769  pull[pull_index].from = index-1-count; } } }
1770  buffer_size = eBuff1-sBuff1;
1771  block_size = it.decimal_step/buffer_size+1;
1772  it.numerator = it.decimal = 0;
1773  while(!(it.decimal >= it.size)) {
1774  AARRAY_aSortNextRange(array, &it, &sA, &eA);
1775  AARRAY_aSortNextRange(array, &it, &sB, &eB);
1776  start = sA;
1777  if(start == pull[0].sRange) {
1778  if(pull[0].from > pull[0].to) {
1779  sA += pull[0].count;
1780  if(eA-sA == 0) continue; }
1781  else if(pull[0].from < pull[0].to) {
1782  eB -= pull[0].count;
1783  if(eB-sB == 0) continue; } }
1784  if(start == pull[1].sRange) {
1785  if(pull[1].from > pull[1].to) {
1786  sA += pull[1].count;
1787  if(eA-sA == 0) continue; }
1788  else if(pull[1].from < pull[1].to) {
1789  eB -= pull[1].count;
1790  if(eB-sB == 0) continue; ; } }
1791  if(f(array[eB-1], array[sA]))
1792  AARRAY_aSortRotate(array, eA-sA, sA, eB, cache, AARRAY_sortCache);
1793  else if(f(array[eA], array[eA-1])) {
1794  size_t
1795  sBlockA, eBlockA, sFirstA, eFirstA, sLastA,
1796  eLastA, sLastB, eLastB, sBlockB, eBlockB;
1797  size_t indexA, findA;
1798  sBlockA = sA; eBlockA = eA;
1799  sFirstA = sA; eFirstA = sA+(eBlockA-sBlockA) % block_size;
1800  for(indexA = sBuff1, index = eFirstA; index < eBlockA;
1801  indexA++, index += block_size)
1802  AARRAY_swap(TYPE, array[indexA], array[index]);
1803  sLastA = sFirstA;
1804  eLastA = eFirstA;
1805  sLastB = 0; eLastB = 0;
1806  sBlockB = sB; eBlockB = sB+(block_size < eB-sB? block_size : eB-sB);
1807  sBlockA += eFirstA-sFirstA;
1808  indexA = sBuff1;
1809  if(eLastA-sLastA <= AARRAY_sortCache)
1810  memcpy(&cache[0], &array[sLastA], (eLastA-sLastA)*sizeof(array[0]));
1811  else if(eBuff2-sBuff2 > 0)
1812  AARRAY_blockSwap(TYPE, array, sLastA, sBuff2, eLastA-sLastA);
1813  if(eBlockA-sBlockA > 0) {
1814  while(1) {
1815  if((eLastB-sLastB > 0 && !f(array[eLastB-1], array[indexA]))
1816  || eBlockB-sBlockB == 0) {
1817  size_t B_split = AARRAY_aSortBinaryFirst_$##FNAME(
1818  array, array[indexA], sLastB, eLastB, f);
1819  size_t B_remaining = eLastB-B_split;
1820  size_t minA = sBlockA;
1821  for(findA = minA+block_size; findA < eBlockA;
1822  findA += block_size)
1823  if(f(array[findA], array[minA])) minA = findA;
1824  AARRAY_blockSwap(TYPE, array, sBlockA, minA, block_size);
1825  AARRAY_swap(TYPE, array[sBlockA], array[indexA]);
1826  indexA++;
1827  if(eLastA-sLastA <= AARRAY_sortCache)
1828  AARRAY_aSortMergeExternal_$##FNAME(
1829  array, sLastA, eLastA, eLastA, B_split, f, cache);
1830  else if(eBuff2-sBuff2 > 0)
1831  AARRAY_aSortMergeInternal_$##FNAME(
1832  array, sLastA, eLastA, eLastA, B_split, f, sBuff2);
1833  else
1834  AARRAY_aSortMergeInPlace_$##FNAME(
1835  array, sLastA, eLastA, eLastA, B_split, f, cache);
1836  if(eBuff2-sBuff2 > 0 || block_size <= AARRAY_sortCache) {
1837  if(block_size <= AARRAY_sortCache)
1838  memcpy(&cache[0], &array[sBlockA],
1839  block_size*sizeof(array[0]));
1840  else AARRAY_blockSwap(TYPE, array, sBlockA, sBuff2,
1841  block_size);
1842  AARRAY_blockSwap(TYPE, array, B_split,
1843  sBlockA+block_size-B_remaining,
1844  B_remaining); }
1845  else
1846  AARRAY_aSortRotate(array, sBlockA-B_split, B_split,
1847  sBlockA+block_size, cache, AARRAY_sortCache);
1848  sLastA = sBlockA-B_remaining; eLastA =
1849  sBlockA-B_remaining+block_size;
1850  sLastB = eLastA; eLastB = eLastA+B_remaining;
1851  sBlockA += block_size;
1852  if(eBlockA-sBlockA == 0) break; }
1853  else if(eBlockB-sBlockB < block_size) {
1854  AARRAY_aSortRotate(
1855  array, sBlockB-sBlockA, sBlockA, eBlockB, cache, 0);
1856  sLastB = sBlockA; eLastB = sBlockA+(eBlockB-sBlockB);
1857  sBlockA += eBlockB-sBlockB;
1858  eBlockA += eBlockB-sBlockB;
1859  eBlockB = sBlockB; }
1860  else {
1861  AARRAY_blockSwap(TYPE, array, sBlockA, sBlockB, block_size);
1862  sLastB = sBlockA; eLastB = sBlockA+block_size;
1863  sBlockA += block_size;
1864  eBlockA += block_size;
1865  sBlockB += block_size;
1866  if(eBlockB > eB-block_size) eBlockB = eB;
1867  else eBlockB += block_size; } } }
1868  if(eLastA-sLastA <= AARRAY_sortCache)
1869  AARRAY_aSortMergeExternal_$##FNAME(
1870  array, sLastA, eLastA, eLastA, eB, f, cache);
1871  else if(eBuff2-sBuff2 > 0)
1872  AARRAY_aSortMergeInternal_$##FNAME(
1873  array, sLastA, eLastA, eLastA, eB, f, sBuff2);
1874  else
1875  AARRAY_aSortMergeInPlace_$##FNAME(
1876  array, sLastA, eLastA, eLastA, eB, f, cache); } }
1877  /* insertion sort */
1878  size_t i, j;
1879  for(i = sBuff2+1; i < eBuff2; i++) {
1880  const TYPE temp = array[i];
1881  for(j = i; j > sBuff2 && f(temp, array[j-1]); j--)
1882  array[j] = array[j-1];
1883  array[j] = temp; }
1884  for(pull_index = 0; pull_index < 2; pull_index++) {
1885  size_t amount, unique = pull[pull_index].count*2;
1886  if(pull[pull_index].from > pull[pull_index].to) {
1887  size_t
1888  sBuff = pull[pull_index].sRange,
1889  eBuff = pull[pull_index].sRange+pull[pull_index].count;
1890  while(eBuff-sBuff > 0) {
1891  AARRAY_sortFindFirstForward(FNAME, array[sBuff], eBuff,
1892  pull[pull_index].eRange, unique);
1893  amount = index-eBuff;
1894  AARRAY_aSortRotate(array, eBuff-sBuff, sBuff, index,
1895  cache, AARRAY_sortCache);
1896  sBuff += (amount+1);
1897  eBuff += amount;
1898  unique -= 2; } }
1899  else if(pull[pull_index].from < pull[pull_index].to) {
1900  size_t
1901  sBuff = pull[pull_index].eRange-pull[pull_index].count,
1902  eBuff = pull[pull_index].eRange;
1903  while(eBuff-sBuff > 0) {
1904  AARRAY_sortFindLastBackward(FNAME, array[eBuff-1],
1905  pull[pull_index].sRange,
1906  sBuff, unique);
1907  amount = sBuff-index;
1908  AARRAY_aSortRotate(
1909  array, amount, index, eBuff, cache, AARRAY_sortCache);
1910  sBuff -= amount;
1911  eBuff -= (amount+1);
1912  unique -= 2; } } } }
1913  if(!AARRAY_aSortNextLevel(array, &it)) break; }
1914  return array; })
1915 
1916 $define AARRAY_sortCompare(TYPE,,)
1917 AARRAY_define(int AARRAY_sortCompare__$##TYPE(TYPE a, TYPE b), {
1918  return a<b; })
1919 
1920 GENERATE_GENERICS(AARRAY_sortCompare,,)
1921 GENERATE_GENERICS(AARRAY_sort, FUNC, FUNC_int_TT)
1922 #define aSort(vec) \
1923  (AARRAY_typeof(vec, (uint64_t*(*)(void*,void(*)(void))) \
1924  AARRAY_sort_FUNC_FUNCTIONS[TEST_width(*vec)])((void*)vec, (void(*)(void)) \
1925  AARRAY_sortCompare__FUNCTIONS[TEST_width(*vec)]))
1926 #define aSortF_FUNC(vec, f) \
1927  (AARRAY_typeof(vec, (uint64_t*(*)(void*,void(*)(void))) \
1928  AARRAY_sort_FUNC_FUNCTIONS[TEST_width(*vec)])((void*)vec, (void(*)(void))f))
1929 
1930 #if __has_extension(blocks)
1931 GENERATE_GENERICS(AARRAY_sort, BLOCK, BLOCK_int_TT)
1932 #define aSortF_BLOCK(vec, f) \
1933  (AARRAY_typeof(vec, (uint64_t*(*)(void*, void*)) \
1934  AARRAY_sort_BLOCK_FUNCTIONS[TEST_width(*vec)])((void*)vec, (void*)f))
1935 #endif
1936 #if defined(__cplusplus)
1937 GENERATE_GENERICS(AARRAY_sort, LAMBDA, LAMBDA_int_TT)
1938 #define aSortF_LAMBDA(vec, f) \
1939  (AARRAY_typeof(vec, (uint64_t*(*)(void*, \
1940  std::function<int(uint64_t,uint64_t)>)) \
1941  AARRAY_sort_LAMBDA_FUNCTIONS[TEST_width(*vec)]) \
1942  ((void*)vec, (std::function<int(uint64_t,uint64_t)>)f))
1943 #endif
1944 
1945 
1946 
1947 
1948 /* (a^b) to avoid overflow into the sign bit */
1949 $define AARRAY_searchCompare(TYPE,,)
1950 AARRAY_define(int64_t AARRAY_searchCompare__$##TYPE(TYPE a, TYPE b), {
1951  $exec [ TYPE = int64_t ] && echo 'if((a^b)>(UINT64_MAX>>1)) return a<b? INT64_MIN : INT64_MAX;'
1952  return (int64_t)((uint64_t)a-(uint64_t)b); })
1953 
1954 
1955 
1956 
1957 $define AARRAY_binary(TYPE, FNAME, FTYPE)
1958 AARRAY_define(int AARRAY_binary_$##FNAME$##_$##TYPE(
1959  TYPE*vec, size_t*index, TYPE key, FTYPE(TYPE)), {
1960  size_t min = 0, mid = 0, max = aLength(vec);
1961  if(!max) { *index = 0; return 0; }
1962  while(min < max) {
1963  mid = (min + max) >> 1;
1964  int64_t cmp = f(key, vec[mid]);
1965  if(cmp == 0) { *index = mid; return 1; }
1966  if(cmp < 0) max = mid;
1967  else min = ++mid; }
1968  *index = mid; return 0; })
1969 
1970 /* an alternative, probably slower, but fully tested */
1971 /* AARRAY_define(int AARRAY_binary_$##FNAME$##_$##TYPE(
1972  TYPE*vec, size_t*index, TYPE key, FTYPE(TYPE)), {
1973  size_t min = 0, width = aLength(vec);
1974  size_t base = 0;
1975  while(width) {
1976  min = base + (width>>1);
1977  int64_t cmp = f(key, vec[min]);
1978  if(cmp==0) { *index = min; return 1; }
1979  if(cmp>0) { base = min+1; width--; }
1980  width >>= 1; }
1981  *index = min; return 0; }) */
1982 
1983 /* our own shmancy algorithm, to make your life more enjoyable */
1984 $define AARRAY_pingpong(TYPE, FNAME, FTYPE)
1985 AARRAY_define(int AARRAY_pingpong_$##FNAME$##_$##TYPE(
1986  TYPE*vec, size_t*index, TYPE key, FTYPE(TYPE)), {
1987  size_t min = 0, max = aLength(vec);
1988  if(!max) { *index = 0; return 0; }
1989  /* start secant 1/8th of the way into the array, because why not */
1990  size_t a = min+(max>>3), b = max-1-(max>>3), c;
1991  int64_t fa = f(key, vec[a]), fb = f(key, vec[b]);
1992  while(min < max) {
1993  /* divide by non-zero? interpolate : bisect */
1994  c = fb-fa? b - (size_t)((double)fb * (double)(b-a) / (double)(fb-fa)) : max-((max-min)>>1);
1995  /* keep the pingpong ball on the table */
1996  a = b; b = c < min ? min : c >= max ? max-1 : c;
1997  fa = fb; fb = f(key, vec[b]);
1998  if(fb == 0) { *index = b; return 1; }
1999  if(fb > 0) min = b+1; else max = b; }
2000  *index = max; return 0; })
2001 
2002 /* same again but with stride -- for arrays of structs */
2003 $define AARRAY_pingpongS(TYPE, FNAME, FTYPE)
2004 AARRAY_define(int AARRAY_pingpongS_$##FNAME$##_$##TYPE(
2005  TYPE*vec, size_t*index, TYPE*key, FTYPE(TYPE*), size_t stride), {
2006  size_t min = 0, max = aLength(vec)/stride;
2007  if(!max) { *index = 0; return 0; }
2008  /* start secant 1/8th of the way into the array, because why not */
2009  size_t a = min+(max>>3), b = max-1-(max>>3), c;
2010  int64_t fa = f(key, vec+a*stride),
2011  fb = f(key, vec+b*stride);
2012  while(min < max) {
2013  /* divide by non-zero? interpolate : bisect */
2014  c = fb-fa? b - (size_t)((double)fb * (double)(b-a) / (double)(fb-fa)) : max-((max-min)>>1);
2015  /* keep the pingpong ball on the table */
2016  a = b; b = c < min ? min : c >= max ? max-1 : c;
2017  fa = fb; fb = f(key, vec+b*stride);
2018  if(fb == 0) { *index = b; return 1; }
2019  if(fb > 0) min = b+1; else max = b; }
2020  *index = max; return 0; })
2021 
2022 $define FUNC_T_TT(TYPE) int64_t(*f)(TYPE,TYPE)
2023 
2024 $define BLOCK_T_TT(TYPE) int64_t(^f)(TYPE,TYPE)
2025 
2026 $define LAMBDA_T_TT(TYPE) std::function<int64_t(TYPE,TYPE)>f
2027 
2028 GENERATE_GENERICS(AARRAY_searchCompare,,)
2029 GENERATE_GENERICS(AARRAY_binary, FUNC, FUNC_T_TT)
2030 GENERATE_GENERICS(AARRAY_pingpong, FUNC, FUNC_T_TT)
2031 GENERATE_GENERICS(AARRAY_pingpongS, FUNC, FUNC_T_TT)
2032 #define aSearch(vec, index, key) \
2033  ((int(*)(void*, size_t*, uint64_t, void(*)(void))) \
2034  AARRAY_binary_FUNC_FUNCTIONS[TEST_width(*vec)]) \
2035  (vec, index, (uint64_t)key, \
2036  (void(*)(void))AARRAY_searchCompare__FUNCTIONS[TEST_width(*vec)])
2037 #define aSearchF_FUNC(vec, index, key, f) \
2038  ((int(*)(void*, size_t*, uint64_t, void(*)(void))) \
2039  AARRAY_binary_FUNC_FUNCTIONS[TEST_width(*vec)]) \
2040  (vec, index, (uint64_t)key, (void(*)(void))f)
2041 #define aSearchP(vec, index, key) \
2042  ((int(*)(void*, size_t*, uint64_t, void(*)(void))) \
2043  AARRAY_pingpong_FUNC_FUNCTIONS[TEST_width(*vec)]) \
2044  (vec, index, (uint64_t)key, \
2045  (void(*)(void))AARRAY_searchCompare__FUNCTIONS[TEST_width(*vec)])
2046 #define aSearchPF_FUNC(vec, index, key, f) \
2047  ((int(*)(void*, size_t*, uint64_t, void(*)(void))) \
2048  AARRAY_pingpong_FUNC_FUNCTIONS[TEST_width(*vec)]) \
2049  (vec, index, (uint64_t)key, (void(*)(void))f)
2050 #define aSearchPS_FUNC(vec, index, key, f, stride) \
2051  ((int(*)(void*, size_t*, uint64_t, void(*)(void), size_t)) \
2052  AARRAY_pingpongS_FUNC_FUNCTIONS[TEST_width(*vec)]) \
2053  (vec, index, (uint64_t)key, (void(*)(void))f, stride)
2054 
2055 #if __has_extension(blocks)
2056 GENERATE_GENERICS(AARRAY_binary, BLOCK, BLOCK_T_TT)
2057 GENERATE_GENERICS(AARRAY_pingpong, BLOCK, BLOCK_T_TT)
2058 GENERATE_GENERICS(AARRAY_pingpongS, BLOCK, BLOCK_T_TT)
2059 #define aSearchF_BLOCK(vec, index, key, f) \
2060  ((int(*)(void*, size_t*, uint64_t, void*)) \
2061  AARRAY_binary_BLOCK_FUNCTIONS[TEST_width(*vec)]) \
2062  (vec, index, (uint64_t)key, (void*)f)
2063 #define aSearchPF_BLOCK(vec, index, key, f) \
2064  ((int(*)(void*, size_t*, uint64_t, void*)) \
2065  AARRAY_pingpong_BLOCK_FUNCTIONS[TEST_width(*vec)]) \
2066  (vec, index, (uint64_t)key, (void*)f)
2067 #define aSearchPS_BLOCK(vec, index, key, f, stride) \
2068  ((int(*)(void*, size_t*, uint64_t, void*, size_t)) \
2069  AARRAY_pingpongS_BLOCK_FUNCTIONS[TEST_width(*vec)]) \
2070  (vec, index, (uint64_t)key, (void*)f, stride)
2071 #endif
2072 #if defined(__cplusplus)
2073 GENERATE_GENERICS(AARRAY_binary, LAMBDA, LAMBDA_T_TT)
2074 GENERATE_GENERICS(AARRAY_pingpong, LAMBDA, LAMBDA_T_TT)
2075 GENERATE_GENERICS(AARRAY_pingpongS, LAMBDA, LAMBDA_T_TT)
2076 #define aSearchF_LAMBDA(vec, index, key, f) \
2077  ((int(*)(void*, size_t*, uint64_t, \
2078  std::function<int64_t(uint64_t,uint64_t)>)) \
2079  AARRAY_binary_LAMBDA_FUNCTIONS[TEST_width(*vec)]) \
2080  (vec, index, (uint64_t)key, \
2081  (std::function<int64_t(uint64_t,uint64_t)>)f)
2082 #define aSearchPF_LAMBDA(vec, index, key, f) \
2083  ((int(*)(void*, size_t*, uint64_t, \
2084  std::function<int64_t(uint64_t,uint64_t)>)) \
2085  AARRAY_pingpong_LAMBDA_FUNCTIONS[TEST_width(*vec)]) \
2086  (vec, index, (uint64_t)key, \
2087  (std::function<int64_t(uint64_t,uint64_t)>)f)
2088 #define aSearchPS_LAMBDA(vec, index, key, f, stride) \
2089  ((int(*)(void*, size_t*, uint64_t, \
2090  std::function<int64_t(uint64_t*,uint64_t*)>, size_t)) \
2091  AARRAY_pingpongS_LAMBDA_FUNCTIONS[TEST_width(*vec)]) \
2092  (vec, index, (uint64_t)key, \
2093  (std::function<int64_t(uint64_t*,uint64_t*)>)f, stride)
2094 #endif
2095 
2096 
2097 
2098 
2099 #if !defined(AARRAY_NOCONVENIENCE)
2100 #if __has_extension(blocks)
2101  #define aMap aMap_BLOCK
2102  #define aFilter aFilter_BLOCK
2103  #define aFold aFold_BLOCK
2104  #define aLoop aLoop_BLOCK
2105  #define aSortF aSortF_BLOCK
2106  #define aSearchF aSearchF_BLOCK
2107  #define aSearchPS aSearchPS_BLOCK
2108  #define aSearchPF aSearchPF_BLOCK
2109 #elif defined(__cplusplus)
2110  #define aMap aMap_LAMBDA
2111  #define aFilter aFilter_LAMBDA
2112  #define aFold aFold_LAMBDA
2113  #define aLoop aLoop_LAMBDA
2114  #define aSortF aSortF_LAMBDA
2115  #define aSearchF aSearchF_LAMBDA
2116  #define aSearchPS aSearchPS_LAMBDA
2117  #define aSearchPF aSearchPF_LAMBDA
2118 #else
2119  #define aMap aMap_FUNC
2120  #define aFilter aFilter_FUNC
2121  #define aFold aFold_FUNC
2122  #define aLoop aLoop_FUNC
2123  #define aSortF aSortF_FUNC
2124  #define aSearchF aSearchF_FUNC
2125  #define aSearchPS aSearchPS_FUNC
2126  #define aSearchPF aSearchPF_FUNC
2127 #endif
2128 #endif
2129 
2130 
2131 
2132 
2133 /* api to quickly print arrays without '\0' endings */
2134 $define AARRAY_Write(TYPE, ...)
2135 AARRAY_define(int AARRAY_Write__$##TYPE(
2136  char errLoc[], FILE*file, size_t vecsCount, uintptr_t vecs[]), {
2137  AARRAY_safety((void)errLoc, if(!file) AARRAY_Error_NullParameter);
2138  size_t n = (size_t)-1; while(++n < vecsCount)
2139  if(vecs[n] &&
2140  *((size_t*)vecs[n]-1) >
2141  fwrite((void*)vecs[n], sizeof(TYPE), *((size_t*)vecs[n]-1), file))
2142  return -1;
2143  return 0; })
2144 
2145 $define AARRAY_WriteE(TYPE, ...)
2146 AARRAY_define(int AARRAY_WriteE__$##TYPE(
2147  size_t vecsCount, uintptr_t vecs[]), {
2148  fflush(stdout);
2149  size_t n = (size_t)-1; while(++n < vecsCount)
2150  if(vecs[n] &&
2151  *((size_t*)vecs[n]-1) >
2152  fwrite((void*)vecs[n], sizeof(TYPE), *((size_t*)vecs[n]-1), stderr))
2153  return -1;
2154  fflush(stderr);
2155  return 0; })
2156 
2157 GENERATE_GENERICS(AARRAY_Write,)
2158 GENERATE_GENERICS(AARRAY_WriteE,)
2159 
2160 #define AARRAY_ArgsHead(A, ...) A
2161 
2162 #define aWriteF(file, ...) \
2163  ((int(*)(char[], FILE*, size_t, uintptr_t[])) \
2164  AARRAY_Write__FUNCTIONS[TEST_width(*AARRAY_ArgsHead(__VA_ARGS__, NULL))]) \
2165  (AARRAY_LINE, file, /* for c++ */ \
2166  AARRAY_nowarn_internal_start AARRAY_PtrArgs(__VA_ARGS__) \
2167  AARRAY_nowarn_internal_end)
2168 #define aWrite(...) aWriteF(stdout, __VA_ARGS__)
2169 #define aWriteE(...) \
2170  ((int(*)(size_t, uintptr_t[])) \
2171  AARRAY_WriteE__FUNCTIONS[TEST_width(*AARRAY_ArgsHead(__VA_ARGS__, NULL))]) \
2172  (/* for c++ */ \
2173  AARRAY_nowarn_internal_start AARRAY_PtrArgs(__VA_ARGS__) \
2174  AARRAY_nowarn_internal_end)
2175 
2176 
2177 
2178 
2179 /* api to emulate printf for arrays
2180  * cppcheck-suppress ctuuninitvar
2181  * cppcheck-suppress uninitvar
2182  */
2183 AARRAY_define(void AARRAY_percent_parse(
2184  char errLoc[], const char fmt[], size_t*pptr,
2185  char*pspecifier, int*pnum1, int*pnum2,
2186  size_t*pstart, size_t*pend, size_t*doublePercent), {
2187  /* get parser values */
2188  char specifier = *pspecifier; int num1 = *pnum1, num2 = *pnum2;
2189  size_t start = *pstart; size_t end = *pend; size_t ptr = *pptr;
2190  while(1) {
2191  if(fmt[ptr] == '\0') {
2192  end = ptr;
2193  specifier = 'e'; break; }
2194  else if(0==strncmp(fmt+ptr, "%v", 2)) {
2195  end = ptr;
2196  ptr = start = ptr+2;
2197  specifier = 'v'; break; }
2198  else if(0==strncmp(fmt+ptr, "%s", 2)) {
2199  end = ptr;
2200  ptr = start = ptr+2;
2201  specifier = 's'; break; }
2202  else if(0==strncmp(fmt+ptr, "%c", 2)) {
2203  end = ptr;
2204  ptr = start = ptr+2;
2205  specifier = 'c'; break; }
2206  else if(0==strncmp(fmt+ptr, "%%", 2)) {
2207  end = ptr;
2208  ptr = start = ptr+2;
2209  *doublePercent = ptr;
2210  specifier = '%'; break; }
2211  else if(fmt[ptr] == '%') {
2212  end = ptr;
2213  /* parse %u %i arguments == %base u|i bitwidth
2214  base == 2-64 bitwidth == c s i l ll 8 16 32 64 z m p */
2215  ptr++; size_t ptr_start = ptr;
2216  AARRAY_safety((void)errLoc;,
2217  if(fmt[ptr]=='\0') AARRAY_Error_FormatStringMalformed);
2218  num1 = 0; num2 = 0;
2219  /* get base to print number in */
2220  char num_str[] = "10";
2221  while(fmt[ptr] >= '0' && fmt[ptr] <= '9') ptr++;
2222  AARRAY_safety(, if(ptr-ptr_start > 2) AARRAY_Error_FormatStringMalformed
2223  else) if(ptr != ptr_start) {
2224  num_str[0] = fmt[ptr_start];
2225  num_str[1] = (ptr != ptr_start+1 ? fmt[ptr_start+1] : '\0');
2226  num1 = (int)strtoul(num_str, NULL, 10); }
2227  else num1 = 10;
2228  /* get number's type */
2229  specifier = fmt[ptr++];
2230  AARRAY_safety(, if((specifier != 'i' && specifier != 'u' &&
2231  specifier != 'f' && specifier != 'd') ||
2232  (num1 < 2 || num1 > 64))
2233  AARRAY_Error_FormatStringMalformed);
2234  /* get number's bit width */
2235  if(specifier == 'i' || specifier == 'u') {
2236  if(0==strncmp(fmt+ptr, "ll", 2)) {
2237  num2 = sizeof(long long)*8; ptr+=2; }
2238  else if(0==strncmp(fmt+ptr, "16", 2)) { num2 = 16; ptr+=2; }
2239  else if(0==strncmp(fmt+ptr, "32", 2)) { num2 = 32; ptr+=2; }
2240  else if(0==strncmp(fmt+ptr, "64", 2)) { num2 = 64; ptr+=2; }
2241  else switch(fmt[ptr]) {
2242  case 'c': case '8': num2 = sizeof(char)*8; ptr++; break;
2243  case 's': num2 = sizeof(short)*8; ptr++; break;
2244  case 'i': num2 = sizeof(int)*8; ptr++; break;
2245  case 'l': num2 = sizeof(long)*8; ptr++; break;
2246  case 'z': num2 = sizeof(size_t)*8; ptr++; break;
2247  case 'm': num2 = sizeof(intmax_t)*8; ptr++; break;
2248  case 'p': num2 = sizeof(intptr_t)*8; ptr++; break;
2249  default: num2 = sizeof(int)*8; } }
2250  else if(specifier == 'f'){ num2 = sizeof(float)*8; }
2251  else if(specifier == 'd'){ num2 = sizeof(double)*8; }
2252  else { AARRAY_safety(, AARRAY_Error_FormatStringMalformed); }
2253  AARRAY_safety(,if(!num2) AARRAY_Error_FormatStringMalformed);
2254  start = ptr;
2255  break; }
2256  ptr++; }
2257  /* return parser values */
2258  *pspecifier = specifier; *pnum1 = num1; *pnum2 = num2;
2259  *pend = end; *pstart = start; *pptr = ptr; })
2260 
2261 static const char AARRAY_baseChars[] =
2262  "0123456789abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ._";
2263 AARRAY_define(void AARRAY_u_to_str(
2264  uint64_t value,
2265  /* can contain INTMAX_MAX in binary */
2266  char str[(8 * sizeof(int64_t))+1], int base), {
2267  char*walkstr=str;
2268  /* validate base */
2269  if(base<2 || base>64) base = 10;
2270  /* reverse number */
2271  do *walkstr++ = AARRAY_baseChars[value%(unsigned int)base]; while(value/=(unsigned int)base);
2272  *walkstr='\0';
2273  char aux; while(--walkstr>str) aux=*walkstr, *walkstr=*str, *str++=aux; })
2274 AARRAY_define(void AARRAY_i_to_str(
2275  int64_t value,
2276  char str[(8 * sizeof(int64_t))+1], int base), {
2277  char*walkstr=str;
2278  /* validate base */
2279  if(base<2 || base>64) base = 10;
2280  uint8_t sign = value < 0;
2281  if(sign) value = -value;
2282  /* reverse number */
2283  do *walkstr++ = AARRAY_baseChars[(uint64_t)value%(unsigned int)base];
2284  while((value=(int64_t)((uint64_t)value/(unsigned int)base)));
2285  if(sign) *walkstr++ = '-';
2286  else *walkstr++ = '+';
2287  *walkstr='\0';
2288  char aux; while(--walkstr>str) aux=*walkstr, *walkstr=*str, *str++=aux; })
2289 
2290 /* cppp let Fmt be defined once, but output to both streams and arrays */
2291 $define OUTPUT_A(A,B) A
2292 
2293 $define OUTPUT_B(A,B) B
2294 
2295 $define FMT_PRINT(isCHAR, isCHARptr, isINT8, isINT16, isINT32,
2296  isINT64, isFLOAT, isDOUBLE, OUTPUT_AB)
2297  case '%': {
2298  OUTPUT_AB(if(EOF==fputc('%', fmtOut)) return -1,
2299  (void)aAppend(fmtOut, '%'));
2300  break; }
2301  case 's': {
2302  AARRAY_safety(, if(vc>=vecCount) AARRAY_Error_FormatStringArgs);
2303  AARRAY_safety(, if(!vec[vc]) AARRAY_Error_NullParameter)
2304  OUTPUT_AB(if(EOF==fputs(isCHARptr, fmtOut)) return -1,
2305  (void)aAppendArray(fmtOut, SIZE_MAX,
2306  (uintptr_t)AARRAY_move(isCHARptr)));
2307  break; }
2308  case 'c': {
2309  AARRAY_safety(, if(vc>=vecCount) AARRAY_Error_FormatStringArgs);
2310  OUTPUT_AB(if(EOF==fputc(isCHAR, fmtOut)) return -1,
2311  (void)aAppend(fmtOut, (uint8_t)isCHAR));
2312  break; }
2313  case 'u': {
2314  AARRAY_safety(, if(vc>=vecCount) AARRAY_Error_FormatStringArgs);
2315  AARRAY_u_to_str((num2==8? isINT8 :
2316  (num2==16? isINT16 : (num2==32? isINT32 :isINT64))),
2317  buffer, num1);
2318  OUTPUT_AB(if(EOF==fputs(buffer, fmtOut)) return -1,
2319  (void)aAppendArray(fmtOut, SIZE_MAX,
2320  (uintptr_t)AARRAY_move(buffer)));
2321  break; }
2322  case 'i': {
2323  AARRAY_safety(, if(vc>=vecCount) AARRAY_Error_FormatStringArgs);
2324  AARRAY_i_to_str((num2==8? (int8_t)isINT8 :
2325  (num2==16? (int16_t)isINT16 :
2326  (num2==32? (int32_t)isINT32 : (int64_t)isINT64))),
2327  buffer, num1);
2328  OUTPUT_AB(if(EOF==fputs(buffer, fmtOut)) return -1,
2329  (void)aAppendArray(fmtOut, SIZE_MAX,
2330  (uintptr_t)AARRAY_move(buffer)));
2331  break; }
2332  case 'f': case 'd': {
2333  AARRAY_safety(, if(vc>=vecCount) AARRAY_Error_FormatStringArgs);
2334  OUTPUT_AB(if(EOF==fprintf(fmtOut, "%g",
2335  specifier=='f'?(double)isFLOAT:isDOUBLE)) return -1,
2336  int len = snprintf(*fmtOut, 0, "%g",
2337  specifier=='f'?(double)isFLOAT:isDOUBLE);
2338  /* safe to assume no errors from snprintf */
2339  size_t oldlen = aLength(*fmtOut);
2340  (void)aMulti(fmtOut, oldlen, 0, 0, (uintptr_t)len+1, 0);
2341  snprintf(&(*fmtOut)[oldlen], (size_t)len+1, "%g",
2342  specifier=='f'?(double)isFLOAT:isDOUBLE);
2343  (void)aZLength2(*fmtOut, 1));
2344  break; }
2345 
2346 $define GENERATE_Fmt(NAME, OUTPUT_AB)
2347 AARRAY_define(int AARRAY_Fmt_$##NAME(char errLoc[],
2348  OUTPUT_AB(FILE*, char**) fmtOut,
2349  size_t vecCount, uint64_t vec[]), {
2350  AARRAY_safety(, if(!fmtOut) AARRAY_Error_NullParameter);
2351  size_t ptr= 0, prevStart = 0, start = 0, end = 0, vc = 0;
2352  char specifier = 0; size_t doublePercent;
2353  /* defined to avoid static-analysis false positive */
2354  int num1 = 0, num2 = 0;
2355  if(!vecCount) return 0;
2356  char*fmt = (char*)vec[vc++];
2357  AARRAY_safety(, if(!fmt) AARRAY_Error_NullParameter);
2358  /* big enough for binary INTMAX_MAX */
2359  char buffer[(8 * sizeof(intmax_t))+1];
2360  while(1) {
2361  prevStart = start;
2362  AARRAY_percent_parse(errLoc, fmt, &ptr,
2363  &specifier, &num1, &num2, &start, &end,
2364  &doublePercent);
2365  OUTPUT_AB(if(end-prevStart < fwrite(fmt+prevStart, sizeof(char),
2366  end-prevStart, fmtOut)) return -1,
2367  (void)aAppendArray(fmtOut, end-prevStart,
2368  (uintptr_t)AARRAY_move(&fmt[prevStart])));
2369  switch(specifier) {
2370  case 'e':
2371  AARRAY_safety(, OUTPUT_AB(, (void)aAppend(fmtOut, 'X'); (void)aZLength2(*fmtOut, 1)));
2372  return 0;
2373  FMT_PRINT((char)vec[vc], (char*)vec[vc], (uint8_t)vec[vc],
2374  (uint16_t)vec[vc], (uint32_t)vec[vc], (uint64_t)vec[vc],
2375  *(float*)&vec[vc], *(double*)&vec[vc], OUTPUT_AB)
2376  case 'v':
2377  AARRAY_safety(, if(vc>=vecCount) AARRAY_Error_FormatStringArgs);
2378  prevStart = end+2;
2379  doublePercent = 0;
2380  do {
2381  AARRAY_percent_parse(errLoc, fmt, &ptr,
2382  &specifier, &num1, &num2, &start, &end,
2383  &doublePercent); }
2384  while(specifier == '%');
2385  AARRAY_safety(, if(specifier=='e' || specifier=='v')
2386  AARRAY_Error_FormatStringMalformed);
2387  size_t nn = (size_t)-1; while(++nn < aLength((uintptr_t*)(vec[vc]))) {
2388  if(nn) {
2389  /* resolving %% to % is a pain, since we now have to */
2390  /* loop through %v's separator again, doing the conversion */
2391  if(doublePercent) {
2392  size_t ptr2 = prevStart; while(ptr2 < doublePercent)
2393  switch(fmt[ptr2]) {
2394  case '%': ptr2+=2; OUTPUT_AB(fputc('%', fmtOut),
2395  (void)aAppend(fmtOut, '%')); break;
2396  default: OUTPUT_AB(fputc(fmt[ptr2++], fmtOut),
2397  (void)aAppend(fmtOut, (uint8_t)fmt[ptr2++])); }
2398  prevStart = doublePercent; }
2399  OUTPUT_AB(if(end-prevStart <fwrite(fmt+prevStart, sizeof(char),
2400  end-prevStart, fmtOut)) return -1,
2401  (void)aAppendArray(fmtOut, end-prevStart,
2402  (uintptr_t)AARRAY_move(&fmt[prevStart]))); }
2403  switch(specifier) {
2404  FMT_PRINT(((char*)vec[vc])[nn], ((char**)vec[vc])[nn],
2405  ((uint8_t*)vec[vc])[nn], ((uint16_t*)vec[vc])[nn],
2406  ((uint32_t*)vec[vc])[nn], ((uint64_t*)vec[vc])[nn],
2407  ((float*)vec[vc])[nn], ((double*)vec[vc])[nn], OUTPUT_AB); } }
2408  break; }
2409  vc++;
2410  specifier = 0; }
2411  return 0; })
2412 
2413 GENERATE_Fmt(File, OUTPUT_A)
2414 GENERATE_Fmt(Array, OUTPUT_B)
2415 
2416 AARRAY_define(int AARRAY_Fmt_Error(
2417  char errLoc[], size_t vecCount, uint64_t vec[]), {
2418  fflush(stdout);
2419  int returnValue = AARRAY_Fmt_File(errLoc, stderr, vecCount, vec);
2420  fflush(stderr);
2421  return returnValue; })
2422 
2423 #define aFmt(...) AARRAY_Fmt_File (AARRAY_LINE, stdout, \
2424  AARRAY_64bitArgs(__VA_ARGS__))
2425 #define aFmtE(...) AARRAY_Fmt_Error(AARRAY_LINE, \
2426  AARRAY_64bitArgs(__VA_ARGS__))
2427 #define aFmtF(file, ...) AARRAY_Fmt_File (AARRAY_LINE, file, \
2428  AARRAY_64bitArgs(__VA_ARGS__))
2429 #define aFmtA(array, ...) AARRAY_Fmt_Array(AARRAY_LINE, array, \
2430  AARRAY_64bitArgs(__VA_ARGS__))
2431 
2432 
2433 
2434 
2435 #if !defined(AARRAY_NOCONVENIENCE)
2436  #define aA aAppend
2437  #define aR aReplace
2438  #define aAA aAppendArray
2439  #define aRA aReplaceArray
2440  #define aD aDelete
2441  #define aC aConcat
2442 
2443  #define aL aLength
2444  #define aL2 aLength2
2445  #define aZL2 aZLength2
2446 
2447  #define aF aFmt
2448  #define aFE aFmtE
2449  #define aFF aFmtF
2450  #define aFA aFmtA
2451  #define aW aWrite
2452  #define aWE aWriteE
2453  #define aWF aWriteF
2454 
2455  #define aStr(string) aAppendArray((char**)NULL, SIZE_MAX, (uintptr_t)string)
2456 #endif
2457 
2458 #if defined(__cplusplus)
2459  AARRAY_nowarn_pedantic_cpp_end
2460 #endif
2461 
2462 #endif