Skip to content

Commit

Permalink
Avoid allocating intermediate field builder list. (#245)
Browse files Browse the repository at this point in the history
During encoding, we used to create a list of builders for
the fields of a protobuf message and then make a call to
mconcat on the message builder type.  But mconcat is
recursive and therefore cannot be inlined as such, and
GHC seems reluctant to perform beta reduction on known
constructors such as (:) across module boundaries.

Therefore this commit switches from "mconcat [x, y, z]"
to "mappend (mappend x y) z" (for example).  These
appends are left associativity because the builder
writes in reverse, starting with the rightmost field.
  • Loading branch information
j6carey authored Oct 4, 2023
1 parent 88ca7ae commit b87cf2c
Show file tree
Hide file tree
Showing 2 changed files with 11 additions and 6 deletions.
8 changes: 7 additions & 1 deletion src/Proto3/Suite/DotProto/Generate.hs
Original file line number Diff line number Diff line change
Expand Up @@ -928,7 +928,13 @@ messageInstD stringType ctxt parentIdent msgIdent messageParts = do
[HsPWildCard, HsPRec (unqual_ msgName) punnedFieldsP]
(HsUnGuardedRhs encodeMessageE) []

encodeMessageE = apply mconcatE [HsList encodedFields]
encodeMessageE = case encodedFields of
[] -> memptyE
(field : fields) -> foldl op (paren field) fields
where op fs f = apply (apply mappendE [fs]) [paren f]
-- NOTE: We use a left fold because this way the leftmost field
-- is the most nested and the rightmost field--the one to be written
-- first by the right-to-left builder--is the one that is least nested.

punnedFieldsP = map (fp . coerce . recordFieldName) qualifiedFields
where fp nm = HsPFieldPat (unqual_ nm) (HsPVar (HsIdent nm))
Expand Down
9 changes: 4 additions & 5 deletions src/Proto3/Suite/DotProto/Generate/Syntax.hs
Original file line number Diff line number Diff line change
Expand Up @@ -107,10 +107,9 @@ defaultSrcLoc = SrcLoc "<generated>" 0 0

dotProtoFieldC, primC, repeatedC, nestedRepeatedC, namedC, mapC,
fieldNumberC, singleC, dotsC, pathC, qualifiedC, anonymousC, dotProtoOptionC,
identifierC, stringLitC, intLitC, floatLitC, boolLitC, trueC, falseC,
nothingC, justC, forceEmitC, mconcatE, encodeMessageFieldE,
fromStringE, decodeMessageFieldE, pureE, returnE, memptyE, msumE, atE, oneofE,
fmapE :: HsExp
identifierC, stringLitC, intLitC, floatLitC, boolLitC, trueC, falseC, nothingC,
justC, forceEmitC, encodeMessageFieldE, fromStringE, decodeMessageFieldE,
pureE, returnE, mappendE, memptyE, msumE, atE, oneofE, fmapE :: HsExp

dotProtoFieldC = HsVar (protobufASTName "DotProtoField")
primC = HsVar (protobufASTName "Prim")
Expand Down Expand Up @@ -140,10 +139,10 @@ trueC = HsVar (haskellName "True")
falseC = HsVar (haskellName "False")
nothingC = HsVar (haskellName "Nothing")
justC = HsVar (haskellName "Just")
mconcatE = HsVar (haskellName "mconcat")
fromStringE = HsVar (haskellName "fromString")
pureE = HsVar (haskellName "pure")
returnE = HsVar (haskellName "return")
mappendE = HsVar (haskellName "mappend")
memptyE = HsVar (haskellName "mempty")
msumE = HsVar (haskellName "msum")
fmapE = HsVar (haskellName "fmap")
Expand Down

0 comments on commit b87cf2c

Please sign in to comment.