packages feed

project-m36-1.2.0: src/lib/ProjectM36/RelExprSize.hs

{-# LANGUAGE MagicHash, FlexibleInstances #-}
module ProjectM36.RelExprSize where
import ProjectM36.Base
import Data.Int
#ifdef MIN_VERSION_ghc_bignum
import GHC.Num.Integer
import GHC.Num.BigNat
#else
import GHC.Integer.GMP.Internals
import GHC.Exts
#endif
import qualified Data.Text as T
import Data.Time.Clock
import qualified Data.ByteString as BS
import Data.Time.Calendar
import qualified Data.Map as M
import Data.Scientific

type ByteCount = Int64

-- | Provide reasonably accurate but fast estimates for size of the data.
class Size a where
  size :: a -> ByteCount

instance Size (RelationalExprBase a) where
  size expr =   
    case expr of
      MakeRelationFromExprs _ tupleExprs -> size tupleExprs
      MakeStaticRelation _ tupSet -> size tupSet
      ExistingRelation (Relation _ tupSet) -> size tupSet
      RelationVariable _ _ -> 0
      RelationValuedAttribute _ -> 0
      Project _ expr' -> size expr'
      Union exprA exprB -> size exprA + size exprB
      Join exprA exprB -> size exprA + size exprB
      Rename _ expr' -> size expr'
      Difference exprA exprB -> size exprA + size exprB
      Group _ _ expr' -> size expr'
      Ungroup _ expr' -> size expr'
      Restrict _ expr' -> size expr'
      Equals exprA exprB -> size exprA + size exprB
      NotEquals exprA exprB -> size exprA + size exprB
      Extend _ expr' -> size expr'
      With macros expr' -> size expr' + sum (fmap (size . snd) macros)

ptrSize :: Int -> Int64
ptrSize l = fromIntegral $ 8 * l

instance Size RelationTupleSet where
  size (RelationTupleSet tups) = sum (fmap size tups) + ptrSize (length tups)

instance Size RelationTuple where
  size (RelationTuple _ atoms) = sum (fmap size atoms) + ptrSize (length atoms)
                                     
instance Size (TupleExprsBase a) where
  size (TupleExprs _ exprs) = sum (fmap size exprs) + ptrSize (length exprs)

instance Size (TupleExprBase a) where
  size (TupleExpr tupMap) = sum (fmap size tupMap) + ptrSize (M.size tupMap) * 2

instance Size (AtomExprBase a) where
  size expr =
    case expr of
      AttributeAtomExpr{} -> 0
      NakedAtomExpr a -> size a
      FunctionAtomExpr _ exprs _ -> sum (fmap size exprs) + ptrSize (length exprs)
      RelationAtomExpr relexpr -> size relexpr
      ConstructedAtomExpr _ exprs _ -> sum (fmap size exprs) + ptrSize (length exprs)
      SubrelationAttributeAtomExpr{} -> 0
      IfThenAtomExpr if' then' else' -> size if' + size then' + size else'

instance Size Atom where
  size atom =
    case atom of
      IntegerAtom i -> size i
      IntAtom _ -> 8
      ScientificAtom s -> size s
      DoubleAtom _ -> 8
      TextAtom t -> fromIntegral $ T.length t * 2 --UTF-16 until text-2.0 is widespread
      DayAtom d -> size (toModifiedJulianDay d)
      DateTimeAtom (UTCTime d dt) -> size d + size dt
      ByteStringAtom bs -> fromIntegral $ BS.length bs
      BoolAtom _ -> 1
      UUIDAtom _ -> 16
      RelationAtom rel -> size rel
      RelationalExprAtom expr -> size expr
      ConstructedAtom _ _ atoms -> 8 + sum (fmap size atoms)
      SubrelationFoldAtom rel _attr -> 8 + size rel

instance Size Relation where
  size (Relation _ tupSet) = size tupSet + ptrSize (length (asList tupSet))

instance Size Integer where
#ifdef MIN_VERSION_ghc_bignum
  size (IS _) = 8
  size (IP bn) = fromIntegral (8 + bigNatSize bn)
  size (IN bn) = fromIntegral (8 + bigNatSize bn)
#else  
  size (S# _) = 8
  size (Jp# (BN# bytearray)) = fromIntegral (I# (sizeofByteArray# bytearray))
  size (Jn# (BN# bytearray)) = fromIntegral (I# (sizeofByteArray# bytearray))
#endif

instance Size Day where
  size d = size $ toModifiedJulianDay d

instance Size DiffTime where
  size d = size $ diffTimeToPicoseconds d

instance Size Scientific where
  size s = 8 + size (coefficient s)

instance Size [RelationTuple] where
  size = foldr (\t acc -> acc + size t) 0