diff --git a/core/src/Streamly/Data/Array.hs b/core/src/Streamly/Data/Array.hs index 4061672b03..b869df05d3 100644 --- a/core/src/Streamly/Data/Array.hs +++ b/core/src/Streamly/Data/Array.hs @@ -107,8 +107,6 @@ module Streamly.Data.Array ) where -#include "inline.hs" - import Streamly.Internal.Data.Array import Streamly.Internal.Data.MutByteArray (Unbox(..), Serialize(..)) diff --git a/core/src/Streamly/Data/RingArray.hs b/core/src/Streamly/Data/RingArray.hs new file mode 100644 index 0000000000..81a8a232ef --- /dev/null +++ b/core/src/Streamly/Data/RingArray.hs @@ -0,0 +1,92 @@ +{-# LANGUAGE CPP #-} +-- | +-- Module : Streamly.Data.RingArray +-- Copyright : (c) 2025 Composewell Technologies +-- +-- License : BSD3 +-- Maintainer : streamly@composewell.com +-- Stability : released +-- Portability : GHC +-- +-- This module provides APIs to create and use unboxed, mutable ring arrays of +-- fixed size. Ring arrays are useful to keep a circular buffer or a sliding +-- window of elements. +-- +-- RingArrays are of fixed size but there is a way to expand the size of the +-- ring, you can copy the ring to a MutArray, expand the MutArray and the cast +-- it back to RingArray. +-- +-- This module is designed to be imported qualified: +-- +-- >>> import qualified Streamly.Data.RingArray as Ring +-- +-- Please refer to "Streamly.Internal.Data.RingArray" for functions that have +-- not yet been released. +-- + +module Streamly.Data.RingArray + ( RingArray + + -- * Construction + , createOfLast + , castMutArray -- XXX this is unsafeFreeze in Array module + , castMutArrayWith + -- , unsafeCastMutArray + -- , unsafeCastMutArrayWith + + -- * Moving the Head + , moveForward + , moveReverse + -- , moveBy + + -- * In-place Mutation + , insert + , replace + , replace_ + , putIndex + , modifyIndex + + -- * Random Access + , getIndex + , unsafeGetIndex + , unsafeGetHead + + -- * Conversion + , toList + , toMutArray + + -- * Streams + , read + , readRev + + -- * Unfolds + , reader + , readerRev + + -- * Size + , length + , byteLength + + -- * Casting + , cast + -- , unsafeCast + , asBytes + , asMutArray + -- , asMutArray_ + + -- * Folds + -- , foldlM' + , fold + + -- * Stream of Rings + , ringsOf + , scanRingsOf + + -- * Fast Byte Comparisons + , eqArray + , eqArrayN + + ) where + +import Streamly.Internal.Data.RingArray +import Prelude hiding (read, length) diff --git a/core/src/Streamly/Internal/Data/RingArray.hs b/core/src/Streamly/Internal/Data/RingArray.hs index e69c0306b7..dac99a92be 100644 --- a/core/src/Streamly/Internal/Data/RingArray.hs +++ b/core/src/Streamly/Internal/Data/RingArray.hs @@ -285,16 +285,22 @@ unsafeCastMutArray = unsafeCastMutArrayWith 0 -- field in the ring. For copying we can have another API though. -- XXX castMutArray is called unsafeFreeze in the Array module. Make the naming --- consistent? Also we can use castMutArrayWith to specify the index and use --- the default index 0. +-- consistent? --- | @castMutArray arr index@ casts a mutable array to a ring array having --- the ring head at @index@ position in the array. +-- | @castMutArrayWith index arr@ casts a mutable array to a ring array, and +-- positions the ring head at the given @index@ in the array. +-- +-- A MutArray can be a slice which means its memory starts from some offset in +-- the underlying MutableByteArray, and not from 0 offset. RingArray always +-- uses the memory from offset zero in the MutableByteArray, therefore, it +-- refuses to cast if it finds the array does not start from offset zero i.e. +-- if the array was created from some slicing operation over another array. In +-- such cases it returns 'Nothing'. +-- +-- To create a RingArray from a sliced MutArray use 'createOfLast', or clone +-- the MutArray and then cast it. -- -- This operation throws an error if the index is not within the array bounds. --- It returns Nothing if the array cannot be cast into ring because the array --- is a slice. In that case clone the array and cast it or stream the array and --- use 'createOfLast' to create a ring. -- {-# INLINE castMutArrayWith #-} castMutArrayWith :: forall a. Unbox a => Int -> MutArray a -> Maybe (RingArray a) @@ -306,8 +312,10 @@ castMutArrayWith i arr | otherwise = Nothing -- | Cast a MutArray to a ring sharing the same memory without copying. The --- ring head is at index 0 of the array. Cast fails with Nothing if the array --- is a slice. +-- ring head is positioned at index 0 of the array. The size of the ring is +-- equal to the MutArray length. +-- +-- See 'castMutArrayWith' for failure scenarios. -- -- >>> castMutArray = RingArray.castMutArrayWith 0 -- @@ -667,7 +675,8 @@ eqArrayN RingArray{..} Array.Array{..} nBytes {-# INLINE eqArray #-} eqArray :: RingArray a -> Array a -> IO Bool eqArray RingArray{..} Array.Array{..} - | arrEnd - arrStart < ringSize = error "eqArrayN: array is shorter than ring" + | arrEnd - arrStart < ringSize = + error "eqArrayN: array is shorter than ring" | otherwise = do part1 <- MutByteArray.unsafeByteCmp @@ -832,6 +841,10 @@ asMutArray rb = , ringHead rb ) +-- | Like 'asMutArray' but does not return the ring head. +-- +-- >>> asMutArray_ = fst . RingArray.asMutArray +-- {-# INLINE asMutArray_ #-} asMutArray_ :: RingArray a -> MutArray a asMutArray_ rb = diff --git a/core/streamly-core.cabal b/core/streamly-core.cabal index fc9e45dd11..1b85de2f1e 100644 --- a/core/streamly-core.cabal +++ b/core/streamly-core.cabal @@ -455,7 +455,6 @@ library -- Pre-release modules -- , Streamly.Data.Pipe - -- , Streamly.Data.RingArray -- , Streamly.Data.RingArray.Generic -- , Streamly.Data.IORef -- , Streamly.Data.List @@ -466,18 +465,18 @@ library -- , Streamly.Data.Either.Strict -- streamly-core released modules in alphabetic order - -- NOTE: these must be added to streamly.cabal as well , Streamly.Console.Stdio , Streamly.Control.Exception - , Streamly.Data.MutByteArray , Streamly.Data.Array , Streamly.Data.Array.Generic + , Streamly.Data.Fold , Streamly.Data.MutArray , Streamly.Data.MutArray.Generic - , Streamly.Data.Fold - , Streamly.Data.Scanl + , Streamly.Data.MutByteArray , Streamly.Data.Parser , Streamly.Data.ParserK + , Streamly.Data.RingArray + , Streamly.Data.Scanl , Streamly.Data.Stream , Streamly.Data.StreamK , Streamly.Data.Unfold