public Collection<V> values() {
   List<V> s = Generics.newArrayList();
   for (TwoDimensionalMap<K2, K3, V> innerMap : map.values()) {
     s.addAll(innerMap.values());
   }
   return s;
 }
  private boolean equals(ArrayCoreMap other) {
    TwoDimensionalMap<CoreMap, CoreMap, Boolean> calledMap = equalsCalled.get();
    boolean createdCalledMap = (calledMap == null);
    if (createdCalledMap) {
      calledMap = TwoDimensionalMap.identityHashMap();
      equalsCalled.set(calledMap);
    }

    // Note that for the purposes of recursion, we assume the two maps
    // are equals.  The two maps will therefore be equal if they
    // encounter each other again during the recursion unless there is
    // some other key that causes the equality to fail.
    // We do not need to later put false, as the entire call to equals
    // will unwind with false if any one equality check returns false.
    // TODO: since we only ever keep "true", we would rather use a
    // TwoDimensionalSet, but no such thing exists
    if (calledMap.contains(this, other)) {
      return true;
    }
    boolean result = true;
    calledMap.put(this, other, true);
    calledMap.put(other, this, true);

    if (this.size != other.size) {
      result = false;
    } else {
      for (int i = 0; i < this.size; i++) {
        // test if other contains this key,value pair
        boolean matched = false;
        for (int j = 0; j < other.size; j++) {
          if (this.keys[i] == other.keys[j]) {
            if ((this.values[i] == null && other.values[j] != null)
                || (this.values[i] != null && other.values[j] == null)) {
              matched = false;
              break;
            }

            if ((this.values[i] == null && other.values[j] == null)
                || (this.values[i].equals(other.values[j]))) {
              matched = true;
              break;
            }
          }
        }

        if (!matched) {
          result = false;
          break;
        }
      }
    }

    if (createdCalledMap) {
      equalsCalled.set(null);
    }
    return result;
  }
 public Set<K3> thirdKeySet() {
   Set<K3> keys = Generics.newHashSet();
   for (K1 k1 : map.keySet()) {
     TwoDimensionalMap<K2, K3, V> m = map.get(k1);
     for (K2 k2 : m.firstKeySet()) {
       keys.addAll(m.get(k2).keySet());
     }
   }
   return keys;
 }
 public V put(K1 key1, K2 key2, K3 key3, V value) {
   TwoDimensionalMap<K2, K3, V> m = getTwoDimensionalMap(key1);
   return m.put(key2, key3, value);
 }