summaryrefslogtreecommitdiff
path: root/src/ImmutGrowVector.hs
diff options
context:
space:
mode:
authorTom Smeding <tom@tomsmeding.com>2026-04-06 23:35:05 +0200
committerTom Smeding <tom@tomsmeding.com>2026-04-06 23:36:28 +0200
commit287d9e5c4fc50bcca2474b9783148181d7ede872 (patch)
tree81a80cc5f5aabb2d3cffd3874438782d32096cff /src/ImmutGrowVector.hs
parent875da72c83b20260ac5af2bdcc8b992d657fd97e (diff)
Log watching
Diffstat (limited to 'src/ImmutGrowVector.hs')
-rw-r--r--src/ImmutGrowVector.hs43
1 files changed, 43 insertions, 0 deletions
diff --git a/src/ImmutGrowVector.hs b/src/ImmutGrowVector.hs
new file mode 100644
index 0000000..d36209d
--- /dev/null
+++ b/src/ImmutGrowVector.hs
@@ -0,0 +1,43 @@
+module ImmutGrowVector where
+
+import Foreign.Storable
+import Data.Vector.Storable qualified as VS
+
+
+-- | 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 (VS.Vector a) (VS.Vector a)
+ deriving (Show)
+
+empty :: Storable a => ImmutGrowVector a
+empty = ImmutGrowVector VS.empty VS.empty
+
+fromListN :: Storable a => Int -> [a] -> ImmutGrowVector a
+fromListN n l
+ | n > 2 =
+ let (l1, l2) = splitAt (n - 2) l
+ in ImmutGrowVector (VS.fromListN (n - 2) l1) (VS.fromListN 2 l2)
+ | otherwise =
+ ImmutGrowVector VS.empty (VS.fromListN n l)
+
+(!) :: Storable a => ImmutGrowVector a -> Int -> a
+ImmutGrowVector prefix suffix ! i
+ | i < VS.length prefix = prefix VS.! i
+ | otherwise = suffix VS.! (i - VS.length prefix)
+
+length :: Storable a => ImmutGrowVector a -> Int
+length (ImmutGrowVector prefix suffix) = VS.length prefix + VS.length suffix
+
+set :: Storable a => ImmutGrowVector a -> Int -> a -> ImmutGrowVector a
+set (ImmutGrowVector prefix suffix) idx value
+ | idx < VS.length prefix = error "ImmutGrowVector: mutation in slow part"
+ | otherwise = ImmutGrowVector prefix (suffix VS.// [(idx - VS.length prefix, value)])
+
+append :: Storable a => ImmutGrowVector a -> a -> ImmutGrowVector a
+append (ImmutGrowVector prefix suffix) value
+ | VS.length suffix < 8 = ImmutGrowVector prefix (suffix `VS.snoc` value)
+ | otherwise =
+ let n = VS.length suffix
+ in ImmutGrowVector (prefix <> VS.take (n - 1) suffix) (VS.drop (n - 1) suffix `VS.snoc` value)