Skip to content

Replace std::bind with lambdas in eetf/ei.hpp#2646

Merged
stephenberry merged 1 commit into
mainfrom
refactor/eetf-bind-to-lambda
Jun 18, 2026
Merged

Replace std::bind with lambdas in eetf/ei.hpp#2646
stephenberry merged 1 commit into
mainfrom
refactor/eetf-bind-to-lambda

Conversation

@stephenberry

Copy link
Copy Markdown
Owner

Summary

Replaces every std::bind call site in include/glaze/eetf/ei.hpp with an equivalent lambda. This is a pure refactor with no behavioral change.

The EETF decode/encode helpers wrapped the C ei_* functions with std::bind(ei_func, _1, _2, trailing_args...) and passed the result to detail::decode_impl / detail::encode_impl. Each is a textbook trailing-argument bind, which a lambda expresses more clearly and compiles better.

Why lambdas here

  • Inlining. std::bind returns an opaque call wrapper routed through std::invoke; compilers inline through it far less reliably than a lambda, especially in Debug. These helpers are all GLZ_ALWAYS_INLINE hot paths, so the codegen difference is real.
  • No decay-copies. std::bind decay-copies each bound argument into the wrapper; a [&] capture avoids that.
  • Clarity + a stricter signature. Drops the _1/_2 placeholders and the per-function using namespace std::placeholders;. The fixed-signature lambda also makes the ei_* call's argument list explicit and would be a compile error on a signature mismatch, where bind would silently swallow it.
  • It's the standard guidance (Effective Modern C++ Item 34, "Prefer lambdas to std::bind").

Scope

  • 23 std::bind sites converted (10 decode, 13 encode); 8 now-unused using namespace std::placeholders; lines removed.
  • The lambda parameter types follow each helper's invocation contract: decode_impl invokes the functor once as func(const char*, int*); encode_impl invokes it twice (a nullptr sizing pass then the real buffer) as func(char*, int*). The bound trailing arguments are passed through unchanged.
  • No include change: ei.hpp did not directly include <functional>.

Verification

  • Compile-checked locally (clang++ -std=c++23 -fsyntax-only -Wall -Wextra) via a harness that instantiates both the decode path (read_term) and the encode path (write_term) over a struct exercising bool / int / double / long long / unsigned long long / string / atom / vector / map (map header + encode_atom_len keys) / binary / tuple. Clean.
  • Full build + tests run in CI via the clang-linux-erlang and gcc-erlang jobs, which link against erl_interface and exercise these paths.

Every ei_* wrapper in the EETF decode/encode helpers used
std::bind(ei_func, _1, _2, trailing...) passed to decode_impl/encode_impl.
Each is a trailing-argument bind that a lambda expresses more clearly and
inlines more reliably -- these helpers are all GLZ_ALWAYS_INLINE hot paths,
and std::bind routes through an opaque std::invoke wrapper that decay-copies
its bound args.

Convert all 23 sites to lambdas and drop the now-unused
'using namespace std::placeholders;' from each function. Pure refactor, no
behavioral change: decode_impl invokes the functor once as func(const char*,
int*); encode_impl invokes it twice (nullptr sizing pass, then the real
buffer) as func(char*, int*); the bound trailing arguments are passed through
unchanged.
@stephenberry stephenberry merged commit 1684edd into main Jun 18, 2026
53 checks passed
@stephenberry stephenberry deleted the refactor/eetf-bind-to-lambda branch June 18, 2026 16:29
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.

1 participant