001 /* 002 * Copyright (C) 2008 Google Inc. 003 * 004 * Licensed under the Apache License, Version 2.0 (the "License"); 005 * you may not use this file except in compliance with the License. 006 * You may obtain a copy of the License at 007 * 008 * http://www.apache.org/licenses/LICENSE-2.0 009 * 010 * Unless required by applicable law or agreed to in writing, software 011 * distributed under the License is distributed on an "AS IS" BASIS, 012 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 013 * See the License for the specific language governing permissions and 014 * limitations under the License. 015 */ 016 017 package com.google.common.collect; 018 019 import static com.google.common.base.Preconditions.checkNotNull; 020 021 import com.google.common.annotations.Beta; 022 import com.google.common.annotations.GwtCompatible; 023 import com.google.common.base.Supplier; 024 025 import java.io.Serializable; 026 import java.util.Comparator; 027 import java.util.Map; 028 import java.util.Set; 029 import java.util.SortedMap; 030 import java.util.SortedSet; 031 import java.util.TreeMap; 032 033 import javax.annotation.Nullable; 034 035 /** 036 * Implementation of {@code Table} whose row keys and column keys are ordered 037 * by their natural ordering or by supplied comparators. When constructing a 038 * {@code TreeBasedTable}, you may provide comparators for the row keys and 039 * the column keys, or you may use natural ordering for both. 040 * 041 * <p>The {@link #rowKeySet} method returns a {@link SortedSet} and the {@link 042 * #rowMap} method returns a {@link SortedMap}, instead of the {@link Set} and 043 * {@link Map} specified by the {@link Table} interface. 044 * 045 * <p>Note that the column keys as returned by {@link #columnKeySet()} and 046 * {@link #columnMap()} are <i>not</i> sorted. Sorted column keys can be 047 * observed in {@link Table#row(Object)} and the values of {@link #rowMap()}. 048 * 049 * <p>The views returned by {@link #column}, {@link #columnKeySet()}, and {@link 050 * #columnMap()} have iterators that don't support {@code remove()}. Otherwise, 051 * all optional operations are supported. Null row keys, columns keys, and 052 * values are not supported. 053 * 054 * <p>Lookups by row key are often faster than lookups by column key, because 055 * the data is stored in a {@code Map<R, Map<C, V>>}. A method call like {@code 056 * column(columnKey).get(rowKey)} still runs quickly, since the row key is 057 * provided. However, {@code column(columnKey).size()} takes longer, since an 058 * iteration across all row keys occurs. 059 * 060 * <p>Note that this implementation is not synchronized. If multiple threads 061 * access this table concurrently and one of the threads modifies the table, it 062 * must be synchronized externally. 063 * 064 * @author Jared Levy 065 * @since 7 066 */ 067 @GwtCompatible(serializable = true) 068 @Beta 069 public class TreeBasedTable<R, C, V> extends StandardRowSortedTable<R, C, V> { 070 private final Comparator<? super C> columnComparator; 071 072 private static class Factory<C, V> 073 implements Supplier<TreeMap<C, V>>, Serializable { 074 final Comparator<? super C> comparator; 075 Factory(Comparator<? super C> comparator) { 076 this.comparator = comparator; 077 } 078 public TreeMap<C, V> get() { 079 return new TreeMap<C, V>(comparator); 080 } 081 private static final long serialVersionUID = 0; 082 } 083 084 /** 085 * Creates an empty {@code TreeBasedTable} that uses the natural orderings 086 * of both row and column keys. 087 * 088 * <p>The method signature specifies {@code R extends Comparable} with a raw 089 * {@link Comparable}, instead of {@code R extends Comparable<? super R>}, 090 * and the same for {@code C}. That's necessary to support classes defined 091 * without generics. 092 */ 093 @SuppressWarnings("unchecked") // eclipse doesn't like the raw Comparable 094 public static <R extends Comparable, C extends Comparable, V> 095 TreeBasedTable<R, C, V> create() { 096 return new TreeBasedTable<R, C, V>(Ordering.natural(), 097 Ordering.natural()); 098 } 099 100 /** 101 * Creates an empty {@code TreeBasedTable} that is ordered by the specified 102 * comparators. 103 * 104 * @param rowComparator the comparator that orders the row keys 105 * @param columnComparator the comparator that orders the column keys 106 */ 107 public static <R, C, V> TreeBasedTable<R, C, V> create( 108 Comparator<? super R> rowComparator, 109 Comparator<? super C> columnComparator) { 110 checkNotNull(rowComparator); 111 checkNotNull(columnComparator); 112 return new TreeBasedTable<R, C, V>(rowComparator, columnComparator); 113 } 114 115 /** 116 * Creates a {@code TreeBasedTable} with the same mappings and sort order 117 * as the specified {@code TreeBasedTable}. 118 */ 119 public static <R, C, V> TreeBasedTable<R, C, V> create( 120 TreeBasedTable<R, C, ? extends V> table) { 121 TreeBasedTable<R, C, V> result 122 = new TreeBasedTable<R, C, V>( 123 table.rowComparator(), table.columnComparator()); 124 result.putAll(table); 125 return result; 126 } 127 128 TreeBasedTable(Comparator<? super R> rowComparator, 129 Comparator<? super C> columnComparator) { 130 super(new TreeMap<R, Map<C, V>>(rowComparator), 131 new Factory<C, V>(columnComparator)); 132 this.columnComparator = columnComparator; 133 } 134 135 // TODO(jlevy): Move to StandardRowSortedTable? 136 137 /** 138 * Returns the comparator that orders the rows. With natural ordering, 139 * {@link Ordering#natural()} is returned. 140 */ 141 public Comparator<? super R> rowComparator() { 142 return rowKeySet().comparator(); 143 } 144 145 /** 146 * Returns the comparator that orders the columns. With natural ordering, 147 * {@link Ordering#natural()} is returned. 148 */ 149 public Comparator<? super C> columnComparator() { 150 return columnComparator; 151 } 152 153 // rowKeySet() and rowMap() are defined here so they appear in the Javadoc. 154 155 @Override public SortedSet<R> rowKeySet() { 156 return super.rowKeySet(); 157 } 158 159 @Override public SortedMap<R, Map<C, V>> rowMap() { 160 return super.rowMap(); 161 } 162 163 // Overriding so NullPointerTester test passes. 164 165 @Override public boolean contains( 166 @Nullable Object rowKey, @Nullable Object columnKey) { 167 return super.contains(rowKey, columnKey); 168 } 169 170 @Override public boolean containsColumn(@Nullable Object columnKey) { 171 return super.containsColumn(columnKey); 172 } 173 174 @Override public boolean containsRow(@Nullable Object rowKey) { 175 return super.containsRow(rowKey); 176 } 177 178 @Override public boolean containsValue(@Nullable Object value) { 179 return super.containsValue(value); 180 } 181 182 @Override public V get(@Nullable Object rowKey, @Nullable Object columnKey) { 183 return super.get(rowKey, columnKey); 184 } 185 186 @Override public boolean equals(@Nullable Object obj) { 187 return super.equals(obj); 188 } 189 190 @Override public V remove( 191 @Nullable Object rowKey, @Nullable Object columnKey) { 192 return super.remove(rowKey, columnKey); 193 } 194 195 private static final long serialVersionUID = 0; 196 }