• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2017 The Libphonenumber Authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.i18n.phonenumbers.metadata.table;
17 
18 import static com.google.common.base.Preconditions.checkArgument;
19 import static com.google.common.collect.ImmutableBiMap.toImmutableBiMap;
20 import static java.util.function.Function.identity;
21 
22 import com.google.auto.value.AutoValue;
23 import com.google.common.collect.ImmutableBiMap;
24 import com.google.i18n.phonenumbers.metadata.i18n.PhoneRegion;
25 import com.google.i18n.phonenumbers.metadata.i18n.SimpleLanguageTag;
26 import java.util.Set;
27 import java.util.function.Function;
28 
29 /** A group of {@link RangeTable} columns. */
30 @AutoValue
31 public abstract class ColumnGroup<K, T extends Comparable<T>> {
32   /**
33    * Returns a group for columns with the same type as the given "prototype" column and which has a
34    * a prefix that's the name of the prototype. Suffix values are parsed using the given function.
35    */
of( Column<T> prototype, Function<String, K> parseFn)36   public static <K, T extends Comparable<T>> ColumnGroup<K, T> of(
37       Column<T> prototype, Function<String, K> parseFn) {
38     return new AutoValue_ColumnGroup<>(prototype, parseFn);
39   }
40 
41   /** Returns a group for the specified prototype column keyed by {@link PhoneRegion}. */
byRegion( Column<T> prototype)42   public static <T extends Comparable<T>> ColumnGroup<PhoneRegion, T> byRegion(
43       Column<T> prototype) {
44     return of(prototype, PhoneRegion::of);
45   }
46 
47   /** Returns a group for the specified prototype column keyed by {@link SimpleLanguageTag}. */
byLanguage( Column<T> prototype)48   public static <T extends Comparable<T>> ColumnGroup<SimpleLanguageTag, T> byLanguage(
49       Column<T> prototype) {
50     return of(prototype, SimpleLanguageTag::of);
51   }
52 
53   // Internal use only.
prototype()54   abstract Column<T> prototype();
parseFn()55   abstract Function<String, K> parseFn();
56 
57   /** Returns the column for a specified key. */
getColumn(K key)58   public Column<T> getColumn(K key) {
59     // The reason this does not just call "prototype().fromPrototype(...)" is that the key may not
60     // be parsable by the function just because it's the "right" type. This allows people to pass
61     // in a function that limits columns to some subset of the domain (e.g. a subset of region
62     // codes).
63     return getColumnFromId(key.toString());
64   }
65 
66   /** Returns the column for a specified ID string. */
getColumnFromId(String id)67   public Column<T> getColumnFromId(String id) {
68     try {
69       Object unused = parseFn().apply(id);
70     } catch (RuntimeException e) {
71       throw new IllegalArgumentException(
72           String.format("invalid column %s, not in group: %s", id, this), e);
73     }
74     return prototype().fromPrototype(id);
75   }
76 
77   /** Returns the key of a column in this group. */
78   @SuppressWarnings("unchecked")
getKey(Column<?> c)79   public K getKey(Column<?> c) {
80     checkArgument(c.isIn(this), "column %s in not group %s", c, this);
81     // Cast is safe since any column in this group is a Column<T>.
82     return extractKey((Column<T>) c);
83   }
84 
85   /** Returns a bidirectional mapping from group key to column, for columns in this group. */
86   @SuppressWarnings("unchecked")
extractGroupColumns(Set<Column<?>> columns)87   public ImmutableBiMap<K, Column<T>> extractGroupColumns(Set<Column<?>> columns) {
88     return columns.stream()
89         .filter(c -> c.isIn(this))
90         // Cast is safe since any column in this group is a Column<T>.
91         .map(c -> (Column<T>) c)
92         .collect(toImmutableBiMap(this::extractKey, identity()));
93   }
94 
95   // Assumes we've already verified that the column is in this group.
extractKey(Column<T> column)96   private K extractKey(Column<T> column) {
97     String name = column.getName();
98     return parseFn().apply(name.substring(name.lastIndexOf(':') + 1));
99   }
100 }
101