Skip to content

Optimise <- in among #227

@ojwb

Description

@ojwb

It's pretty common for an among action to simply be <- followed by a literal string. For amongs with many such cases we could use among_var to lookup in an array of strings rather than dispatching to multiple explicit calls to slice_from with different arguments.

That's probably not going to make a huge difference for languages with an optimising compiler (like C), but for Python we generate an if chain and this may be a significant win.

Currently we generate:

    def __r_exception1(self):
        self.bra = self.cursor
        among_var = self.find_among(EnglishStemmer.a_10)
        if among_var == 0:
            return False
        self.ket = self.cursor
        if self.cursor < self.limit:
            return False
        if among_var == 1:
            if not self.slice_from(u"sky"):
                return False
        elif among_var == 2:
            if not self.slice_from(u"die"):
                return False
        elif among_var == 3:
            if not self.slice_from(u"lie"):
                return False
        elif among_var == 4:
            if not self.slice_from(u"tie"):
                return False
        elif among_var == 5:
            if not self.slice_from(u"idl"):
                return False
        elif among_var == 6:
            if not self.slice_from(u"gentl"):
                return False
        elif among_var == 7:
            if not self.slice_from(u"ugli"):
                return False
        elif among_var == 8:
            if not self.slice_from(u"earli"):
                return False
        elif among_var == 9:
            if not self.slice_from(u"onli"):
                return False
        elif among_var == 10:
            if not self.slice_from(u"singl"):
                return False
        return True


We could instead generate:

    as_10 = (u"sky", u"die", u"lie", u"tie", u"idl", u"gentl", u"ugli", u"earli", u"onli", u"singl")

    def __r_exception1(self):
        self.bra = self.cursor
        among_var = self.find_among(EnglishStemmer.a_10)
        if among_var == 0:
            return False
        self.ket = self.cursor
        if self.cursor < self.limit:
            return False
        if among_var > 0:
            if not self.slice_from(EnglishStemmer.as_10[among_var - 1]):
                return False
        return True

We can do this even when there are other types of among action by partitioning the allocated among_var values - e.g. 0 for failure, positive for a slice_from index, -1 for null action, other negative values for dispatch to custom action code (using a if-chain for Python like we currently do, but it'll be a shorter if-chain because there's only one if for all the <- actions).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions