@@ -17,6 +17,7 @@ module Streamly.Internal.Data.Serialize.TH
18--------------------------------------------------------------------------------
18--------------------------------------------------------------------------------
20+import Data.List (foldl')
20import Data.Word (Word16, Word32, Word64, Word8)
21import Data.Word (Word16, Word32, Word64, Word8)
22import Language.Haskell.TH
23import Language.Haskell.TH
@@ -40,6 +41,9 @@ type Field = (Maybe Name, Type)
41_x = mkName "x"
42_x = mkName "x"
43_arr :: Name
47_arr :: Name
44_arr = mkName "arr"
48_arr = mkName "arr"
@@ -72,22 +76,10 @@ matchConstructor cname numFields exp0 =
72 (normalB exp0)
76 (normalB exp0)
75−exprGetSize :: Int -> Type -> Q Exp
79+exprGetSize :: Q Exp -> (Int, Type) -> Q Exp
76−exprGetSize i ty =
80+exprGetSize acc (i, ty) =
78− (sigE (varE 'size) (appT (conT ''Size) (pure ty)))
81+ [|case size :: Size $(pure ty) of
80− (conP 'VarSize [varP _f])
81− (normalB (appE (varE _f) (varE (mkFieldName i))))
82+ Size f -> f $(acc) $(varE (mkFieldName i))|]
83− , match (conP 'ConstSize [varP _sz]) (normalB (varE _sz)) []
92getTagSize :: Int -> Int
84getTagSize :: Int -> Int
93getTagSize numConstructors
85getTagSize numConstructors
@@ -123,16 +115,23 @@ mkSizeOfExpr headTy constructors =
123 ("Attempting to get size with no constructors (" ++
115 ("Attempting to get size with no constructors (" ++
124 $(lift (pprint headTy)) ++ ")")|]
116 $(lift (pprint headTy)) ++ ")")|]
125 -- One constructor with no fields is a unit type. Size of a unit type is
117 -- One constructor with no fields is a unit type. Size of a unit type is
126− -- 1.
118+ -- 1. XXX Use isUnitType?
127 [constructor@(DataCon _ _ _ fields)] ->
119 [constructor@(DataCon _ _ _ fields)] ->
128 case fields of
120 case fields of
129− [] -> appE (conE 'ConstSize) (litE (IntegerL 1))
121+ -- Unit type
125+ (lamE [varP _acc, wildP] [| $(varE _acc) + 1 |])
132− (conE 'VarSize)
129+ (conE 'Size)
134− [varP _x]
131+ [varP _acc, varP _x]
135− (caseE (varE _x) [matchCons constructor]))
133+ [matchCons (varE _acc) constructor]))
136 _ -> sizeOfHeadDt
135 _ -> sizeOfHeadDt
@@ -140,22 +139,30 @@ mkSizeOfExpr headTy constructors =
140 tagSizeExp =
139 tagSizeExp =
141 litE (IntegerL (fromIntegral (getTagSize (length constructors))))
140 litE (IntegerL (fromIntegral (getTagSize (length constructors))))
143− sizeOfField (i, (_, ty)) = exprGetSize i ty
142+ -- XXX fields of the same type can be folded together, will reduce the code
144−
143+ -- size when there are many fields of the same type.
145− sizeOfFields fields =
144+ -- XXX const size fields can be calculated statically.
145+ -- XXX This can result in large compilation times due to nesting when there
146+ -- are many constructors. We can create a list and sum the list at run time
147+ -- to avoid that depending on the number of constructors. Or using a let
148+ -- statement for each case may help?
146− appE (varE 'sum) (listE (map sizeOfField (zip [0..] fields)))
149+ -- appE (varE 'sum) (listE (acc : map (exprGetSize (litE (IntegerL 0))) (zip [0..] fields)))
147−
150+ sizeOfFields acc fields =
151+ foldl' exprGetSize acc $ zip [0..] fields
148− matchCons (DataCon cname _ _ fields) =
153+ matchCons acc (DataCon cname _ _ fields) =
154+ let expr = sizeOfFields acc (map snd fields)
149− matchConstructor cname (length fields) (sizeOfFields fields)
155+ in matchConstructor cname (length fields) expr
151 -- XXX We fix VarSize for simplicity. Should be changed later.
157 -- XXX We fix VarSize for simplicity. Should be changed later.
152 sizeOfHeadDt =
158 sizeOfHeadDt =
153− appE
159+ let acc = [|$(varE _acc) + $(tagSizeExp)|]
154− (conE 'VarSize)
160+ f =
156− [varP _x]
162+ [varP _acc, varP _x]
158− + $(caseE (varE _x) (fmap matchCons constructors))|])
163+ (caseE (varE _x) (fmap (matchCons acc) constructors))
165+ in appE (conE 'Size) f
160--------------------------------------------------------------------------------
167--------------------------------------------------------------------------------
@@ -328,7 +335,7 @@ deriveSerializeInternal preds headTy cons = do
328 let methods =
335 let methods =
329 -- INLINE on sizeOf actually worsens some benchmarks, and improves
336 -- INLINE on sizeOf actually worsens some benchmarks, and improves
331− [ -- PragmaD (InlineP 'size Inline FunLike AllPhases)
338+ [ -- PragmaD (InlineP 'size Inlinable FunLike AllPhases)
332 FunD 'size [Clause [] (NormalB sizeOfMethod) []]
339 FunD 'size [Clause [] (NormalB sizeOfMethod) []]
333 , PragmaD (InlineP 'deserialize Inline FunLike AllPhases)
340 , PragmaD (InlineP 'deserialize Inline FunLike AllPhases)