public void TestSmallDict() { var ht = new SmallDictionary<int, int>(); const int elements = 150; for (int i = 0; i < elements; i += 10) { ht.Add(i, i); ht.AssertBalanced(); ht.Add(i - 2, i - 2); ht.AssertBalanced(); ht.Add(i - 3, i - 3); ht.AssertBalanced(); ht.Add(i - 4, i - 4); ht.AssertBalanced(); ht.Add(i - 6, i - 6); ht.AssertBalanced(); ht.Add(i - 5, i - 5); ht.AssertBalanced(); ht.Add(i - 1, i - 1); ht.AssertBalanced(); ht.Add(i - 7, i - 7); ht.AssertBalanced(); ht.Add(i - 8, i - 8); ht.AssertBalanced(); ht.Add(i - 9, i - 9); ht.AssertBalanced(); } Assert.Equal(150, ht.Count()); for (int i = 0; i < elements; i += 10) { Assert.Equal(ht[i], i); Assert.Equal(ht[i - 2], i - 2); Assert.Equal(ht[i - 3], i - 3); Assert.Equal(ht[i - 4], i - 4); Assert.Equal(ht[i - 6], i - 6); Assert.Equal(ht[i - 5], i - 5); Assert.Equal(ht[i - 1], i - 1); Assert.Equal(ht[i - 7], i - 7); Assert.Equal(ht[i - 8], i - 8); Assert.Equal(ht[i - 9], i - 9); } foreach (var p in ht) { Assert.Equal(p.Key, p.Value); } var keys = ht.Keys.ToArray(); var values = ht.Values.ToArray(); for (int i = 0, l = ht.Count(); i < l; i++) { Assert.Equal(keys[i], values[i]); } }
public void SmallDictionaryAlwaysBalanced() { var sd = new SmallDictionary<int, string>(); sd.Add(1, "1"); sd.AssertBalanced(); sd.Add(10, "1"); sd.AssertBalanced(); sd.Add(2, "1"); sd.AssertBalanced(); sd.Add(1000, "1"); sd.AssertBalanced(); sd.Add(-123, "1"); sd.AssertBalanced(); sd.Add(0, "1"); sd.AssertBalanced(); sd.Add(4, "1"); sd.AssertBalanced(); sd.Add(5, "1"); sd.AssertBalanced(); sd.Add(6, "1"); sd.AssertBalanced(); }
public void SmallDictionaryAlwaysBalanced() { var sd = new SmallDictionary <int, string>(); sd.Add(1, "1"); sd.AssertBalanced(); sd.Add(10, "1"); sd.AssertBalanced(); sd.Add(2, "1"); sd.AssertBalanced(); sd.Add(1000, "1"); sd.AssertBalanced(); sd.Add(-123, "1"); sd.AssertBalanced(); sd.Add(0, "1"); sd.AssertBalanced(); sd.Add(4, "1"); sd.AssertBalanced(); sd.Add(5, "1"); sd.AssertBalanced(); sd.Add(6, "1"); sd.AssertBalanced(); }
/// <summary> /// Adds a mapping to this unification, creating a new unification. /// </summary> /// <param name="key"> /// The key of the mapping to add. /// </param> /// <param name="value"> /// The value of the mapping to add. /// </param> /// <returns> /// The result of adding, which will ignore this mapping if there is /// already a present mapping for <paramref name="key"/>. /// </returns> internal ImmutableTypeMap Add(TypeParameterSymbol key, TypeWithModifiers value) { var sd = new SmallDictionary <TypeParameterSymbol, TypeWithModifiers>(); sd.Add(key, value); return(ComposeDict(sd)); }
public WithLambdaParametersBinder(LambdaSymbol lambdaSymbol, Binder enclosing) : base(enclosing) { this.lambdaSymbol = lambdaSymbol; this.parameterMap = new MultiDictionary <string, ParameterSymbol>(); var parameters = lambdaSymbol.Parameters; if (!parameters.IsDefaultOrEmpty) { _definitionMap = new SmallDictionary <string, ParameterSymbol>(); foreach (var parameter in parameters) { if (!parameter.IsDiscard) { var name = parameter.Name; this.parameterMap.Add(name, parameter); if (!_definitionMap.ContainsKey(name)) { _definitionMap.Add(name, parameter); } } } } }
/// <summary> /// Sequentially composes this map with another one, then filters out /// the set of additions to the map using the given allowed set. /// </summary> /// <param name="other">The RHS of the sequential composition.</param> /// <param name="allowed">The array of allowed type parameters.</param> /// <returns> /// The composed map, with the present keys restricted to those either /// in this map or in <paramref name="allowed"/>. /// </returns> public ImmutableTypeMap RestrictedCompose(ImmutableTypeMap other, ImmutableArray <TypeParameterSymbol> allowed) { // Don't return 'other' if we're empty. // 'other' might need restricting. if (other.IsEmpty) { return(this); } // TODO(MattWindsor91): efficiency: we're creating and disposing // of a lot of intermediate data structures here. var unfiltered = Compose(other); var rdict = new SmallDictionary <TypeParameterSymbol, TypeWithModifiers>(); // De-duplicating this is important: SmallDictionary errors // on duplicate key insertion. var allAllowed = allowed.AddRange(Mapping.Keys).Distinct(); foreach (var a in allAllowed) { if (unfiltered.Mapping.ContainsKey(a)) { rdict.Add(a, unfiltered.Mapping[a]); } } return(new ImmutableTypeMap(rdict)); }
/// <summary> /// Synthesizes the correct receiver of a witness invocation. /// </summary> /// <param name="syntax">The syntax to be attached to the node.</param> /// <param name="witness">The witness we are calling into.</param> /// <returns> /// The appropriate receiver for this witness. /// If we're in a block, this will be a local variable; /// otherwise, this will be a <c>default()</c>. /// </returns> private BoundExpression SynthesizeWitnessReceiver(SyntaxNode syntax, TypeSymbol witness) { Debug.Assert(syntax != null, "Syntax for witness receiver should not be null"); Debug.Assert(witness != null, "Witness receiver should not be null"); Debug.Assert(witness.IsInstanceType() || witness.IsConceptWitness, "Witness receiver should be a valid witness"); // If we're not in a block, we can't synthesise a local if (_rootStatement.Kind != BoundKind.Block) { return(new BoundDefaultExpression(syntax, witness) { WasCompilerGenerated = true }); } // TODO(@MattWindsor91): this is probably inefficient if (_conceptWitnessesToHoist == null) { _conceptWitnessesToHoist = new SmallDictionary <TypeSymbol, LocalSymbol>(); } if (!_conceptWitnessesToHoist.ContainsKey(witness)) { _conceptWitnessesToHoist.Add(witness, WitnessDictionaryLocal(witness, syntax)); } var local = _conceptWitnessesToHoist[witness]; return(new BoundLocal(syntax, local, null, witness) { WasCompilerGenerated = true }); }
public void TestSmallDict() { var ht = new SmallDictionary<int, int>(); const int elements = 150; for (int i = 0; i < elements; i += 4) { ht.Add(i, i); ht.Add(i - 1, i - 1); ht.Add(i - 2, i - 2); ht.Add(i - 3, i - 3); } Assert.Equal(152, ht.Count()); for (int j = 0; j < 100; j++) { for (int i = 0; i < elements; i += 4) { int v; ht.TryGetValue(i, out v); Assert.Equal(i, v); ht.TryGetValue(i - 1, out v); Assert.Equal(i - 1, v); ht.TryGetValue(i - 2, out v); Assert.Equal(i - 2, v); ht.TryGetValue(i - 3, out v); Assert.Equal(i - 3, v); } } foreach(var p in ht) { Assert.Equal(p.Key, p.Value); } var keys = ht.Keys.ToArray(); var values = ht.Values.ToArray(); for (int i = 0, l = ht.Count(); i < l; i++) { Assert.Equal(keys[i], values[i]); } }
public void TestSmallDict() { var ht = new SmallDictionary <int, int>(); const int elements = 150; for (int i = 0; i < elements; i += 4) { ht.Add(i, i); ht.Add(i - 1, i - 1); ht.Add(i - 2, i - 2); ht.Add(i - 3, i - 3); } Assert.Equal(152, ht.Count()); for (int j = 0; j < 100; j++) { for (int i = 0; i < elements; i += 4) { int v; ht.TryGetValue(i, out v); Assert.Equal(i, v); ht.TryGetValue(i - 1, out v); Assert.Equal(i - 1, v); ht.TryGetValue(i - 2, out v); Assert.Equal(i - 2, v); ht.TryGetValue(i - 3, out v); Assert.Equal(i - 3, v); } } foreach (var p in ht) { Assert.Equal(p.Key, p.Value); } var keys = ht.Keys.ToArray(); var values = ht.Values.ToArray(); for (int i = 0, l = ht.Count(); i < l; i++) { Assert.Equal(keys[i], values[i]); } }
private static void RecordDefinition <T>(SmallDictionary <string, Symbol> declarationMap, ImmutableArray <T> definitions) where T : Symbol { foreach (Symbol s in definitions) { if (!declarationMap.ContainsKey(s.Name)) { declarationMap.Add(s.Name, s); } } }
public override void InitializeTupleFieldDefinitionsToIndexMap() { Debug.Assert(this.IsTupleType); Debug.Assert(this.IsDefinition); // we only store a map for definitions var retargetedMap = new SmallDictionary <FieldSymbol, int>(ReferenceEqualityComparer.Instance); foreach ((FieldSymbol field, int index) in _underlyingType.TupleFieldDefinitionsToIndexMap) { retargetedMap.Add(this.RetargetingTranslator.Retarget(field), index); } this.TupleData !.SetFieldDefinitionsToIndexMap(retargetedMap); }
private void DeclareLocals <TSymbol>(Scope scope, ImmutableArray <TSymbol> locals, bool declareAsFree = false) where TSymbol : Symbol { foreach (var local in locals) { Debug.Assert(!_localToScope.ContainsKey(local)); if (declareAsFree) { #if DEBUG Debug.Assert(_freeVariables.Add(local)); #endif } else { _localToScope.Add(local, scope); } } }
private static SmallDictionary <TypeParameterSymbol, TypeSymbolWithAnnotations> ConstructMapping(ImmutableArray <TypeParameterSymbol> from, ImmutableArray <TypeSymbolWithAnnotations> to) { var mapping = new SmallDictionary <TypeParameterSymbol, TypeSymbolWithAnnotations>(ReferenceEqualityComparer.Instance); Debug.Assert(from.Length == to.Length); for (int i = 0; i < from.Length; i++) { TypeParameterSymbol tp = from[i]; TypeSymbolWithAnnotations ta = to[i]; if (!ta.Is(tp)) { mapping.Add(tp, ta); } } return(mapping); }
/// <summary> /// Given a meaning, ensure that it is the only meaning within this scope (or report a diagnostic that it isn't). /// Returns true if a diagnostic was reported. Sets done=true if there is no need to check further enclosing /// scopes (for example, when this meaning is the same as a previous meaning, or it can be determined that a /// diagnostic had previously been reported). /// </summary> private bool EnsureSingleDefinition(SingleMeaning newMeaning, DiagnosticBag diagnostics, ref bool done) { if (singleMeaningTable == null) { Interlocked.CompareExchange(ref singleMeaningTable, new SmallDictionary <string, SingleMeaning>(), null); } lock (singleMeaningTable) { SingleMeaning oldMeaning; if (singleMeaningTable.TryGetValue(newMeaning.Name, out oldMeaning)) { if (oldMeaning.Direct) { return(ResolveConflict(oldMeaning, newMeaning, diagnostics, ref done)); } else { if (newMeaning.Direct) { singleMeaningTable[newMeaning.Name] = newMeaning; return(ResolveConflict(oldMeaning, newMeaning, diagnostics, ref done)); } else { // both indirect if ((object)oldMeaning.Symbol != null && newMeaning.Symbol == oldMeaning.Symbol && !newMeaning.IsDefinition) { done = true; // optimization } return(false); } } } else { singleMeaningTable.Add(newMeaning.Name, newMeaning); return(false); } } }
/// <summary> /// Report an error if adding the edge (method1, method2) to the ctor-initializer /// graph would add a new cycle to that graph. /// </summary> /// <param name="method1">a calling ctor</param> /// <param name="method2">the chained-to ctor</param> /// <param name="syntax">where to report a cyclic error if needed</param> /// <param name="diagnostics">a diagnostic bag for receiving the diagnostic</param> internal void ReportCtorInitializerCycles(MethodSymbol method1, MethodSymbol method2, CSharpSyntaxNode syntax, DiagnosticBag diagnostics) { // precondition and postcondition: the graph _constructorInitializers is acyclic. // If adding the edge (method1, method2) would induce a cycle, we report an error // and do not add it to the set of edges. If it would not induce a cycle we add // it to the set of edges and return. if (method1 == method2) { // direct recursion is diagnosed elsewhere throw ExceptionUtilities.Unreachable; } if (_constructorInitializers == null) { _constructorInitializers = new SmallDictionary <MethodSymbol, MethodSymbol>(); _constructorInitializers.Add(method1, method2); return; } MethodSymbol next = method2; while (true) { if (_constructorInitializers.TryGetValue(next, out next)) { Debug.Assert((object)next != null); if (method1 == next) { // We found a (new) cycle containing the edge (method1, method2). Report an // error and do not add the edge. diagnostics.Add(ErrorCode.ERR_IndirectRecursiveConstructorCall, syntax.Location, method1); return; } } else { // we've reached the end of the path without finding a cycle. Add the new edge. _constructorInitializers.Add(method1, method2); return; } } }
/// <summary> /// Create the optimized plan for the location of lambda methods and whether scopes need access to parent scopes /// </summary> internal void ComputeLambdaScopesAndFrameCaptures(ParameterSymbol thisParam) { RemoveUnneededReferences(thisParam); VisitClosures(ScopeTree, (scope, closure) => { if (closure.CapturedVariables.Count > 0) { (Scope innermost, Scope outermost) = FindLambdaScopeRange(closure, scope); RecordClosureScope(innermost, outermost, closure); } }); (Scope innermost, Scope outermost) FindLambdaScopeRange(Closure closure, Scope closureScope) { Scope innermost = null; Scope outermost = null; var capturedVars = PooledHashSet <Symbol> .GetInstance(); capturedVars.AddAll(closure.CapturedVariables); // If any of the captured variables are local functions we'll need // to add the captured variables of that local function to the current // set. This has the effect of ensuring that if the local function // captures anything "above" the current scope then parent frame // is itself captured (so that the current lambda can call that // local function). foreach (var captured in closure.CapturedVariables) { if (captured is LocalFunctionSymbol localFunc) { var(found, _) = GetVisibleClosure(closureScope, localFunc); capturedVars.AddAll(found.CapturedVariables); } } for (var curScope = closureScope; curScope != null && capturedVars.Count > 0; curScope = curScope.Parent) { if (!(capturedVars.Overlaps(curScope.DeclaredVariables) || capturedVars.Overlaps(curScope.Closures.Select(c => c.OriginalMethodSymbol)))) { continue; } outermost = curScope; if (innermost == null) { innermost = curScope; } capturedVars.RemoveAll(curScope.DeclaredVariables); capturedVars.RemoveAll(curScope.Closures.Select(c => c.OriginalMethodSymbol)); } // If any captured variables are left, they're captured above method scope if (capturedVars.Count > 0) { outermost = null; } capturedVars.Free(); return(innermost, outermost); } void RecordClosureScope(Scope innermost, Scope outermost, Closure closure) { // 1) if there is innermost scope, lambda goes there as we cannot go any higher. // 2) scopes in [innermostScope, outermostScope) chain need to have access to the parent scope. // // Example: // if a lambda captures a method's parameter and `this`, // its innermost scope depth is 0 (method locals and parameters) // and outermost scope is -1 // Such lambda will be placed in a closure frame that corresponds to the method's outer block // and this frame will also lift original `this` as a field when created by its parent. // Note that it is completely irrelevant how deeply the lexical scope of the lambda was originally nested. if (innermost != null) { LambdaScopes.Add(closure.OriginalMethodSymbol, innermost.BoundNode); // Disable struct closures on methods converted to delegates, as well as on async and iterator methods. var markAsNoStruct = !CanTakeRefParameters(closure.OriginalMethodSymbol); if (markAsNoStruct) { ScopesThatCantBeStructs.Add(innermost.BoundNode); } while (innermost != outermost) { NeedsParentFrame.Add(innermost.BoundNode); innermost = innermost.Parent; if (markAsNoStruct && innermost != null) { ScopesThatCantBeStructs.Add(innermost.BoundNode); } } } } }
public void AddZeroKey() { var dict = new SmallDictionary<int, string>(); dict.Add(0,"abc"); }
public void GetMissingKeyOne() { var dict = new SmallDictionary<int, string>(); dict.Add(2, "abc"); var temp = dict[3]; }
private static SmallDictionary<TypeParameterSymbol, TypeWithModifiers> ConstructMapping(ImmutableArray<TypeParameterSymbol> from, ImmutableArray<TypeWithModifiers> to) { var mapping = new SmallDictionary<TypeParameterSymbol, TypeWithModifiers>(ReferenceEqualityComparer.Instance); Debug.Assert(from.Length == to.Length); for (int i = 0; i < from.Length; i++) { TypeParameterSymbol tp = from[i]; TypeWithModifiers ta = to[i]; if (!ta.Is(tp)) { mapping.Add(tp, ta); } } return mapping; }
public void GetMissingKeyThree() { var dict = new SmallDictionary<int, string>(); dict.Add(2, "abc"); dict.Add(5, "def"); dict.Add(11, "third"); var temp = dict[3]; }
/// <summary> /// Report an error if adding the edge (method1, method2) to the ctor-initializer /// graph would add a new cycle to that graph. /// </summary> /// <param name="method1">a calling ctor</param> /// <param name="method2">the chained-to ctor</param> /// <param name="syntax">where to report a cyclic error if needed</param> /// <param name="diagnostics">a diagnostic bag for receiving the diagnostic</param> internal void ReportCtorInitializerCycles(MethodSymbol method1, MethodSymbol method2, SyntaxNode syntax, DiagnosticBag diagnostics) { // precondition and postcondition: the graph _constructorInitializers is acyclic. // If adding the edge (method1, method2) would induce a cycle, we report an error // and do not add it to the set of edges. If it would not induce a cycle we add // it to the set of edges and return. if (method1 == method2) { // direct recursion is diagnosed elsewhere throw ExceptionUtilities.Unreachable; } if (_constructorInitializers == null) { _constructorInitializers = new SmallDictionary<MethodSymbol, MethodSymbol>(); _constructorInitializers.Add(method1, method2); return; } MethodSymbol next = method2; while (true) { if (_constructorInitializers.TryGetValue(next, out next)) { Debug.Assert((object)next != null); if (method1 == next) { // We found a (new) cycle containing the edge (method1, method2). Report an // error and do not add the edge. diagnostics.Add(ErrorCode.ERR_IndirectRecursiveConstructorCall, syntax.Location, method1); return; } } else { // we've reached the end of the path without finding a cycle. Add the new edge. _constructorInitializers.Add(method1, method2); return; } } }
public void Add() { var dict = new SmallDictionary<int, string>(); dict.Add(2, "abc"); Assert.AreEqual(1, dict.Count); dict.Add(5,"def"); Assert.AreEqual(2, dict.Count); dict.Add(11,"third"); Assert.AreEqual(3, dict.Count); Assert.AreEqual("abc", dict[2]); Assert.AreEqual("def", dict[5]); Assert.AreEqual("third", dict[11]); }
public void AddExistingKeyTwoKeys() { var dict = new SmallDictionary<int, string>(); dict.Add(2, "abc"); dict.Add(3, "def"); dict.Add(3, "def"); }
public void Remove() { var dict = new SmallDictionary<int, string>(); Assert.IsFalse(dict.Remove(2), "Remove a missing item from an empty dictionary"); dict.Add(2, "abc"); Assert.IsFalse(dict.Remove(3), "Remove a missing item from a dictionary with one item"); Assert.IsTrue(dict.Remove(2), "Remove the only item from a dictionary"); Assert.AreEqual(0, dict.Count, "Nothing remains after removing the only item"); dict.Add(2, "abc"); dict.Add(5, "def"); dict.Add(11, "third"); Assert.IsFalse(dict.Remove(7), "Remove a missing item from a dictionary with three items"); Assert.IsTrue(dict.Remove(2), "Remove the first item from a dictionary with three items"); Assert.AreEqual(2, dict.Count, "Two items remain after removing the first of three"); string output; Assert.IsFalse(dict.TryGetValue(2, out output), "Removed item (first) should be gone from original three"); Assert.AreEqual("def", dict[5]); Assert.AreEqual("third", dict[11]); dict.Add(2, "abc"); Assert.IsTrue(dict.Remove(5), "Remove first of two items in others"); Assert.AreEqual(2, dict.Count); Assert.IsFalse(dict.TryGetValue(5, out output)); Assert.AreEqual("abc", dict[2]); Assert.AreEqual("third", dict[11]); Assert.IsTrue(dict.Remove(2), "Remove only item in others"); Assert.AreEqual(1, dict.Count); Assert.IsFalse(dict.TryGetValue(2, out output)); Assert.AreEqual("third", dict[11]); Assert.IsTrue(dict.Remove(11), "Remove only item in dictionary which previously had three"); Assert.AreEqual(0, dict.Count); Assert.IsFalse(dict.TryGetValue(11, out output)); dict.Add(2, "abc"); dict.Add(5, "def"); dict.Add(11, "third"); dict.Add(13, "fourth"); Assert.IsTrue(dict.Remove(11), "Remove middle of three items in others"); Assert.AreEqual(3, dict.Count); Assert.IsFalse(dict.TryGetValue(11, out output)); Assert.AreEqual("abc", dict[2]); Assert.AreEqual("def", dict[5]); Assert.AreEqual("fourth", dict[13]); Assert.IsTrue(dict.Remove(13), "Remove last of two items in others"); Assert.AreEqual(2, dict.Count); Assert.IsFalse(dict.TryGetValue(13, out output)); Assert.AreEqual("abc", dict[2]); Assert.AreEqual("def", dict[5]); Assert.IsTrue(dict.Remove(2), "Remove first item when others contains exactly one"); Assert.AreEqual(1, dict.Count); Assert.IsFalse(dict.TryGetValue(2, out output)); Assert.AreEqual("def", dict[5]); }
public void Enumerator() { var dict = new SmallDictionary<int, string>(); foreach (var kvp in dict) { Assert.Fail("Should get no iterations looping over empty dictionary"); } dict.Add(2, "abc"); int count = 0; foreach (var kvp in dict) { count++; Assert.AreEqual(2, kvp.Key); Assert.AreEqual("abc", kvp.Value); } Assert.AreEqual(1,count); dict.Add(5, "def"); dict.Add(11, "third"); count = 0; Dictionary<int, string> normalDict = new Dictionary<int, string>(dict); Assert.AreEqual("abc", normalDict[2]); Assert.AreEqual("def", normalDict[5]); Assert.AreEqual("third", normalDict[11]); Assert.AreEqual(3, normalDict.Count); foreach (var kvp in dict) { count++; Assert.IsTrue(normalDict.ContainsKey(kvp.Key)); Assert.AreEqual(normalDict[kvp.Key], kvp.Value); normalDict.Remove(kvp.Key); } Assert.AreEqual(3, count); }
public void KeysAndValues() { var dict = new SmallDictionary<int, string>(); VerifyIntArrays(new int[0], dict.Keys.ToArray()); VerifyStringArrays(new string[0], dict.Values.ToArray()); dict.Add(2, "abc"); VerifyIntArrays(new int[] {2}, dict.Keys.ToArray()); VerifyStringArrays(new string[] {"abc"}, dict.Values.ToArray()); // This test is too strict, it enforces a particular order of the results. dict.Add(5, "def"); dict.Add(11, "third"); VerifyIntArrays(new int[] { 2, 5, 11 }, dict.Keys.ToArray()); VerifyStringArrays(new string[] { "abc", "def", "third" }, dict.Values.ToArray()); }