This module provides a mutable version of Streamly.Data.Array. The
contents of a mutable array can be modified in-place. For general
documentation, please refer to the original module.
An unboxed mutable array. An array is created with a given length
and capacity. Length is the number of valid elements in the array. Capacity
is the maximum number of elements that the array can be expanded to without
having to reallocate the memory.
The elements in the array can be mutated in-place without changing the
reference (constructor). However, the length of the array cannot be mutated
in-place. A new array reference is generated when the length changes. When
the length is increased (upto the maximum reserved capacity of the array),
the array is not reallocated and the new reference uses the same underlying
memory as the old one.
Several routines in this module allow the programmer to control the capacity
of the array. The programmer can control the trade-off between memory usage
and performance impact due to reallocations when growing or shrinking the
array.
Create a MutArray from the first N elements of a list. The array is
allocated to size N, if the list terminates before N elements then the
array may hold less than N elements.
createOf n folds a maximum of n elements from the input stream to an
MutArray.
Example3 expressions
>>> createOf = MutArray.createOfWith MutArray.new>>> createOf n = Fold.take n (MutArray.unsafeCreateOf n)>>> createOf n = MutArray.appendN n (MutArray.emptyOf n)
The array is mutated to append an additional element to it. If there is no
reserved space available in the array then it is reallocated to double the
original size.
This is useful to reduce allocations when appending unknown number of
elements.
Note that the returned array may be a mutated version of the original array.
Example1 expression
>>> snoc = MutArray.snocWith (* 2)
Performs O(n * log n) copies to grow, but is liberal with memory allocation.
append action mutates the array generated by action to append the
input stream. If there is no reserved space available in the array it is
reallocated to double the size.
Note that the returned array may be a mutated version of original array.
O(1) Write the given element at the given index in the array.
Performs in-place mutation of the array.
Example3 expressions
>>> putIndex ix arr val = MutArray.modifyIndex ix arr (const (val, ()))>>> f = MutArray.putIndices>>> putIndex ix arr val = Stream.fold (f arr) (Stream.fromPure (ix, val))
Cast an array having elements of type a into an array having elements of
type b. The length of the array should be a multiple of the size of the
target element otherwise Nothing is returned.
The Unbox type class provides operations for serialization (unboxing)
and deserialization (boxing) of fixed-length, non-recursive Haskell data
types to and from their byte stream representation.
Unbox uses fixed size encoding, therefore, size is independent of the value,
it must be determined solely by the type. This restriction makes types with
Unbox instances suitable for storing in arrays. Note that sum types may
have multiple constructors of different sizes, the size of a sum type is
computed as the maximum required by any constructor.
The peekAt operation reads as many bytes from the mutable byte
array as the size of the data type and builds a Haskell data type from
these bytes. pokeAt operation converts a Haskell data type to its
binary representation which consists of size bytes and then stores
these bytes into the mutable byte array. These operations do not check the
bounds of the array, the user of the type class is expected to check the
bounds before peeking or poking.
IMPORTANT: The serialized data's byte ordering remains the same as the host
machine's byte order. Therefore, it can not be deserialized from host
machines with a different byte ordering.
Instances can be derived via Generics, Template Haskell, or written
manually. Note that the data type must be non-recursive. WARNING! Generic
and Template Haskell deriving, both hang for recursive data types. Deriving
via Generics is more convenient but Template Haskell should be preferred
over Generics for the following reasons:
Instances derived via Template Haskell provide better and more reliable
performance.
Generic deriving allows only 256 fields or constructor tags whereas
template Haskell has no limit.
Here is an example, for deriving an instance of this type class using
generics:
Example2 expressions
>>> import GHC.Generics (Generic)>>> :{data Object = Object { _int0 :: Int , _int1 :: Int } deriving Generic:}