class GenericProperties<T> extends Node {

    private static final GenericProperties<?> EMPTY = new GenericProperties<>(Map.of());

    @SuppressWarnings("unchecked")
    public static <T> GenericProperties<T> empty() {
        return (GenericProperties<T>) EMPTY;
    }

    private final Map<String, T> properties;

    public GenericProperties(Map<String, T> map) {
        this.properties = Collections.unmodifiableMap(map);
    }

    public Map<String, T> properties() {
        return properties;
    }

    public T get(String key) {
        return properties.get(key);
    }

    public boolean isEmpty() {
        return properties.isEmpty();
    }

    public <U> GenericProperties<U> map(Function<? super T, ? extends U> mapper) {
        if (isEmpty()) {
            return empty();
        }
        // The new map must support NULL values.
        Map<String, U> mappedProperties = new HashMap<>(properties.size());
        properties.forEach((key, value) -> mappedProperties.put(
            key,
            mapper.apply(value)
        ));
        return new GenericProperties<>(mappedProperties);
    }

    @Override
    public boolean equals(Object o) {<FILL_FUNCTION_BODY>}

    @Override
    public int hashCode() {
        return Objects.hash(properties);
    }

    @Override
    public String toString() {
        return properties.toString();
    }

    @Override
    public <R, C> R accept(AstVisitor<R, C> visitor, C context) {
        return visitor.visitGenericProperties(this, context);
    }

    public int size() {
        return properties.size();
    }

    public Set<String> keys() {
        return properties.keySet();
    }

    /**
     * Raises an {@link IllegalArgumentException} if the properties contain a
     * setting not contained in the given collection.
     **/
    public GenericProperties<T> ensureContainsOnly(Collection<String> supportedSettings) {
        for (String key : properties.keySet()) {
            if (!supportedSettings.contains(key)) {
                throw new IllegalArgumentException("Setting '" + key + "' is not supported");
            }
        }
        return this;
    }
}

        if (this == o) {
            return true;
        }
        if (o == null || getClass() != o.getClass()) {
            return false;
        }
        GenericProperties<?> that = (GenericProperties<?>) o;
        return Objects.equals(properties, that.properties);
    
<methods>public non-sealed void <init>() ,public R accept(AstVisitor<R,C>, C) ,public abstract boolean equals(java.lang.Object) ,public abstract int hashCode() ,public abstract java.lang.String toString() <variables>