class TupleDomain {

    public <U> TupleDomain<U> transform(Function<T, U> function)
    {
        if (isNone()) {
            return none();
        }
        if (isAll()) {
            return all();
        }

        Map<T, Domain> domains = this.domains.orElseThrow();
        HashMap<U, Domain> result = new LinkedHashMap<>(domains.size());
        for (Map.Entry<T, Domain> entry : domains.entrySet()) {
            U key = function.apply(entry.getKey());

            if (key == null) {
                continue;
            }

            Domain previous = result.put(key, entry.getValue());

            if (previous != null) {
                throw new IllegalArgumentException(format("Every argument must have a unique mapping. %s maps to %s and %s", entry.getKey(), entry.getValue(), previous));
            }
        }

        return TupleDomain.withColumnDomains(result);
    }

    private  TupleDomain(Optional<Map<T, Domain>> domains);

}