HORIZON HASKELLDocslts/ghc-9.10.xc74966e2026-09-27Search names, modules, packages, or :: a typeCtrl K

GHC 9.10.3 · lts/ghc-9.10.x · c74966e · 2026-09-27

Modulestreamly-core-0.2.2Haskell2010

Streamly.Internal.Data.Ring

A ring array is a circular mutable array.

  • 1 type
  • 32 values
datadata Ring a
#

A ring buffer is a mutable array of fixed size. Initially the array is empty, with ringStart pointing at the start of allocated memory. We call the next location to be written in the ring as ringHead. Initially ringHead == ringStart. When the first item is added, ringHead points to ringStart + sizeof item. When the buffer becomes full ringHead would wrap around to ringStart. When the buffer is full, ringHead always points at the oldest item in the ring and the newest item added always overwrites the oldest item.

When using it we should keep in mind that a ringBuffer is a mutable data structure. We should not leak out references to it for immutable use.

Constructors

Construction

6 declarations
valuenew :: Storable a => Int -> IO (Ring a, Ptr a)
#

Create a new ringbuffer and return the ring buffer and the ringHead. Returns the ring and the ringHead, the ringHead is same as ringStart.

valuenewRing :: Int -> m (Ring a)
#

newRing count allocates an empty array that can hold count items. The memory of the array is uninitialized and the allocation is aligned as per the Storable instance of the type.

Unimplemented

valuewriteN :: Int -> Fold m a (Ring a)
#

writeN n is a rolling fold that keeps the last n elements of the stream in a ring array.

Unimplemented

valueadvance :: Storable a => Ring a -> Ptr a -> Ptr a
#

Advance the ringHead by 1 item, wrap around if we hit the end of the array.

valuemoveBy :: Storable a => Int -> Ring a -> Ptr a -> Ptr a
#

Move the ringHead by n items. The direction depends on the sign on whether n is positive or negative. Wrap around if we hit the beginning or end of the array.

valuestartOf :: Ring a -> Ptr a
#

Get the first address of the ring as a pointer.

Random writes

4 declarations
valueunsafeInsert :: Storable a => Ring a -> Ptr a -> a -> IO (Ptr a)
#

Insert an item at the head of the ring, when the ring is full this replaces the oldest item in the ring with the new item. This is unsafe beause ringHead supplied is not verified to be within the Ring. Also, the ringStart foreignPtr must be guaranteed to be alive by the caller.

valueslide :: Ring a -> a -> m (Ring a)
#

Insert an item at the head of the ring, when the ring is full this replaces the oldest item in the ring with the new item.

Unimplemented

valueputIndex :: Ring a -> Int -> a -> m ()
#

O(1) Write the given element at the given index in the ring array. Performs in-place mutation of the array.

Example1 expression
putIndex arr ix val = Ring.modifyIndex arr ix (const (val, ()))

Unimplemented

valuemodifyIndex :: Ring a -> Int -> (a -> (a, b)) -> m b
#

Modify a given index of a ring array using a modifier function.

Unimplemented

Unfolds

2 declarations
valueread :: (MonadIO m, Storable a) => Unfold m (Ring a, Ptr a, Int) a
#

Read n elements from the ring starting at the supplied ring head. If n is more than the ring size it keeps reading the ring in a circular fashion.

If the ring is not full the user must ensure than n is less than or equal to the number of valid elements in the ring.

Internal

Random reads

3 declarations
valuegetIndex :: Ring a -> Int -> m a
#

O(1) Lookup the element at the given index. Index starts from 0.

valuegetIndexUnsafe :: Ring a -> Int -> m a
#

Return the element at the specified index without checking the bounds.

Unsafe because it does not check the bounds of the ring array.

valuegetIndexRev :: Ring a -> Int -> m a
#

O(1) Lookup the element at the given index from the end of the array. Index starts from 0.

Slightly faster than computing the forward index and using getIndex.

Size

4 declarations
valuelength :: Ring a -> Int
#

O(1) Get the length of the array i.e. the number of elements in the array.

Note that byteLength is less expensive than this operation, as length involves a costly division operation.

Unimplemented

valuebyteCapacity :: Ring a -> Int
#

Get the total capacity of an array. An array may have space reserved beyond the current used length of the array.

Pre-release

valuebytesFree :: Ring a -> Int
#

The remaining capacity in the array for appending more elements without reallocation.

Pre-release

Casting

4 declarations
valuecast :: Storable b => Ring a -> Maybe (Ring b)
#

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.

Pre-release

valuecastUnsafe :: Ring a -> Ring b
#

Cast an array having elements of type a into an array having elements of type b. The array size must be a multiple of the size of type b.

Unimplemented

Folds

4 declarations
valueunsafeFoldRing :: Storable a => Ptr a -> (b -> a -> b) -> b -> Ring a -> b
#

Fold the buffer starting from ringStart up to the given Ptr using a pure step function. This is useful to fold the items in the ring when the ring is not full. The supplied pointer is usually the end of the ring.

Unsafe because the supplied Ptr is not checked to be in range.

valueunsafeFoldRingFullM
  1. :: (MonadIO m, Storable a)
  2. => Ptr a
  3. -> b -> a -> m b
  4. -> b
  5. -> Ring a
  6. -> m b
#

Fold the entire length of a ring buffer starting at the supplied ringHead pointer. Assuming the supplied ringHead pointer points to the oldest item, this would fold the ring starting from the oldest item to the newest item in the ring.

Note, this will crash on ring of 0 size.

valueunsafeFoldRingNM
  1. :: (MonadIO m, Storable a)
  2. => Int
  3. -> Ptr a
  4. -> b -> a -> m b
  5. -> b
  6. -> Ring a
  7. -> m b
#

Fold Int items in the ring starting at Ptr a. Won't fold more than the length of the ring.

Note, this will crash on ring of 0 size.

Stream of Arrays

1 declaration
valueringsOf :: Int -> Stream m a -> Stream m (MutArray a)
#

ringsOf n stream groups the input stream into a stream of ring arrays of size n. Each ring is a sliding window of size n.

Unimplemented

Fast Byte Comparisons

4 declarations
valueunsafeEqArray :: Ring a -> Ptr a -> Array a -> Bool
#

Byte compare the entire length of ringBuffer with the given array, starting at the supplied ringHead pointer. Returns true if the Array and the ringBuffer have identical contents.

This is unsafe because the ringHead Ptr is not checked to be in range. The supplied array must be equal to or bigger than the ringBuffer, ARRAY BOUNDS ARE NOT CHECKED.

valueslidingWindow
  1. :: (MonadIO m, Storable a, Unbox a)
  2. => Int
  3. -> Fold m (a, Maybe a) b
  4. -> Fold m a b
#

slidingWindow collector is an incremental sliding window fold that does not require all the intermediate elements in a computation. This maintains n elements in the window, when a new element comes it slides out the oldest element and the new element along with the old element are supplied to the collector fold.

The Maybe type is for the case when initially the window is filling and there is no old element.

valueslidingWindowWith
  1. :: (MonadIO m, Storable a, Unbox a)
  2. => Int
  3. -> Fold m ((a, Maybe a), m (MutArray a)) b
  4. -> Fold m a b
#

Like slidingWindow but also provides the entire ring contents as an Array. The array reflects the state of the ring after inserting the incoming element.

IMPORTANT NOTE: The ring is mutable, therefore, the result of (m (Array a)) action depends on when it is executed. It does not capture the sanpshot of the ring at a particular time.