dph-prim-seq-0.5.1.1: Data/Array/Parallel/Unlifted/Sequential/Segmented/USegd.hs
{-# LANGUAGE CPP #-}
#include "fusion-phases.h"
-- | Segment Descriptors
module Data.Array.Parallel.Unlifted.Sequential.Segmented.USegd (
-- * Types
USegd,
-- * Constructors
mkUSegd,
emptyUSegd, singletonUSegd, lengthsToUSegd,
-- * Projections
lengthUSegd, lengthsUSegd, indicesUSegd, elementsUSegd,
-- * Operations
sliceUSegd, extractUSegd
) where
import Data.Array.Parallel.Unlifted.Sequential.Vector as V
-- | Segment descriptors represent the structure of nested arrays.
-- For each segment, it stores the length and the starting index in the flat data array.
--
-- Example:
--
-- @
-- flat array data: [1, 2, 3, 4, 5, 6, 7, 8]
-- (segmentation) ---- ------- - ----
-- segd lengths: [2, 3, 1, 2]
-- indices: [0, 2, 5, 6]
-- elements: 8
-- @
data USegd
= USegd
{ usegd_lengths :: !(Vector Int) -- ^ length of each segment
, usegd_indices :: !(Vector Int) -- ^ starting index of each segment in the flat array
, usegd_elements :: !Int -- ^ total number of elements in the flat array
}
-- Constructors ---------------------------------------------------------------
-- | O(1). Construct a new segment descriptor.
mkUSegd
:: Vector Int -- ^ length of each segment
-> Vector Int -- ^ starting index of each segment
-> Int -- ^ total number of elements in the flat array
-> USegd
{-# INLINE mkUSegd #-}
mkUSegd = USegd
-- | O(1). Yield an empty segment descriptor, with no elements or segments.
emptyUSegd :: USegd
{-# INLINE emptyUSegd #-}
emptyUSegd = USegd V.empty V.empty 0
-- | O(1). Yield a singleton segment descriptor.
-- The single segment covers the given number of elements.
singletonUSegd :: Int -> USegd
{-# INLINE singletonUSegd #-}
singletonUSegd n = USegd (V.singleton n) (V.singleton 0) n
-- | O(n). Convert a length array into a segment descriptor.
--
-- The array contains the length of each segment, and we compute the
-- indices from that. Runtime is O(n) in the number of segments.
--
lengthsToUSegd :: Vector Int -> USegd
{-# INLINE lengthsToUSegd #-}
lengthsToUSegd lens
= USegd lens (V.scanl (+) 0 lens) (V.sum lens)
-- Projections ----------------------------------------------------------------
-- | O(1). Yield the overall number of segments.
lengthUSegd :: USegd -> Int
{-# INLINE lengthUSegd #-}
lengthUSegd = V.length . usegd_lengths
-- | O(1). Yield the lengths of the individual segments.
lengthsUSegd :: USegd -> Vector Int
{-# INLINE lengthsUSegd #-}
lengthsUSegd = usegd_lengths
-- | O(1). Yield the segment indices of a segment descriptor.
indicesUSegd :: USegd -> Vector Int
{-# INLINE indicesUSegd #-}
indicesUSegd = usegd_indices
-- | O(1). Yield the number of data elements.
elementsUSegd :: USegd -> Int
{-# INLINE elementsUSegd #-}
elementsUSegd = usegd_elements
-- | O(n). Extract a slice of a segment descriptor, avoiding copying where possible.
--
-- We can share the segment lengths with the original segment descriptor,
-- but still need to recompute the starting indices of each. Hence
-- runtime is O(n) in the number of segments sliced out.
--
-- NOTE: In the new segment descriptor, the starting index of the first
-- segment will be 0.
sliceUSegd
:: USegd -- ^ source segment descriptor
-> Int -- ^ index of first segment
-> Int -- ^ number of segments to slice out
-> USegd
{-# INLINE sliceUSegd #-}
sliceUSegd segd i n
= lengthsToUSegd $ V.slice (lengthsUSegd segd) i n
-- | O(n). Extract a slice of a segment descriptor, copying everything.
--
-- In contrast to `sliceUSegd`, this function copies the array of
-- segment lengths as well as recomputing the starting indices of each.
--
-- NOTE: In the new segment descriptor, the starting index of the first
-- segment will be 0.
extractUSegd
:: USegd -- ^ source segment desciptor
-> Int -- ^ index of the first segment
-> Int -- ^ number of segments to extract out
-> USegd
{-# INLINE extractUSegd #-}
extractUSegd segd i n
= lengthsToUSegd $ V.extract (lengthsUSegd segd) i n