@@ -23,13 +23,15 @@ module Data.TypeRepMap.Internal where
2323
2424import Prelude hiding (lookup)
2525
26+import Control.Monad.ST (runST)
2627import Control.Monad.Zip (mzip)
2728import Data.Function (on)
2829import Data.IntMap.Strict (IntMap)
2930import Data.Kind (Type)
3031import Data.List (intercalate, nubBy)
3132import Data.Maybe (fromJust)
32−import Data.Primitive.Array (Array, indexArray, mapArray')
33+import Data.Primitive.Array (Array, freezeArray, indexArray, mapArray', readArray, sizeofArray,
34+ thawArray, writeArray)
3335import Data.Primitive.PrimArray (PrimArray, indexPrimArray, sizeofPrimArray)
3436import Data.Semigroup (Semigroup (..))
3537import GHC.Base (Any, Int (..), Int#, (*#), (+#), (<#))
@@ -162,6 +164,28 @@ delete :: forall a (f :: KindOf a -> Type) . Typeable a => TypeRepMap f -> TypeR
162164delete = fromTriples . deleteByFst (typeFp @a) . toTriples
163165{-# INLINE delete #-}
164166
167+{- |
168+Update a value at a specific key with the result of the provided function. When
169+the key is not a member of the map, the original map is returned.
170+
171+>>> trmap = fromList @(TypeRepMap Identity) [WrapTypeable $ Identity "a"]
172+>>> lookup @String $ adjust (fmap (++ "ww")) trmap
173+Just (Identity "aww")
174+-}
175+adjust :: forall a f . Typeable a => (f a -> f a) -> TypeRepMap f -> TypeRepMap f
176+adjust fun tr = case cachedBinarySearch (typeFp @a) (fingerprintAs tr) (fingerprintBs tr) of
177+ Nothing -> tr
178+ Just i -> tr {trAnys = changeAnyArr i (trAnys tr)}
179+ where
180+ changeAnyArr :: Int -> Array Any -> Array Any
181+ changeAnyArr i trAs = runST $ do
182+ let n = sizeofArray trAs
183+ mutArr <- thawArray trAs 0 n
184+ a <- toAny . fun . fromAny <$> readArray mutArr i
185+ writeArray mutArr i a
186+ freezeArray mutArr 0 n
187+{-# INLINE adjust #-}
188+
165189{- | Map over the elements of a 'TypeRepMap'.
166190
167191>>> tm = insert (Identity True) $ one (Identity 'a')