/// <summary> /// Caches some object <paramref name="Item"/>. /// </summary> /// <param name="HonestItemSizeInBytes">The size of <paramref name="Item"/> in bytes.</param> /// <param name="Item">Object which should be cached.</param> /// <returns> /// A reference code for later access to the object <paramref name="Item"/>. /// </returns> public static ulong CacheItem(object Item, int HonestItemSizeInBytes) { RefCounter++; Debug.Assert((!(Item is MultidimensionalArray)) || (((MultidimensionalArray)Item).Length * sizeof(double) == HonestItemSizeInBytes)); CacheBank cb = new CacheBank() { Item = Item, MemSize = HonestItemSizeInBytes, UseCount = 1, Reference = RefCounter }; while (CurrentSize + cb.MemSize > MaxMem) { if (!RemoveAtTail()) { break; } } int iBank = Insert(cb); Debug.Assert(object.ReferenceEquals(Banks[iBank], cb)); Debug.Assert(cb.iBank == iBank); ulong R = ((ulong)iBank); R |= (((ulong)cb.Reference) << 32); return(R); }
/// <summary> /// Returns true if the item stored under reference <paramref name="Reference"/> is still present in the cache, false otherwise. /// In contrast to <see cref="GetItem"/>, this is cheaper and does not affect cache statistics. /// </summary> public static bool IsAlive(ulong Reference) { int iBank = (int)(Reference & 0x00000000FFFFFFFF); int iref = (int)((Reference & 0xFFFFFFFF00000000) >> 32); CacheBank cb = Banks[iBank]; return(cb != null && iref == cb.Reference); }
static CacheBank Head; // dummy 'bank', marking the tail of the cache-ranking list (last object to discard) static void Remove(int iBank) { CacheBank toRemove = Banks[iBank]; Debug.Assert(toRemove.iBank == iBank); Banks[iBank] = null; toRemove.prev.next = toRemove.next; toRemove.next.prev = toRemove.prev; CurrentSize = CurrentSize - toRemove.MemSize; emptyBanks.Add(iBank); m_NoOfUsedBanks--; Debug.Assert(m_NoOfUsedBanks >= 0); }
/// <summary> /// Removes some cached item from the cache. /// </summary> public static void ForgetItem(ulong Reference) { int iBank = (int)(Reference & 0x00000000FFFFFFFF); int iref = (int)((Reference & 0xFFFFFFFF00000000) >> 32); CacheBank cb = Banks[iBank]; if ((cb != null && iref == cb.Reference)) { // object is still in cache, so there is something to forget. Remove(iBank); } }
static int Insert(CacheBank cb) { if (emptyBanks.Count > 0) { cb.iBank = emptyBanks[emptyBanks.Count - 1]; emptyBanks.RemoveAt(emptyBanks.Count - 1); Debug.Assert(Banks[cb.iBank] == null); Banks[cb.iBank] = cb; } else { cb.iBank = Banks.Count; Banks.Add(cb); } m_NoOfUsedBanks++; CurrentSize += cb.MemSize;// update the bank ranking: switch (Strategy) { case CacheStrategy.DiscardLeastRecentyUsed: // insert at head cb.next = Head.next; cb.prev = Head; Head.next.prev = cb; Head.next = cb; break; case CacheStrategy.DiscardLeastFrequentlyUsed: // insert at tail cb.next = Tail; cb.prev = Tail.prev; Tail.prev.next = cb; Tail.prev = cb; // bubble up until the sorting is ok. BubbleUp(cb); break; default: throw new NotImplementedException(); } Debug.Assert(Banks[cb.iBank].iBank == cb.iBank); return(cb.iBank); }
static void ResetCache() { Tail = new CacheBank() { iBank = int.MinValue }; Head = new CacheBank() { iBank = int.MinValue }; Tail.prev = Head; Head.next = Tail; emptyBanks = new List <int>(); Banks = new List <CacheBank>(); CurrentSize = 0; m_NoOfUsedBanks = 0; }
private static void BubbleUp(CacheBank a) { while ( (!object.ReferenceEquals(a.prev, Head)) && // reached top of ranking (a.UseCount >= a.prev.UseCount)) // >= prefers least-recently used in case of doubt { CacheBank p = a.prev; CacheBank pp = p.prev; CacheBank n = a.next; pp.next = a; a.next = p; p.next = n; a.prev = pp; p.prev = a; n.prev = p; } }
static CacheBank Access(int iBank) { CacheBank a = Banks[iBank]; if (a == null) { return(a); } a.UseCount++; // update the bank ranking: switch (Strategy) { case CacheStrategy.DiscardLeastRecentyUsed: // // remove 'a', where-ever it is... a.prev.next = a.next; a.next.prev = a.prev; // ... and put it on top: a.next = Head.next; a.prev = Head; Head.next.prev = a; Head.next = a; break; case CacheStrategy.DiscardLeastFrequentlyUsed: // // bubble up until the sorting is ok. BubbleUp(a); break; default: throw new NotImplementedException(); } return(a); }
/// <summary> /// Returns the item stored under reference <paramref name="Reference"/> /// -- or -- /// null, if the object has been removed from the cache. /// </summary> public static object GetItem(ulong Reference) { int iBank = (int)(Reference & 0x00000000FFFFFFFF); int iref = (int)((Reference & 0xFFFFFFFF00000000) >> 32); CacheBank cb = Banks[iBank]; if (cb != null && iref == cb.Reference) { Access(iBank); Hits++; return(cb.Item); } else { Misses++; return(null); } }