package org.eclipse.jgit.lib;
import java.text.MessageFormat;
-import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collections;
-import java.util.Iterator;
-import java.util.LinkedHashMap;
-import java.util.LinkedHashSet;
import java.util.List;
-import java.util.Map;
import java.util.Set;
import java.util.concurrent.atomic.AtomicReference;
* section to search for.
* @return set of all subsections of specified section within this
* configuration and its base configuration; may be empty if no
- * subsection exists.
+ * subsection exists. The set's iterator returns sections in the
+ * order they are declared by the configuration starting from this
+ * instance and progressing through the base.
*/
public Set<String> getSubsections(final String section) {
- return get(new SubsectionNames(section));
+ return getState().getSubsections(section);
}
/**
- * @return the sections defined in this {@link Config}
+ * @return the sections defined in this {@link Config}. The set's iterator
+ * returns sections in the order they are declared by the
+ * configuration starting from this instance and progressing through
+ * the base.
*/
public Set<String> getSections() {
- return get(new SectionNames());
+ return getState().getSections();
}
/**
* @return the list of names defined for this subsection
*/
public Set<String> getNames(String section, String subsection) {
- return get(new NamesInSection(section, subsection));
+ return getState().getNames(section, subsection);
}
/**
T parse(Config cfg);
}
- private static class SubsectionNames implements SectionParser<Set<String>> {
- private final String section;
-
- SubsectionNames(final String sectionName) {
- section = sectionName;
- }
-
- public int hashCode() {
- return section.hashCode();
- }
-
- public boolean equals(Object other) {
- if (other instanceof SubsectionNames) {
- return section.equals(((SubsectionNames) other).section);
- }
- return false;
- }
-
- public Set<String> parse(Config cfg) {
- final Set<String> result = new LinkedHashSet<String>();
- while (cfg != null) {
- for (final ConfigLine e : cfg.state.get().entryList) {
- if (e.subsection != null && e.name == null
- && StringUtils.equalsIgnoreCase(section, e.section))
- result.add(e.subsection);
- }
- cfg = cfg.baseConfig;
- }
- return Collections.unmodifiableSet(result);
- }
- }
-
- private static class NamesInSection implements SectionParser<Set<String>> {
- private final String section;
-
- private final String subsection;
-
- NamesInSection(final String sectionName, final String subSectionName) {
- section = sectionName;
- subsection = subSectionName;
- }
-
- @Override
- public int hashCode() {
- final int prime = 31;
- int result = 1;
- result = prime * result + section.hashCode();
- result = prime * result
- + ((subsection == null) ? 0 : subsection.hashCode());
- return result;
- }
-
- @Override
- public boolean equals(Object obj) {
- if (this == obj)
- return true;
- if (obj == null)
- return false;
- if (getClass() != obj.getClass())
- return false;
- NamesInSection other = (NamesInSection) obj;
- if (!section.equals(other.section))
- return false;
- if (subsection == null) {
- if (other.subsection != null)
- return false;
- } else if (!subsection.equals(other.subsection))
- return false;
- return true;
- }
-
- public Set<String> parse(Config cfg) {
- final Map<String, String> m = new LinkedHashMap<String, String>();
- while (cfg != null) {
- for (final ConfigLine e : cfg.state.get().entryList) {
- if (e.name == null)
- continue;
- if (!StringUtils.equalsIgnoreCase(section, e.section))
- continue;
- if ((subsection == null && e.subsection == null)
- || (subsection != null && subsection
- .equals(e.subsection))) {
- String lc = StringUtils.toLowerCase(e.name);
- if (!m.containsKey(lc))
- m.put(lc, e.name);
- }
- }
- cfg = cfg.baseConfig;
- }
- return new CaseFoldingSet(m);
- }
- }
-
- private static class SectionNames implements SectionParser<Set<String>> {
- public Set<String> parse(Config cfg) {
- final Map<String, String> m = new LinkedHashMap<String, String>();
- while (cfg != null) {
- for (final ConfigLine e : cfg.state.get().entryList) {
- if (e.section != null) {
- String lc = StringUtils.toLowerCase(e.section);
- if (!m.containsKey(lc))
- m.put(lc, e.section);
- }
- }
- cfg = cfg.baseConfig;
- }
- return new CaseFoldingSet(m);
- }
- }
-
- private static class CaseFoldingSet extends AbstractSet<String> {
- private final Map<String, String> names;
-
- CaseFoldingSet(Map<String, String> names) {
- this.names = Collections.unmodifiableMap(names);
- }
-
- @Override
- public boolean contains(Object needle) {
- if (!(needle instanceof String))
- return false;
-
- String n = (String) needle;
- return names.containsKey(n)
- || names.containsKey(StringUtils.toLowerCase(n));
- }
-
- @Override
- public Iterator<String> iterator() {
- return names.values().iterator();
- }
-
- @Override
- public int size() {
- return names.size();
- }
- }
-
private static class StringReader {
private final char[] buf;
import static org.eclipse.jgit.util.StringUtils.compareIgnoreCase;
import static org.eclipse.jgit.util.StringUtils.compareWithCase;
+import static org.eclipse.jgit.util.StringUtils.toLowerCase;
+import java.util.AbstractSet;
import java.util.ArrayList;
import java.util.Collections;
import java.util.Comparator;
+import java.util.HashMap;
+import java.util.Iterator;
+import java.util.LinkedHashMap;
+import java.util.LinkedHashSet;
import java.util.List;
import java.util.Map;
+import java.util.Set;
import java.util.concurrent.ConcurrentHashMap;
+import org.eclipse.jgit.util.StringUtils;
+
class ConfigSnapshot {
final List<ConfigLine> entryList;
final Map<Object, Object> cache;
final ConfigSnapshot baseState;
volatile List<ConfigLine> sorted;
+ volatile SectionNames names;
ConfigSnapshot(List<ConfigLine> entries, ConfigSnapshot base) {
entryList = entries;
baseState = base;
}
+ Set<String> getSections() {
+ return names().sections;
+ }
+
+ Set<String> getSubsections(String section) {
+ Map<String, Set<String>> m = names().subsections;
+ Set<String> r = m.get(section);
+ if (r == null)
+ r = m.get(toLowerCase(section));
+ if (r == null)
+ return Collections.emptySet();
+ return Collections.unmodifiableSet(r);
+ }
+
+ Set<String> getNames(String section, String subsection) {
+ List<ConfigLine> s = sorted();
+ int idx = find(s, section, subsection, "");
+ if (idx < 0)
+ idx = -(idx + 1);
+
+ Map<String, String> m = new LinkedHashMap<String, String>();
+ while (idx < s.size()) {
+ ConfigLine e = s.get(idx++);
+ if (!e.match(section, subsection))
+ break;
+ if (e.name == null)
+ continue;
+ String l = toLowerCase(e.name);
+ if (!m.containsKey(l))
+ m.put(l, e.name);
+ }
+ return new CaseFoldingSet(m);
+ }
+
String[] get(String section, String subsection, String name) {
List<ConfigLine> s = sorted();
int idx = find(s, section, subsection, name);
b.section, b.subsection, b.name);
}
}
+
+ private SectionNames names() {
+ SectionNames n = names;
+ if (n == null)
+ names = n = new SectionNames(this);
+ return n;
+ }
+
+ private static class SectionNames {
+ final CaseFoldingSet sections;
+ final Map<String, Set<String>> subsections;
+
+ SectionNames(ConfigSnapshot cfg) {
+ Map<String, String> sec = new LinkedHashMap<String, String>();
+ Map<String, Set<String>> sub = new HashMap<String, Set<String>>();
+ while (cfg != null) {
+ for (ConfigLine e : cfg.entryList) {
+ if (e.section == null)
+ continue;
+
+ String l1 = toLowerCase(e.section);
+ if (!sec.containsKey(l1))
+ sec.put(l1, e.section);
+
+ if (e.subsection == null)
+ continue;
+
+ Set<String> m = sub.get(l1);
+ if (m == null) {
+ m = new LinkedHashSet<String>();
+ sub.put(l1, m);
+ }
+ m.add(e.subsection);
+ }
+ cfg = cfg.baseState;
+ }
+
+ sections = new CaseFoldingSet(sec);
+ subsections = sub;
+ }
+ }
+
+ private static class CaseFoldingSet extends AbstractSet<String> {
+ private final Map<String, String> names;
+
+ CaseFoldingSet(Map<String, String> names) {
+ this.names = names;
+ }
+
+ @Override
+ public boolean contains(Object needle) {
+ if (needle instanceof String) {
+ String n = (String) needle;
+ return names.containsKey(n)
+ || names.containsKey(StringUtils.toLowerCase(n));
+ }
+ return false;
+ }
+
+ @Override
+ public Iterator<String> iterator() {
+ final Iterator<String> i = names.values().iterator();
+ return new Iterator<String>() {
+ public boolean hasNext() {
+ return i.hasNext();
+ }
+
+ public String next() {
+ return i.next();
+ }
+
+ public void remove() {
+ throw new UnsupportedOperationException();
+ }
+ };
+ }
+
+ @Override
+ public int size() {
+ return names.size();
+ }
+ }
}