Skip to content

Pre-size valdi_core bridge dictionaries and maps#114

Open
ultramiraculous wants to merge 2 commits into
Snapchat:mainfrom
ultramiraculous:um/dict-sizing
Open

Pre-size valdi_core bridge dictionaries and maps#114
ultramiraculous wants to merge 2 commits into
Snapchat:mainfrom
ultramiraculous:um/dict-sizing

Conversation

@ultramiraculous

@ultramiraculous ultramiraculous commented Jul 10, 2026

Copy link
Copy Markdown

[iOS] Pre-size valdi_core bridge dictionaries and maps

Description

We ran into a workload that pushes a large number of small dictionaries (4-8 keys each) through the validi bridge. The bridge builds its dictionaries/maps with no capacity hint, so each one starts at the minimum size and grows as it fills — at 4-8 keys that's multiple resize boundaries crossed per item, each one a rehash/realloc plus a free of the smaller backing buffer. Multiply by the number of items and we're churning a lotttt of transient memory for dictionaries whose final size we already know up front.

The array bridging cases elsewhere in this file already do pre-allocation, so it makes sense to mirror that, I think.

  • JS -> ObjC (NSObjectFromValue): build the Map and TypedObject NSMutableDictionary with dictionaryWithCapacity: (map size / property count), matching the Array case right below it.
  • ObjC -> JS (ValueFromNSDictionary): reserve(dict.count) on the ValueMap before the insert loop, matching the typed and array paths.

There's also obviously some bigger optimization options but this one stood out as a good "starter bug" candidate.

Type of Change

  • Bug fix (non-breaking change that fixes an issue)
  • Documentation improvement
  • Performance optimization
  • Test improvement
  • Other (please describe)

Testing

  • Tests pass locally (bazel test //...)
  • Added/updated tests for changes (if applicable)
  • Tested on multiple platforms (iOS/Android/Web/macOS as applicable)
  • Manual testing performed (describe below)

Testing Details

Covered by the existing test suite (valdi/test/ios/SCValdiMarshallerTests.m) — testCanMarshallMap / testCanUnmarshallMap round-trip an untyped NSDictionary through both changed functions (ValueFromNSDictionary and NSObjectFromValue's map case). No new tests since only the initial capacity changes, not the contents or ordering.

Ran bazel test //... locally: 63/72 targets pass, including everything this change compiles into (//valdi:valdi_ios_objc_test, valdi_ios_swift_test, valdi_macos_objc_test). The 7 that fail (e.g. //valdi:test_java, //libs/dummy:test) fail identically on a clean main checkout, so that's pre-existing local breakage rather than anything from this change.

Checklist

  • Code follows project style guidelines
  • Documentation updated (if needed)
  • No breaking changes (or documented in description)
  • Commit messages follow conventional format
  • No secrets, API keys, or internal URLs included

Related Issues

Additional Context

@github-actions github-actions Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🎉 Thanks for your first contribution to Valdi!

A maintainer will review your PR soon. Here are a few things to check while you wait:

  • ✅ All tests pass (bazel test //...)
  • ✅ Your changes follow our coding standards
  • ✅ You've added tests for your changes (if applicable)
  • ✅ You've updated documentation (if needed)

Join our Discord community if you have questions!

@clholgat clholgat left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This looks good, thanks for PR!

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants