Skip to content

Commit 53385dd

Browse files
committed
Make size run in constant time
1 parent c03be06 commit 53385dd

File tree

4 files changed

+713
-357
lines changed

4 files changed

+713
-357
lines changed

Data/HashMap/Array.hs

Lines changed: 43 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
{-# LANGUAGE BangPatterns, CPP, MagicHash, Rank2Types, UnboxedTuples, ScopedTypeVariables #-}
2+
{-# LANGUAGE GeneralizedNewtypeDeriving #-}
23
{-# OPTIONS_GHC -fno-full-laziness -funbox-strict-fields #-}
34

45
-- | Zero based arrays.
@@ -7,6 +8,11 @@
78
module Data.HashMap.Array
89
( Array
910
, MArray
11+
, RunRes (..)
12+
, RunResA
13+
, RunResM
14+
, Size (..)
15+
, Sized (..)
1016

1117
-- * Creation
1218
, new
@@ -25,6 +31,7 @@ module Data.HashMap.Array
2531
, index#
2632
, update
2733
, updateWith'
34+
, updateWithInternal'
2835
, unsafeUpdateM
2936
, insert
3037
, insertM
@@ -36,6 +43,7 @@ module Data.HashMap.Array
3643
, unsafeThaw
3744
, unsafeSameArray
3845
, run
46+
, runInternal
3947
, run2
4048
, copy
4149
, copyM
@@ -317,10 +325,24 @@ unsafeThaw ary
317325
(# s', mary #) -> (# s', marray mary (length ary) #)
318326
{-# INLINE unsafeThaw #-}
319327

328+
-- | Helper datatype used in 'runInternal' and 'updateWithInternal'
329+
data RunRes f e = RunRes {-# UNPACK #-} !Size !(f e)
330+
331+
type RunResA e = RunRes Array e
332+
333+
type RunResM s e = RunRes (MArray s) e
334+
320335
run :: (forall s . ST s (MArray s e)) -> Array e
321336
run act = runST $ act >>= unsafeFreeze
322337
{-# INLINE run #-}
323338

339+
runInternal :: (forall s . ST s (RunResM s e)) -> RunResA e
340+
runInternal act = runST $ do
341+
RunRes s mary <- act
342+
ary <- unsafeFreeze mary
343+
return (RunRes s ary)
344+
{-# INLINE runInternal #-}
345+
324346
run2 :: (forall s. ST s (MArray s e, a)) -> (Array e, a)
325347
run2 k = runST (do
326348
(marr,b) <- k
@@ -392,7 +414,7 @@ updateM ary idx b =
392414
where !count = length ary
393415
{-# INLINE updateM #-}
394416

395-
-- | /O(n)/ Update the element at the given positio in this array, by
417+
-- | /O(n)/ Update the element at the given position in this array, by
396418
-- applying a function to it. Evaluates the element to WHNF before
397419
-- inserting it into the array.
398420
updateWith' :: Array e -> Int -> (e -> e) -> Array e
@@ -401,6 +423,26 @@ updateWith' ary idx f
401423
= update ary idx $! f x
402424
{-# INLINE updateWith' #-}
403425

426+
-- | This newtype wrapper is to avoid confusion when local functions
427+
-- take more than one paramenter of 'Int' type (see 'go' in
428+
-- 'Data.HashMap.Base.unionWithKeyInternal').
429+
newtype Size = Size { unSize :: Int }
430+
deriving (Eq, Ord, Num, Integral, Enum, Real)
431+
432+
-- | Helper datatype used in 'updateWithInternal''. Used when a change in
433+
-- a value's size must be returned along with the value itself (typically
434+
-- a hashmap).
435+
data Sized a = Sized {-# UNPACK #-} !Size !a
436+
437+
-- | /O(n)/ Update the element at the given position in this array, by
438+
-- applying a function to it. Evaluates the element to WHNF before
439+
-- inserting it into the array.
440+
updateWithInternal' :: Array e -> Int -> (e -> Sized e) -> RunResA e
441+
updateWithInternal' ary idx f =
442+
let Sized sz e = f (index ary idx)
443+
in RunRes sz (update ary idx e)
444+
{-# INLINE updateWithInternal' #-}
445+
404446
-- | /O(1)/ Update the element at the given position in this array,
405447
-- without copying.
406448
unsafeUpdateM :: Array e -> Int -> e -> ST s ()

0 commit comments

Comments
 (0)