/// <summary> /// Version of Intern that gathers statistics /// </summary> private string InternWithStatistics(IInternable candidate) { string result; _stopwatch.Start(); bool?interned = TryIntern(candidate, out result); _stopwatch.Stop(); if (interned.HasValue && !interned.Value) { // Could not intern. _internMisses++; int priorCount = 0; _missedStrings.TryGetValue(result, out priorCount); _missedStrings[result] = priorCount + 1; return(result); } else if (interned == null) { // Decided not to attempt interning _internRejects++; int priorCount = 0; _rejectedStrings.TryGetValue(result, out priorCount); _rejectedStrings[result] = priorCount + 1; return(result); } _internHits++; if (!candidate.ReferenceEquals(result)) { // Reference changed so 'candidate' is now released and should save memory. _internEliminatedStrings++; _internEliminatedChars += candidate.Length; } return(result); }
/// <summary> /// Try to get one element from the list. Upon leaving the function 'candidate' will be at the head of the Mru list. /// This function is not thread-safe. /// </summary> internal bool TryGet(IInternable candidate, out string interned) { if (_size == 0) { interned = candidate.ExpensiveConvertToString(); return(false); } int length = candidate.Length; Node secondPrior = null; Node prior = null; Node head = _mru; bool found = false; int itemCount = 0; while (head != null && !found) { if (head.Value.Length == length) { if (candidate.IsOrdinalEqualToStringOfSameLength(head.Value)) { found = true; } } if (!found) { secondPrior = prior; prior = head; head = head.Next; } itemCount++; } if (found) { // Move it to the top and return the interned version. if (prior != null) { if (!candidate.ReferenceEquals(head.Value)) { // Wasn't at the top already, so move it there. prior.Next = head.Next; head.Next = _mru; _mru = head; interned = _mru.Value; return(true); } else { // But don't move it up if there is reference equality so that multiple calls to Intern don't redundantly emphasize a string. interned = head.Value; return(true); } } else { // Found the item in the top spot. No need to move anything. interned = _mru.Value; return(true); } } else { // Not found. Create a new entry and place it at the top. Node old = _mru; _mru = new Node(candidate.ExpensiveConvertToString()) { Next = old }; // Cache miss. Use this opportunity to discard any element over the max size. if (itemCount >= _size && secondPrior != null) { secondPrior.Next = null; } interned = _mru.Value; return(false); } }
/// <summary> /// Version of Intern that gathers statistics /// </summary> private string InternWithStatistics(IInternable candidate) { string result; _stopwatch.Start(); bool? interned = TryIntern(candidate, out result); _stopwatch.Stop(); if (interned.HasValue && !interned.Value) { // Could not intern. _internMisses++; int priorCount = 0; _missedStrings.TryGetValue(result, out priorCount); _missedStrings[result] = priorCount + 1; return result; } else if (interned == null) { // Decided not to attempt interning _internRejects++; int priorCount = 0; _rejectedStrings.TryGetValue(result, out priorCount); _rejectedStrings[result] = priorCount + 1; return result; } _internHits++; if (!candidate.ReferenceEquals(result)) { // Reference changed so 'candidate' is now released and should save memory. _internEliminatedStrings++; _internEliminatedChars += candidate.Length; } return result; }
/// <summary> /// Try to get one element from the list. Upon leaving the function 'candidate' will be at the head of the Mru list. /// This function is not thread-safe. /// </summary> internal bool TryGet(IInternable candidate, out string interned) { if (_size == 0) { interned = candidate.ExpensiveConvertToString(); return false; } int length = candidate.Length; Node secondPrior = null; Node prior = null; Node head = _mru; bool found = false; int itemCount = 0; while (head != null && !found) { if (head.Value.Length == length) { if (candidate.IsOrdinalEqualToStringOfSameLength(head.Value)) { found = true; } } if (!found) { secondPrior = prior; prior = head; head = head.Next; } itemCount++; } if (found) { // Move it to the top and return the interned version. if (prior != null) { if (!candidate.ReferenceEquals(head.Value)) { // Wasn't at the top already, so move it there. prior.Next = head.Next; head.Next = _mru; _mru = head; interned = _mru.Value; return true; } else { // But don't move it up if there is reference equality so that multiple calls to Intern don't redundantly emphasize a string. interned = head.Value; return true; } } else { // Found the item in the top spot. No need to move anything. interned = _mru.Value; return true; } } else { // Not found. Create a new entry and place it at the top. Node old = _mru; _mru = new Node(candidate.ExpensiveConvertToString()); _mru.Next = old; // Cache miss. Use this opportunity to discard any element over the max size. if (itemCount >= _size && secondPrior != null) { secondPrior.Next = null; } interned = _mru.Value; return false; } }