Skip to content

perf(global): memoise pluralize()/singularize() results #4150

Closed

Description

@bpamiri

Measured on: RustCFML v0.693.0 (the CI pin), develop 0255f0d53, production mode, Apple M3 Ultra.

Problem

pluralize() / singularize() ($singularizeOrPluralize in vendor/wheels/global/strings.cfm) redo all their setup on every call:

  • rebuild the irregulars list from settings;
  • clean the uncountables list;
  • rebuild a 2D array of about 20 regex rules from a comma list;
  • try each rule with ReFindNoCase.

Results depend only on (text, which) and the inflection settings. The framework itself calls these on a small, fixed vocabulary of model, table and route names.

Measured on RustCFML, per call, median of 3 runs:

Call Cost
pluralize("item") 86 µs
singularize("products") 119 µs
A memoised struct lookup for the same result 0.20 µs

On a 50-row list page that calls pluralize once per row, the CFML sampling profiler put pluralize at 18.5% of request samples. That share comes from my test view; the per-call cost is the general number.

Not measured yet: Lucee, Adobe, BoxLang.

Proposal

  • Memoise results in an application-scoped cache keyed by which|text. Cache the uninflected result, and apply count / returnCount formatting after the lookup.
  • Clear the cache whenever uncountables or irregulars change via set(), and on reload.
  • Optionally build the rule array once instead of per call.
  • Bound the cache size (or cache only when the text is short) so user-supplied text can't grow it without limit.

Acceptance

  • Existing inflection specs pass unchanged on all engines.
  • New specs: a cache hit returns the same value; changing irregulars / uncountables invalidates the cache; the cache stays bounded.
  • Before/after per-call timing posted on the PR.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    performancePerformance work (profiling, hot-path optimization)

    Type

    No type

    Projects

    No projects

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions