summaryrefslogtreecommitdiff
path: root/libraries/compact/Data/Compact.hs
diff options
context:
space:
mode:
Diffstat (limited to 'libraries/compact/Data/Compact.hs')
-rw-r--r--libraries/compact/Data/Compact.hs89
1 files changed, 89 insertions, 0 deletions
diff --git a/libraries/compact/Data/Compact.hs b/libraries/compact/Data/Compact.hs
new file mode 100644
index 0000000000..7cedd1c27a
--- /dev/null
+++ b/libraries/compact/Data/Compact.hs
@@ -0,0 +1,89 @@
+{-# LANGUAGE BangPatterns #-}
+{-# LANGUAGE CPP #-}
+{-# LANGUAGE MagicHash #-}
+{-# LANGUAGE UnboxedTuples #-}
+
+-----------------------------------------------------------------------------
+-- |
+-- Module : Data.Compact
+-- Copyright : (c) The University of Glasgow 2001-2009
+-- (c) Giovanni Campagna <gcampagn@cs.stanford.edu> 2014
+-- License : BSD-style (see the file LICENSE)
+--
+-- Maintainer : libraries@haskell.org
+-- Stability : unstable
+-- Portability : non-portable (GHC Extensions)
+--
+-- This module provides a data structure, called a Compact, for
+-- holding fully evaluated data in a consecutive block of memory.
+--
+-- /Since: 1.0.0/
+module Data.Compact (
+ Compact,
+ getCompact,
+ inCompact,
+ isCompact,
+
+ newCompact,
+ newCompactNoShare,
+ appendCompact,
+ appendCompactNoShare,
+ ) where
+
+-- Write down all GHC.Prim deps explicitly to keep them at minimum
+import GHC.Prim (Compact#,
+ compactNew#,
+ State#,
+ RealWorld,
+ Int#,
+ )
+-- We need to import Word from GHC.Types to see the representation
+-- and to able to access the Word# to pass down the primops
+import GHC.Types (IO(..), Word(..))
+
+import Control.DeepSeq (NFData, force)
+
+import Data.Compact.Internal(Compact(..),
+ isCompact,
+ inCompact,
+ compactAppendEvaledInternal)
+
+-- |Retrieve the object that was stored in a Compact
+getCompact :: Compact a -> a
+getCompact (Compact _ obj) = obj
+
+compactAppendInternal :: NFData a => Compact# -> a -> Int# ->
+ State# RealWorld -> (# State# RealWorld, Compact a #)
+compactAppendInternal buffer root share s =
+ case force root of
+ !eval -> compactAppendEvaledInternal buffer eval share s
+
+compactAppendInternalIO :: NFData a => Int# -> Compact b -> a -> IO (Compact a)
+compactAppendInternalIO share (Compact buffer _) root =
+ IO (\s -> compactAppendInternal buffer root share s)
+
+-- |Append a value to a 'Compact', and return a new 'Compact'
+-- that shares the same buffer but a different root object.
+appendCompact :: NFData a => Compact b -> a -> IO (Compact a)
+appendCompact = compactAppendInternalIO 1#
+
+-- |Append a value to a 'Compact'. This function differs from
+-- 'appendCompact' in that it will not preserve internal sharing
+-- in the passed in value (and it will diverge on cyclic structures).
+appendCompactNoShare :: NFData a => Compact b -> a -> IO (Compact a)
+appendCompactNoShare = compactAppendInternalIO 0#
+
+compactNewInternal :: NFData a => Int# -> Word -> a -> IO (Compact a)
+compactNewInternal share (W# size) root =
+ IO (\s -> case compactNew# size s of
+ (# s', buffer #) -> compactAppendInternal buffer root share s' )
+
+-- |Create a new 'Compact', with the provided value as suggested block
+-- size (which will be adjusted if unsuitable), and append the given
+-- value to it, as if calling 'appendCompact'
+newCompact :: NFData a => Word -> a -> IO (Compact a)
+newCompact = compactNewInternal 1#
+
+-- |Create a new 'Compact', but append the value using 'appendCompactNoShare'
+newCompactNoShare :: NFData a => Word -> a -> IO (Compact a)
+newCompactNoShare = compactNewInternal 0#