summaryrefslogtreecommitdiff
path: root/src/ImmutGrowVector.hs
blob: ee38bc489a79915a6ff2ec32211638f7401de372 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
module ImmutGrowVector where

import Data.Vector.Unboxed (Unbox)
import Data.Vector.Unboxed qualified as VU


-- | Acts like an immutable storable vector, except that it's split in a long
-- prefix and a short suffix so that modifications at the end are cheap. If the
-- suffix gets longer (by appending elements), the suffix elements are promoted
-- to prefix elements once in a while, resulting in a big copy at those times.
data ImmutGrowVector a = ImmutGrowVector (VU.Vector a) (VU.Vector a)
  deriving (Show)

empty :: Unbox a => ImmutGrowVector a
empty = ImmutGrowVector VU.empty VU.empty

fromListN :: Unbox a => Int -> [a] -> ImmutGrowVector a
fromListN n l
  | n > 2 =
      let (l1, l2) = splitAt (n - 2) l
      in ImmutGrowVector (VU.fromListN (n - 2) l1) (VU.fromListN 2 l2)
  | otherwise =
      ImmutGrowVector VU.empty (VU.fromListN n l)

(!) :: Unbox a => ImmutGrowVector a -> Int -> a
ImmutGrowVector prefix suffix ! i
  | i < VU.length prefix = prefix VU.! i
  | otherwise = suffix VU.! (i - VU.length prefix)

length :: Unbox a => ImmutGrowVector a -> Int
length (ImmutGrowVector prefix suffix) = VU.length prefix + VU.length suffix

set :: Unbox a => ImmutGrowVector a -> Int -> a -> ImmutGrowVector a
set (ImmutGrowVector prefix suffix) idx value
  | idx < VU.length prefix = error "ImmutGrowVector: mutation in slow part"
  | otherwise = ImmutGrowVector prefix (suffix VU.// [(idx - VU.length prefix, value)])

append :: Unbox a => ImmutGrowVector a -> a -> ImmutGrowVector a
append (ImmutGrowVector prefix suffix) value
  | VU.length suffix < 8 = ImmutGrowVector prefix (suffix `VU.snoc` value)
  | otherwise =
      let n = VU.length suffix
      in ImmutGrowVector (prefix <> VU.take (n - 1) suffix) (VU.drop (n - 1) suffix `VU.snoc` value)

-- | Transform the vector by mapping the underlying unboxed vectors
mapUVector :: (VU.Vector a -> VU.Vector b) -> ImmutGrowVector a -> ImmutGrowVector b
mapUVector f (ImmutGrowVector prefix suffix) = ImmutGrowVector (f prefix) (f suffix)