A dynamic array is equivalent to an OCaml array that will resize itself
when elements are added or removed, except that floats are boxed and
that no initialization element is required.

For all the traversal functions (iter, fold, map, etc.), what happens
when the array that is being traversed is mutated is not defined.Author(s): Brian Hurt, Nicolas Cannasse, David Teller (boilerplate code)

When an operation on an array fails, Invalid_arg is raised. The
integer is the value that made the operation fail, the first string
contains the function name that has been called and the second string
contains the parameter name that made the operation fail.

insert darr idx v inserts v into darr at index idx. All elements
of darr with an index greater than or equal to idx have their
index incremented (are moved up one place) to make room for the new
element.

filter p a returns all the elements of the array a
that satisfy the predicate p. The order of the elements
in the input array is preserved.

Note This function replaces another function called filter,
available in previous versions of the library. As the old function
was incompatible with comprehension of dynamic arrays, its name
was changed to BatDynArray.keep.

Array resizers

Resizer functions are called whenever elements are added to
or removed from the dynamic array to determine what the current number of
storage spaces in the array should be. The three named arguments
passed to a resizer are the current number of storage spaces in
the array, the length of the array before the elements are
added or removed, and the length the array will be after the
elements are added or removed. If elements are being added, newlength
will be larger than oldlength, if elements are being removed,
newlength will be smaller than oldlength. If the resizer function
returns exactly oldlength, the size of the array is only changed when
adding an element while there is not enough space for it.

By default, all dynamic arrays are created with the default_resizer.
When a dynamic array is created from another dynamic array (using copy,
map , etc. ) the resizer of the copy will be the same as the original
dynamic array resizer. To change the resizer, use the set_resizer
function.

The exponential resizer- The default resizer except when the resizer
is being copied from some other darray.

exponential_resizer works by doubling or halving the number of
slots until they "fit". If the number of slots is less than the
new length, the number of slots is doubled until it is greater
than the new length (or Sys.max_array_size is reached).

If the number of slots is more than four times the new length,
the number of slots is halved until it is less than four times the
new length.

Allowing darrays to fall below 25% utilization before shrinking them
prevents "thrashing". Consider the case where the caller is constantly
adding a few elements, and then removing a few elements, causing
the length to constantly cross above and below a power of two.
Shrinking the array when it falls below 50% would causing the
underlying array to be constantly allocated and deallocated.
A few elements would be added, causing the array to be reallocated
and have a usage of just above 50%. Then a few elements would be
remove, and the array would fall below 50% utilization and be
reallocated yet again. The bulk of the array, untouched, would be
copied and copied again. By setting the threshold at 25% instead,
such "thrashing" only occurs with wild swings- adding and removing
huge numbers of elements (more than half of the elements in the array).

exponential_resizer is a good performing resizer for most
applications. A list allocates 2 words for every element, while an
array (with large numbers of elements) allocates only 1 word per
element (ignoring unboxed floats). On insert, exponential_resizer
keeps the amount of wasted "extra" array elements below 50%, meaning
that less than 2 words per element are used. Even on removals
where the amount of wasted space is allowed to rise to 75%, that
only means that darray is using 4 words per element. This is
generally not a significant overhead.

Furthermore, exponential_resizer minimizes the number of copies
needed- appending n elements into an empty darray with initial size
0 requires between n and 2n elements of the array be copied- O(n)
work, or O(1) work per element (on average). A similar argument
can be made that deletes from the end of the array are O(1) as
well (obviously deletes from anywhere else are O(n) work- you
have to move the n or so elements above the deleted element down).

conservative_exponential_resizer is an example resizer function
which uses the oldlength parameter. It only shrinks the array
on inserts- no deletes shrink the array, only inserts. It does
this by comparing the oldlength and newlength parameters. Other
than that, it acts like exponential_resizer.