xref: /aosp_15_r20/external/cldr/tools/cldr-code/src/main/java/org/unicode/cldr/api/CldrData.java (revision 912701f9769bb47905792267661f0baf2b85bed5)
1 package org.unicode.cldr.api;
2 
3 import java.util.function.Consumer;
4 
5 /**
6  * An immutable, reusable CLDR data instance on which visitors can be accepted to process paths and
7  * values, or for which values can be looked up by their corresponding distinguishing path.
8  */
9 public interface CldrData {
10     /**
11      * Accepts the given visitor over all path/value pairs of this CLDR data instance. Note that
12      * value visitors only visit complete "leaf" paths which have associated values, and never see
13      * partial prefix paths.
14      *
15      * <p>Since a value visitor never sees partial path prefixes, a value visitor can never defer to
16      * a prefix visitor (since there's nothing "below" the paths that a value visitor visits).
17      *
18      * @param order the order in which visitation should occur.
19      * @param visitor the visitor to process CLDR data.
20      */
accept(PathOrder order, ValueVisitor visitor)21     void accept(PathOrder order, ValueVisitor visitor);
22 
23     /**
24      * Accepts the given visitor over all partial path prefixes of this CLDR data instance. Note
25      * that, on its own, this visitor will never see CDLR values, or even complete paths. It only
26      * sees the prefix paths under which values can exist.
27      *
28      * <p>Typically an instance of a {@link PrefixVisitor} would by used to identify a specific
29      * sub-hierarchy of data based on the prefix path, and then defer to a {@link ValueVisitor value
30      * visitor} or another {@link PrefixVisitor prefix visitor} to handle it.
31      *
32      * <p>Since {@link PrefixVisitor} requires that paths are visited in at least {@link
33      * PathOrder#NESTED_GROUPING nested grouping} order, the actual order of visitation may be more
34      * strict than the specified value.
35      *
36      * @param order the order in which visitation should occur.
37      * @param visitor the visitor to process CLDR data.
38      */
accept(PathOrder order, PrefixVisitor visitor)39     default void accept(PathOrder order, PrefixVisitor visitor) {
40         PrefixVisitorHost.accept(this::accept, order, visitor);
41     }
42 
43     /**
44      * Returns a {@link CldrValue} for a given distinguishing path.
45      *
46      * @param path the complete distinguishing path associated with a CLDR value.
47      * @return the CldrValue for the given path, if it exists, or else {@code null}.
48      */
get(CldrPath path)49     /* @Nullable */ CldrValue get(CldrPath path);
50 
51     /** Ordering options for path visitation. */
52     // TODO (CLDR-13275): Remove PathOrder and stabilize tools to use only DTD order.
53     enum PathOrder {
54         /**
55          * Visits {@code CldrPath}s in an arbitrary, potentially unstable, order. Only use this
56          * ordering if your visitation code is completely robust against changes to visitation
57          * ordering. This is expected to be the fastest ordering option, but may change over time.
58          *
59          * <p>Note that if this value is specified for a method which requires a stricter ordering
60          * for correctness, then the stricter ordering will be used. Note also that the ordering of
61          * visitation may change between visitations if a more strictly ordered visitation was
62          * required in the meantime (since paths may be re-ordered and cached).
63          */
64         ARBITRARY,
65 
66         /**
67          * Visits {@code CldrPath}s in an order which enforces the grouping of nested sub-paths.
68          * With this ordering, all common "parent" path prefixes will be visited consecutively,
69          * grouping together all "child" paths. However it is important to note that no other
70          * promises are made and this ordering is still unstable and can change over time.
71          *
72          * <p>This ordering is useful for constructing nested visitors over some subset of paths
73          * (e.g. processing all paths with a certain prefix consecutively).
74          *
75          * <p>For example, using {@code NESTED_GROUPING} the paths {@code //a/b/c/d}, {@code
76          * //a/b/e/f}, {@code //a/x/y/z} could be ordered like any of the following:
77          *
78          * <ul>
79          *   <li>{@code //a/b/c/d} &lt; {@code //a/b/e/f} &lt; {@code //a/x/y/z}
80          *   <li>{@code //a/b/e/f} &lt; {@code //a/b/c/d} &lt; {@code //a/x/y/z}
81          *   <li>{@code //a/x/y/z} &lt; {@code //a/b/c/d} &lt; {@code //a/b/e/f}
82          *   <li>{@code //a/x/y/z} &lt; {@code //a/b/e/f} &lt; {@code //a/b/c/d}
83          * </ul>
84          *
85          * The only disallowed ordering here is one in which {@code //a/x/y/z} lies between the
86          * other paths.
87          */
88         NESTED_GROUPING,
89 
90         /**
91          * Visits {@code CldrPath}s in the order defined by the CLDR DTD declaration. This ordering
92          * naturally enforces "nested grouping" of paths but additionally sorts paths so they are
93          * visited in the order defined by the DTD of the {@link CldrDataType}.
94          *
95          * <p>This ordering is more stable than {@link PathOrder#NESTED_GROUPING}, but may still
96          * change between different DTD versions.
97          */
98         DTD
99     }
100 
101     /** A visitor for complete "leaf" paths and their associated values. */
102     interface ValueVisitor {
103         /** Callback method invoked for each value encountered by this visitor. */
visit(CldrValue value)104         void visit(CldrValue value);
105     }
106 
107     /** A visitor for partial path prefixes. */
108     @SuppressWarnings("unused") // For unused arguments in no-op default methods.
109     interface PrefixVisitor {
110         /**
111          * A controller API for allow prefix visitors to delegate sub-hierarchy visitation. A
112          * context is passed into the {@link #visitPrefixStart(CldrPath, Context)} method in order
113          * to allow the visitor to "install" a new visitor to handle the sub-hierarchy root at the
114          * current path prefix.
115          */
116         interface Context {
117             /**
118              * Installs a value visitor at the current point in the visitation. The given visitor
119              * will be called for all the values below this point in the path hierarchy, and the
120              * current visitor will be automatically restored once visitation is complete.
121              *
122              * @param visitor a visitor to process the CLDR data sub-hierarchy rooted at the current
123              *     path prefix.
124              */
install(ValueVisitor visitor)125             default void install(ValueVisitor visitor) {
126                 install(visitor, v -> {});
127             }
128 
129             /**
130              * Installs a value visitor at the current point in the visitation. The given visitor
131              * will be called for all the values below this point in the path hierarchy, and the
132              * current visitor will be automatically restored once visitation is complete.
133              *
134              * @param visitor a visitor to process the CLDR data sub-hierarchy rooted at the current
135              *     path prefix.
136              * @param doneHandler a handler invoked just before the visitor is uninstalled.
137              */
install(T visitor, Consumer<T> doneHandler)138             <T extends ValueVisitor> void install(T visitor, Consumer<T> doneHandler);
139 
140             /**
141              * Installs a prefix visitor at the current point in the visitation. The given visitor
142              * will be called for all the start/end events below this point in the path hierarchy,
143              * and the current visitor will be automatically restored once visitation is complete.
144              *
145              * @param visitor a visitor to process the CLDR data sub-hierarchy rooted at the current
146              *     path prefix.
147              */
install(PrefixVisitor visitor)148             default void install(PrefixVisitor visitor) {
149                 install(visitor, v -> {});
150             }
151 
152             /**
153              * Installs a prefix visitor at the current point in the visitation. The given visitor
154              * will be called for all the start/end events below this point in the path hierarchy,
155              * and the current visitor will be automatically restored once visitation is complete.
156              *
157              * @param visitor a visitor to process the CLDR data sub-hierarchy rooted at the current
158              *     path prefix.
159              * @param doneHandler a handler invoked just before the visitor is uninstalled.
160              */
install(T visitor, Consumer<T> doneHandler)161             <T extends PrefixVisitor> void install(T visitor, Consumer<T> doneHandler);
162         }
163 
164         /**
165          * Callback method invoked for each partial path prefix encountered by this visitor.
166          *
167          * <p>A typical implementation of this method would test the given path to see if it's the
168          * root of a desired sub-hierarchy and (if it matches) begin some sub-hierarchy processing,
169          * which would often include installing a new visitor via the given context.
170          *
171          * @param prefix a path prefix processed as part of some visitation over CLDR data.
172          * @param context a mechanism for installing sub-hierarchy visitors rooted at this point in
173          *     the visitation.
174          */
visitPrefixStart(CldrPath prefix, Context context)175         default void visitPrefixStart(CldrPath prefix, Context context) {}
176 
177         /**
178          * Callback method invoked to signal the end of some sub-hierarchy visitation. This method
179          * is invoked exactly once for each call to {@link #visitPrefixStart(CldrPath, Context)}, in
180          * the opposite "stack" order with the same path prefix. This means that if this visitor
181          * installs a sub-visitor during a call to {@code visitPrefixStart()} then the next callback
182          * made to this visitor will be a call to {@code visitPrefixEnd()} with the same path
183          * prefix.
184          *
185          * <p>A typical implementation of this method would detect the end of some expected
186          * sub-visitation and do post-processing on the data.
187          *
188          * @param prefix a path prefix corresponding to the end of some previously started
189          *     sub-hierarchy visitation.
190          */
visitPrefixEnd(CldrPath prefix)191         default void visitPrefixEnd(CldrPath prefix) {}
192 
193         /**
194          * Callback method invoked for each value encountered by this visitor. This is equivalent to
195          * the {@link ValueVisitor#visit(CldrValue)} method but is not normally needed for prefix
196          * visitors (which are expected to delegate to a separate ValueVisitor). This method is
197          * useful for implementing visitors with full coverage of all paths and values in the {@link
198          * CldrData} hierarchy.
199          */
visitValue(CldrValue value)200         default void visitValue(CldrValue value) {}
201     }
202 }
203