Skip to content

Commit

Permalink
⚡️ Simplify and speed up mailbox-list parsing
Browse files Browse the repository at this point in the history
Note that this fixes `MBX_LIST_FLAGS` and `#mbx_list_flags`, which were
previously unused, and uses them too.

This gives a significant performance boost:

Warming up --------------------------------------
list_with_various_flag_capitalizations            38.976k i/s
        -     39.270k times in 1.007548s (25.66μs/i)
   rfc3501_7.2.2_LIST_response_example            50.042k i/s
        -     52.294k times in 1.044997s (19.98μs/i)
                  utf8_in_list_mailbox            41.722k i/s
        -     44.550k times in 1.067774s (23.97μs/i)
                           xlist_inbox            43.242k i/s
        -     46.387k times in 1.072725s (23.13μs/i)
Calculating -------------------------------------
                                       v0.4.5-8-g4611404d       0.4.5
list_with_various_flag_capitalizations            39.943k     35.777k i/s
        -    116.927k times in 2.927367s 3.268215s
   rfc3501_7.2.2_LIST_response_example            51.684k     45.809k i/s
        -    150.126k times in 2.904669s 3.277229s
                  utf8_in_list_mailbox            42.525k     36.422k i/s
        -    125.166k times in 2.943368s 3.436526s
                           xlist_inbox            43.099k     39.834k i/s
        -    129.726k times in 3.009982s 3.256683s

Comparison:
             list_with_various_flag_capitalizations
                    v0.4.5-8-g4611404d:     39942.7 i/s
                                 0.4.5:     35777.0 i/s - 1.12x  slower

                rfc3501_7.2.2_LIST_response_example
                    v0.4.5-8-g4611404d:     51684.4 i/s
                                 0.4.5:     45808.8 i/s - 1.13x  slower

                               utf8_in_list_mailbox
                    v0.4.5-8-g4611404d:     42524.8 i/s
                                 0.4.5:     36422.3 i/s - 1.17x  slower

                                        xlist_inbox
                    v0.4.5-8-g4611404d:     43098.6 i/s
                                 0.4.5:     39833.8 i/s - 1.08x  slower
  • Loading branch information
nevans committed Nov 20, 2023
1 parent d3facc2 commit 8d06a25
Showing 1 changed file with 23 additions and 39 deletions.
62 changes: 23 additions & 39 deletions lib/net/imap/response_parser.rb
Original file line number Diff line number Diff line change
Expand Up @@ -198,6 +198,7 @@ module RFC3629
# ; revisions of this specification.
# flag-keyword = "$MDNSent" / "$Forwarded" / "$Junk" /
# "$NotJunk" / "$Phishing" / atom
#
# flag-perm = flag / "\*"
#
# Not checking for max one mbx-list-sflag in the parser.
Expand All @@ -220,19 +221,15 @@ module RFC3629
MBX_FLAG = FLAG_EXTENSION

# flag-list = "(" [flag *(SP flag)] ")"
#
# part of resp-text-code:
# >>>
# "PERMANENTFLAGS" SP "(" [flag-perm *(SP flag-perm)] ")"
#
# parens from mailbox-list are included in the regexp:
# >>>
# mbx-list-flags = *(mbx-list-oflag SP) mbx-list-sflag
# *(SP mbx-list-oflag) /
# mbx-list-oflag *(SP mbx-list-oflag)
FLAG_LIST = /\G\((#{FLAG }(?:#{SP}#{FLAG })*|)\)/ni
FLAG_PERM_LIST = /\G\((#{FLAG_PERM}(?:#{SP}#{FLAG_PERM})*|)\)/ni
MBX_LIST_FLAGS = /\G\((#{MBX_FLAG }(?:#{SP}#{MBX_FLAG })*|)\)/ni
# resp-text-code =/ "PERMANENTFLAGS" SP
# "(" [flag-perm *(SP flag-perm)] ")"
# mbx-list-flags = *(mbx-list-oflag SP) mbx-list-sflag
# *(SP mbx-list-oflag) /
# mbx-list-oflag *(SP mbx-list-oflag)
# (Not checking for max one mbx-list-sflag in the parser.)
FLAG_LIST = /\G\((#{FLAG }(?:#{SP}#{FLAG })*|)\)/ni
FLAG_PERM_LIST = /\G\((#{FLAG_PERM}(?:#{SP}#{FLAG_PERM})*|)\)/ni
MBX_LIST_FLAGS = /\G (#{MBX_FLAG }(?:#{SP}#{MBX_FLAG })*) /nix

# RFC3501:
# QUOTED-CHAR = <any TEXT-CHAR except quoted-specials> /
Expand Down Expand Up @@ -1350,18 +1347,17 @@ def mailbox_data__list
alias mailbox_data__lsub mailbox_data__list
alias mailbox_data__xlist mailbox_data__list

# mailbox-list = "(" [mbx-list-flags] ")" SP
# (DQUOTE QUOTED-CHAR DQUOTE / nil) SP mailbox
# [SP mbox-list-extended]
# ; This is the list information pointed to by the ABNF
# ; item "mailbox-data", which is defined above
def mailbox_list
attr = flag_list
match(T_SPACE)
token = match(T_QUOTED, T_NIL)
if token.symbol == T_NIL
delim = nil
else
delim = token.value
end
match(T_SPACE)
name = astring
return MailboxList.new(attr, delim, name)
lpar; attr = peek_rpar? ? [] : mbx_list_flags; rpar
SP!; delim = nquoted
SP!; name = mailbox
# TODO: mbox-list-extended
MailboxList.new(attr, delim, name)
end

def getquota_response
Expand Down Expand Up @@ -1941,22 +1937,10 @@ def flag_perm__list
.map! { _1.start_with?("\\") ? _1[1..].capitalize.to_sym : _1 }
end

# Not checking for max one mbx-list-sflag in the parser.
# >>>
# mbx-list-flags = *(mbx-list-oflag SP) mbx-list-sflag
# *(SP mbx-list-oflag) /
# mbx-list-oflag *(SP mbx-list-oflag)
# mbx-list-oflag = "\Noinferiors" / child-mbox-flag /
# "\Subscribed" / "\Remote" / flag-extension
# ; Other flags; multiple from this list are
# ; possible per LIST response, but each flag
# ; can only appear once per LIST response
# mbx-list-sflag = "\NonExistent" / "\Noselect" / "\Marked" /
# "\Unmarked"
# ; Selectability flags; only one per LIST response
def parens__mbx_list_flags
# See Patterns::MBX_LIST_FLAGS
def mbx_list_flags
match_re(Patterns::MBX_LIST_FLAGS, "mbx-list-flags")[1]
.split(nil).map! { _1.capitalize.to_sym }
.split(nil).map! { _1[1..].capitalize.to_sym }
end

# See https://developers.google.com/gmail/imap/imap-extensions
Expand Down

0 comments on commit 8d06a25

Please sign in to comment.