Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -166,9 +166,9 @@ public UnmanagedMemoryStream GetUnmanagedStream()
byte[] bits;

// Try our cache first.
lock (_resourceCache)
lock (s_resourceCache)
{
bits = _resourceCache.Get(_fontUri);
bits = s_resourceCache.Get(_fontUri);
}

if (bits == null)
Expand Down Expand Up @@ -202,9 +202,9 @@ public UnmanagedMemoryStream GetUnmanagedStream()
fontStream?.Close();
}

lock (_resourceCache)
lock (s_resourceCache)
{
_resourceCache.Add(_fontUri, bits, false);
s_resourceCache.Add(_fontUri, bits, false);
}

return ByteArrayToUnmanagedStream(bits);
Expand Down Expand Up @@ -239,9 +239,9 @@ public Stream GetStream()
byte[] bits;

// Try our cache first.
lock (_resourceCache)
lock (s_resourceCache)
{
bits = _resourceCache.Get(_fontUri);
bits = s_resourceCache.Get(_fontUri);
}

if (bits != null)
Expand Down Expand Up @@ -423,7 +423,7 @@ protected override void Dispose(bool disposing)

private Uri _fontUri;

private static SizeLimitedCache<Uri, byte[]> _resourceCache = new SizeLimitedCache<Uri, byte[]>(MaximumCacheItems);
private static readonly SizeLimitedCache<Uri, byte[]> s_resourceCache = new(MaximumCacheItems);

/// <summary>
/// The maximum number of fonts downloaded from pack:// Uris.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ namespace MS.Internal.Shaping
/// </summary>
internal class GlyphingCache
{
private SizeLimitedCache<Typeface, TypefaceMap> _sizeLimitedCache;
private readonly SizeLimitedCache<Typeface, TypefaceMap> _sizeLimitedCache;

internal GlyphingCache(int capacity)
{
Expand Down
113 changes: 33 additions & 80 deletions src/Microsoft.DotNet.Wpf/src/Shared/MS/Internal/SizeLimitedCache.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,7 +20,7 @@ namespace MS.Internal
/// changed, it gets moved to the end of the list. Also, permanent items,
/// though in the hash table, are NOT in the linked list.
/// </remarks>
internal class SizeLimitedCache<K, V>
internal sealed class SizeLimitedCache<K, V>
{
//*****************************************************
// Constructors
Expand All @@ -40,12 +40,13 @@ public SizeLimitedCache(int maximumItems)
_permanentCount = 0;

// set up an empty list.
// the _begin and _end nodes are empty nodes marking the begin and
// end of the list.
// the _begin and _end nodes are empty nodes marking the begin and end of the list.
_begin = new Node(default(K), default(V), false);
_end = new Node(default(K), default(V), false);
_begin.Next = _end;

_begin.Next = _end;
_end.Previous = _begin;

_nodeLookup = new Dictionary<K, Node>();
}

Expand Down Expand Up @@ -85,20 +86,13 @@ public int MaximumItems
/// </param>
public void Add(K key, V resource, bool isPermanent)
{
ArgumentNullException.ThrowIfNull(key, nameof(key));
ArgumentNullException.ThrowIfNull(resource, nameof(resource));

if ( (object)key == null)
{
throw new ArgumentNullException(nameof(key));
}
if ( (object)resource == null)
{
throw new ArgumentNullException(nameof(resource));
}

// note: [] throws, thus we should check if its in the dictionary first.
if (!_nodeLookup.ContainsKey(key))
// Lookup first
if (!_nodeLookup.TryGetValue(key, out Node node))
{
Node node = new Node(key, resource, isPermanent);
node = new Node(key, resource, isPermanent);
if (!isPermanent)
{
if (IsFull())
Expand All @@ -111,11 +105,11 @@ public void Add(K key, V resource, bool isPermanent)
{
_permanentCount++;
}

_nodeLookup[key] = node;
}
else
{
Node node = _nodeLookup[key];
if (!node.IsPermanent)
{
RemoveFromList(node);
Expand Down Expand Up @@ -151,27 +145,15 @@ public void Add(K key, V resource, bool isPermanent)
/// </param>
public void Remove(K key)
{
if ( (object)key == null)
{
throw new ArgumentNullException(nameof(key));
}
ArgumentNullException.ThrowIfNull(key, nameof(key));

// note: [] throws, thus we should check if its in the dictionary first.
if (!_nodeLookup.ContainsKey(key))
{
if (!_nodeLookup.Remove(key, out Node node))
return;
}
Node node = _nodeLookup[key];

_nodeLookup.Remove(key);
if (!node.IsPermanent)
{
RemoveFromList(node);
}
else
{
_permanentCount--;
}
}

/// <summary>
Expand All @@ -187,17 +169,10 @@ public void Remove(K key)
/// </returns>
public V Get(K key)
{
if ( (object)key == null)
{
throw new ArgumentNullException(nameof(key));
}
ArgumentNullException.ThrowIfNull(key, nameof(key));

// note: [] throws, thus we should check if its in the dictionary first.
if (!_nodeLookup.ContainsKey(key))
{
return default(V);
}
Node node = _nodeLookup[key];
if (!_nodeLookup.TryGetValue(key, out Node node))
return default;

if (!node.IsPermanent)
{
Expand All @@ -218,7 +193,9 @@ public V Get(K key)
private void RemoveOldest()
{
Node node = _begin.Next;

_nodeLookup.Remove(node.Key);

RemoveFromList(node);
}

Expand All @@ -232,6 +209,7 @@ private void InsertAtEnd(Node node)
{
node.Next = _end;
node.Previous = _end.Previous;

node.Previous.Next = node;
_end.Previous = node;
}
Expand All @@ -242,7 +220,7 @@ private void InsertAtEnd(Node node)
/// <param name="node">
/// The node to remove
/// </param>
private void RemoveFromList(Node node)
private static void RemoveFromList(Node node)
{
node.Previous.Next = node.Next;
node.Next.Previous = node.Previous;
Expand All @@ -257,13 +235,13 @@ private void RemoveFromList(Node node)
/// </returns>
private bool IsFull()
{
return (_nodeLookup.Count - _permanentCount >= _maximumItems);
return (_nodeLookup.Count - _permanentCount) >= _maximumItems;
}

/// <summary>
/// Doubly linked list node class. Has 3 values: key, resource, permanence flag
/// </summary>
private class Node
private sealed class Node
{
public Node(K key, V resource, bool isPermanent)
{
Expand All @@ -272,59 +250,34 @@ public Node(K key, V resource, bool isPermanent)
IsPermanent = isPermanent;
}

public K Key
{
get { return _key; }
set { _key = value; }
}
public K Key { get; }

public V Resource
{
get { return _resource; }
set { _resource = value; }
}
public V Resource { get; set; }

public bool IsPermanent
{
get { return _isPermanent; }
set { _isPermanent = value; }
}
public bool IsPermanent { get; set; }

public Node Next
{
get { return _next; }
set { _next = value; }
}
public Node Next { get; set; }

public Node Previous
{
get { return _previous; }
set { _previous = value; }
}
public Node Previous { get; set; }

private V _resource;
private K _key;
private bool _isPermanent;
private Node _next;
private Node _previous;
}

//*****************************************************
// Private Fields
// ****************************************************

// the maximum nonpermanent items allowed
private int _maximumItems;

// need to keep a separate counter for permanent items
private int _permanentCount;

// the maximum nonpermanent items allowed
private readonly int _maximumItems;

// the _begin and _end nodes are empty nodes marking the begin and
// end of the list.
private Node _begin;
private Node _end;
private readonly Node _begin;
private readonly Node _end;

// the hashtable mapping keys to nodes
private Dictionary<K, Node> _nodeLookup;
private readonly Dictionary<K, Node> _nodeLookup;
}
}