Extraction

Function extraction

Attaching the BRONTO_EXTRACT() attribute to a function indicates that expressions matching the function's body should be replaced with calls to the function. This is the inverse of function inlining.

BRONTO_EXTRACT()
bool Contains(auto const& container, auto const& value) {
  return container.find(value) != container.end();
}

// Before:
std::set<int> intersection(std::set<int> const& lhs, std::set<int> const& rhs) {
  std::set<int> result;
  for (auto const& elem : lhs) {
    if (rhs.find(elem) != rhs.end()) {
      result.emplace(elem);
    }
  }
  return result;
}

// After:
std::set<int> intersection(std::set<int> const& lhs, std::set<int> const& rhs) {
  std::set<int> result;
  for (auto const& elem : lhs) {
    if (Contains(rhs, elem)) {
      result.emplace(elem);
    }
  }
  return result;
}

Each function parameter represents a "hole" that can bind to any expression of the appropriate type. When an expression in the codebase structurally matches the function body (with subexpressions substituted for the parameters), it is replaced with a call to the extracted function. Each subexpression substituted for a given parameter must itself be structurally identical.

Member functions

BRONTO_EXTRACT() can also be applied to member functions. In this case, uses of this in the function body become the object expression at the call site.

struct Container {
  struct iterator { /* ... */ };

  BRONTO_EXTRACT()
  bool contains(auto const& value) const {
    return find(value) != end();
  }

  bool insert(auto const& value);
  iterator find(auto const& value) const;
  iterator end() const;
};

// Before:
Container intersection(Container const& lhs, Container const& rhs) {
  Container result;
  for (auto const& elem : lhs) {
    if (rhs.find(elem) != rhs.end()) {
      result.insert(elem);
    }
  }
  return result;
}

// After:
Container intersection(Container const& lhs, Container const& rhs) {
  Container result;
  for (auto const& elem : lhs) {
    if (rhs.contains(elem)) {
      result.insert(elem);
    }
  }
  return result;
}

Requirements

For a function to be extracted, it must

  • have a single return statement (and no other statements),
  • not be a constructor,
  • not be operator-> or any other overloaded operator, and
  • use all of its parameters in the body (unused parameters will never match).

Variadic function templates are not currently supported.

You can see an example live on Compiler Explorer.

On this page