private static List <EquivalenceClass> ComputeIgnoreCaseEquivalenceClasses(CharSetSolver solver, CultureInfo culture) { var ignoreCase = new Dictionary <char, EquivalenceClass>(); var sets = new List <EquivalenceClass>(); for (uint i = 65; i <= 0xFFFF; i++) { char C = (char)i; char c = char.ToLower(C, culture); if (c == C) { continue; } EquivalenceClass?ec; if (!ignoreCase.TryGetValue(c, out ec)) { ec = new EquivalenceClass(solver.CharConstraint(c)); ignoreCase[c] = ec; sets.Add(ec); } ec._set = solver.Or(ec._set, solver.CharConstraint(C)); } return(sets); }
/// <summary> /// Get the set of CI-equivalent characters to c. /// This operation depends on culture for i, I, '\u0130', and '\u0131'; /// culture="" means InvariantCulture while culture=null means to use the current culture. /// </summary> public BDD Apply(char c, string?culture = null) { if (Volatile.Read(ref _cultureIndependentChars[c]) is BDD bdd) { return(bdd); } culture ??= CultureInfo.CurrentCulture.Name; switch (c) { // Do not cache in _cultureIndependentChars values that are culture-dependent case 'i': return (culture == string.Empty ? _i_Invariant : IsTurkishAlphabet(culture) ? _i_Turkish : _i_Default); // for all other cultures, case-sensitivity is the same as for en-US case 'I': return (culture == string.Empty ? _i_Invariant : IsTurkishAlphabet(culture) ? _I_Turkish : // different from 'i' above _i_Default); case Turkish_I_WithDot: return (culture == string.Empty ? _solver.CharConstraint(Turkish_I_WithDot) : IsTurkishAlphabet(culture) ? _i_Turkish : _i_Default); case Turkish_i_WithoutDot: return (IsTurkishAlphabet(culture) ? _I_Turkish : _solver.CharConstraint(Turkish_i_WithoutDot)); case 'k': case 'K': case KelvinSign: Volatile.Write(ref _cultureIndependentChars[c], _solver.Or(_solver.Or(_solver.CharConstraint('k'), _solver.CharConstraint('K')), _solver.CharConstraint(KelvinSign))); return(_cultureIndependentChars[c] !); // Cache in _cultureIndependentChars entries that are culture-independent. // BDDs are idempotent, so while we use volatile to ensure proper adherence // to ECMA's memory model, we don't need Interlocked.CompareExchange. case <= '\x7F': // For ASCII range other than letters i, I, k, and K, the case-conversion is independent of culture and does // not include case-insensitive-equivalent non-ASCII. Volatile.Write(ref _cultureIndependentChars[c], _solver.Or(_solver.CharConstraint(char.ToLower(c)), _solver.CharConstraint(char.ToUpper(c)))); return(_cultureIndependentChars[c] !); default: // Bring in the full transfomation relation, but here it does not actually depend on culture // so it is safe to store the result for c. Volatile.Write(ref _cultureIndependentChars[c], Apply(_solver.CharConstraint(c))); return(_cultureIndependentChars[c] !); } }
public IgnoreCaseTransformer(CharSetSolver solver) { _solver = solver; _i_Invariant = solver.Or(_solver.CharConstraint('i'), solver.CharConstraint('I')); _i_Default = solver.Or(_i_Invariant, solver.CharConstraint(Turkish_I_WithDot)); _i_Turkish = solver.Or(solver.CharConstraint('i'), solver.CharConstraint(Turkish_I_WithDot)); _I_Turkish = solver.Or(solver.CharConstraint('I'), solver.CharConstraint(Turkish_i_WithoutDot)); }