class UdfIndex {

  void addFunction(final T function) {
    final List<ParamType> parameters = function.parameters();
    if (allFunctions.put(parameters, function) != null) {
      throw new KsqlFunctionException(
          "Can't add function " + function.name()
              + " with parameters " + function.parameters()
              + " as a function with the same name and parameter types already exists "
              + allFunctions.get(parameters)
      );
    }

    final int order = allFunctions.size();

    Node curr = root;
    Node parent = curr;
    for (final ParamType parameter : parameters) {
      final Parameter param = new Parameter(parameter, false);
      parent = curr;
      curr = curr.children.computeIfAbsent(param, ignored -> new Node());
    }

    if (function.isVariadic()) {
      // first add the function to the parent to address the
      // case of empty varargs
      parent.update(function, order);

      // then add a new child node with the parameter value type
      // and add this function to that node
      final ParamType varargSchema = Iterables.getLast(parameters);
      final Parameter vararg = new Parameter(varargSchema, true);
      final Node leaf = parent.children.computeIfAbsent(vararg, ignored -> new Node());
      leaf.update(function, order);

      // add a self referential loop for varargs so that we can
      // add as many of the same param at the end and still retrieve
      // this node
      leaf.children.putIfAbsent(vararg, leaf);
    }

    curr.update(function, order);
  }

    UdfIndex(final String udfName, final boolean supportsImplicitCasts);

}