All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.owasp.html.Joinable Maven / Gradle / Ivy

There is a newer version: 20240325.1
Show newest version
package org.owasp.html;

import java.util.Iterator;
import java.util.LinkedHashSet;
import java.util.Map;
import java.util.Set;

import com.google.common.base.Optional;
import com.google.common.base.Preconditions;
import com.google.common.collect.Maps;
import com.google.common.collect.Sets;

/**
 * Something that can request special joining.
 * If two or more things have the same (per equals/hashCode) joinStrategy
 * then they will be grouped together for joining according to that strategy.
 */
interface Joinable {
  Joinable.JoinStrategy getJoinStrategy();

  /**
   * An n-ary function from T to a joined T.
   */
  interface JoinStrategy {
    /** Joins toJoin into a single T. */
    T join(Iterable toJoin);

    /**
     * Must be hashable so that special joinables can be grouped by strategy.
     */
    boolean equals(Object o);

    /**
     * Must be hashable so that special joinables can be grouped by strategy.
     */
    int hashCode();
  }



  static abstract class JoinHelper> {

    final Class baseType;
    final Class specialJoinableType;
    final T zeroValue;
    final T identityValue;
    private Map, Set> requireSpecialJoining;
    private Set uniq = new LinkedHashSet();

    JoinHelper(
        Class baseType,
        Class specialJoinableType,
        T zeroValue,
        T identityValue) {
      this.baseType = baseType;
      this.specialJoinableType = specialJoinableType;
      this.zeroValue = Preconditions.checkNotNull(zeroValue);
      this.identityValue = Preconditions.checkNotNull(identityValue);
    }

    abstract Optional> split(T x);

    abstract T rejoin(Set xs);

    void unroll(T x) {
      Optional> splitX = split(x);
      if (splitX.isPresent()) {
        for (T part : splitX.get()) {
          unroll(part);
        }
      } else if (specialJoinableType.isInstance(x)) {
        // We shouldn't implement special joinable for AttributePolicies
        // without implementing the properly parameterized variant.
        SJ sj = specialJoinableType.cast(x);

        JoinStrategy strategy = sj.getJoinStrategy();

        if (requireSpecialJoining == null) {
          requireSpecialJoining = Maps.newLinkedHashMap();
        }
        Set toJoinTogether = requireSpecialJoining.get(strategy);
        if (toJoinTogether == null) {
          toJoinTogether = Sets.newLinkedHashSet();
          requireSpecialJoining.put(strategy, toJoinTogether);
        }

        toJoinTogether.add(sj);
      } else {
        uniq.add(Preconditions.checkNotNull(x));
      }
    }

    T join() {
      if (uniq.contains(zeroValue)) {
        return zeroValue;
      }

      if (requireSpecialJoining != null) {
        Iterator, Set>> entryIterator
            = requireSpecialJoining.entrySet().iterator();
        while (entryIterator.hasNext()) {
          Map.Entry, Set> e
              = entryIterator.next();

          JoinStrategy strategy = e.getKey();
          Set toJoin = e.getValue();

          entryIterator.remove();

          SJ joined = toJoin.size() == 1
              ? toJoin.iterator().next()
              : strategy.join(toJoin);

          uniq.add(Preconditions.checkNotNull(baseType.cast(joined)));
        }
      }

      uniq.remove(identityValue);

      switch (uniq.size()) {
        case 0:  return identityValue;
        case 1:  return uniq.iterator().next();
        default: return rejoin(uniq);
      }
    }
  }

}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy