#pragma once #include #define LOCKTHREAD const lock mon( safe_cast(this->_data)->SyncRoot ) #define KEY_PAIR Generic::KeyValuePair using namespace msclr; using namespace System; using namespace System::Collections; using namespace System::Timers; using namespace System::Runtime::InteropServices; namespace RSn9 { namespace Caching { generic public ref class SimpleCache sealed : public Generic::IDictionary, public Generic::ICollection, public ICollection, public Generic::IEnumerable, public IEnumerable { private: generic ref class entry; TimeSpan _commonSlide; TimeSpan _commonExpire; Generic::Dictionary^>^ _data; Timer^ _timer; /// /// General initialisation a new instance of the class. /// /// The capacity. /// The interval. /// MRW: 02/03/2007 void constructme(int capacity, TimeSpan interval) { this->_commonSlide = TimeSpan::FromMinutes(5); this->_commonExpire= TimeSpan::FromMinutes(15); this->_data = gcnew Generic::Dictionary^>(capacity); this->_timer = gcnew Timer; this->_timer->AutoReset = true; this->_timer->Interval = interval.TotalMilliseconds; this->_timer->Elapsed += gcnew ElapsedEventHandler(this,&SimpleCache::_timer_Elapsed); this->_timer->Start(); } /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// /// MRW: 02/03/2007 ~SimpleCache() { this->!SimpleCache(); } /// /// Releases unmanaged resources and performs other cleanup operations before the /// is reclaimed by garbage collection. /// /// MRW: 02/03/2007 !SimpleCache() { this->RemoveAll(); if( this->_timer != nullptr ) { delete this->_timer; this->_timer = nullptr; } } public: /// /// Initializes a new instance of the class. /// /// MRW: 02/03/2007 SimpleCache() { this->constructme(4, TimeSpan::FromSeconds(5)); } /// /// Initializes a new instance of the class. /// /// The capacity. /// MRW: 02/03/2007 SimpleCache(int capacity) { this->constructme(capacity, TimeSpan::FromSeconds(5)); } /// /// Initializes a new instance of the class. /// /// The capacity. /// The interval. /// MRW: 02/03/2007 SimpleCache(int capacity, TimeSpan interval) { this->constructme(capacity, interval); } /// /// Gets or sets the with the specified key. /// /// /// MRW: 02/03/2007 property T default[String ^] { virtual T get(String^ key) { LOCKTHREAD; this->_data[key]->_stamp += this->_data[key]->_slide; return this->_data[key]->_data; } virtual void set(String^ key, T value) { LOCKTHREAD; this->_data[key]->_stamp += this->_data[key]->_slide; this->_data[key]->_data = value; } } /// /// Adds an element with the provided key and value to the . /// /// The object to use as the key of the element to add. /// The object to use as the value of the element to add. /// MRW: 02/03/2007 virtual void Add(String^ key, T value) { LOCKTHREAD; this->_data->Add(key, gcnew entry(value, this->_commonExpire, this->_commonSlide , nullptr)); } /// /// Adds the specified key. /// /// The key. /// The value. /// The expire. /// MRW: 02/03/2007 void Add(String^ key, T value, TimeSpan expire) { LOCKTHREAD; this->_data->Add(key, gcnew entry(value,expire,this->_commonSlide,nullptr)); } /// /// Adds the specified key. /// /// The key. /// The value. /// The expire. /// The slide. /// MRW: 02/03/2007 void Add(String^ key, T value, TimeSpan expire, TimeSpan slide) { LOCKTHREAD; this->_data->Add(key, gcnew entry(value,expire,slide,nullptr)); } /// /// Adds the specified key. /// /// The key. /// The value. /// The expire handle. /// MRW: 02/03/2007 void Add(String^ key, T value, EventHandler^ expireHandle) { LOCKTHREAD; this->_data->Add(key, gcnew entry(value,this->_commonExpire,this->_commonSlide,expireHandle)); } /// /// Adds the specified key. /// /// The key. /// The value. /// The expire. /// The expire handle. /// MRW: 02/03/2007 void Add(String^ key, T value, TimeSpan expire, EventHandler^ expireHandle) { LOCKTHREAD; this->_data->Add(key, gcnew entry(value,expire,this->_commonSlide,expireHandle)); } /// /// Adds the specified key. /// /// The key. /// The value. /// The expire. /// The slide. /// The expire handle. /// MRW: 02/03/2007 void Add(String^ key, T value, TimeSpan expire, TimeSpan slide, EventHandler^ expireHandle) { LOCKTHREAD; this->_data->Add(key, gcnew entry(value,expire,slide,expireHandle)); } /// /// Forces the expire. /// /// MRW: 02/03/2007 void ForceExpire() { LOCKTHREAD; try { this->_timer->Stop(); this->InternalExpire(true); } finally { this->_timer->Start(); } } /// /// Removes the element with the specified key from the . /// /// The key of the element to remove. /// /// true if the element is successfully removed; otherwise, false. This method also returns false if key was not found in the original . /// /// MRW: 02/03/2007 virtual bool Remove(String^ key) { LOCKTHREAD; if(this->_data[key]->_onExpire != nullptr) this->_data[key]->_onExpire(this->_data[key]->_data, EventArgs::Empty); delete this->_data[key]; return this->_data->Remove(key); } /// /// Removes all. /// /// MRW: 02/03/2007 void RemoveAll() { if(this->_data->Count >0) { LOCKTHREAD; for each(String^ key in this->_data->Keys) this->Remove(key); this->_data->Clear(); } } /// /// Determines whether the contains an element with the specified key. /// /// The key to locate in the . /// /// true if the contains an element with the key; otherwise, false. /// /// MRW: 02/03/2007 virtual bool ContainsKey(String^ key) { LOCKTHREAD; return this->_data->ContainsKey(key); } /// /// Removes all items from the . /// /// MRW: 02/03/2007 virtual void Clear() { LOCKTHREAD; this->_data->Clear(); } /// /// Copies the elements of the to an , starting at a particular index. /// /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. /// The zero-based index in array at which copying begins. /// MRW: 02/03/2007 virtual void CopyTo(Array^ arry, int index) { LOCKTHREAD; safe_cast(this->_data)->CopyTo(arry,index); } /// /// Gets an object that can be used to synchronize access to the . /// /// /// An object that can be used to synchronize access to the . /// MRW: 02/03/2007 property Object^ SyncRoot { virtual Object^ get() { return safe_cast(this->_data)->SyncRoot; } } /// /// Gets a COPY of containing the values in the . /// /// /// An containing the values in the object that implements . /// MRW: 02/03/2007 property Generic::ICollection^ Values { virtual Generic::ICollection^ get() { LOCKTHREAD; Generic::Dictionary^>::ValueCollection^ rr = this->_data->Values; Generic::List^ lst = gcnew Generic::List(rr->Count); for each(entry^ en in rr) lst->Add(en->_data); return lst; } } /// /// Gets an containing the keys of the . /// /// /// An containing the keys of the object that implements . /// MRW: 02/03/2007 property Generic::ICollection^ Keys { virtual Generic::ICollection^ get() { LOCKTHREAD; return this->_data->Keys; } } /// /// Gets the number of elements contained in the . /// /// /// The number of elements contained in the . /// MRW: 02/03/2007 property int Count { virtual int get() { LOCKTHREAD; return this->_data->Count; } } /// /// Gets a value indicating whether the is read-only. /// /// /// true if the is read-only; otherwise, false. /// MRW: 02/03/2007 property bool IsReadOnly { virtual bool get() { return false; } } /// /// Gets a value indicating whether access to the is synchronized (thread safe). /// /// /// true if access to the is synchronized (thread safe); otherwise, false. /// MRW: 02/03/2007 property bool IsSynchronized { virtual bool get() { return true; } } /// /// Gets or sets the common expire. /// /// The common expire. /// MRW: 02/03/2007 property TimeSpan CommonExpire { TimeSpan get() { return this->_commonExpire; } void set(TimeSpan value) { this->_commonExpire = value; } } /// /// Gets or sets the common slide. /// /// The common slide. /// MRW: 02/03/2007 property TimeSpan CommonSlide { TimeSpan get() { return this->_commonSlide; } void set(TimeSpan value) { this->_commonSlide = value; } } /// /// Returns an enumerator that iterates through the cache. /// /// /// An object that can be used to iterate through the collection. /// /// MRW: 02/03/2007 virtual IEnumerator^ GetEnumerator() = IEnumerable::GetEnumerator { LOCKTHREAD; return this->_data->GetEnumerator(); } private: /// /// Not implemented. /// /// The key. /// The value. /// /// MRW: 02/03/2007 virtual bool TryGetValue(String^ key,[Out] T %value) sealed = Generic::IDictionary::TryGetValue { throw gcnew NotImplementedException(); } /// /// Adds an item to the . /// /// The object to add to the . /// The is read-only. /// MRW: 02/03/2007 virtual void Add2(KEY_PAIR item) sealed = Generic::ICollection::Add { this->Add(item.Key, item.Value); } /// /// Determines whether the contains a specific value. /// /// The object to locate in the . /// /// true if item is found in the ; otherwise, false. /// /// MRW: 02/03/2007 virtual bool Contains2(KEY_PAIR item) sealed = Generic::ICollection::Contains { LOCKTHREAD; Generic::Dictionary^ tmp = gcnew Generic::Dictionary(this->_data->Count); for each( String^ key in this->_data->Keys ) tmp->Add(key, this->_data[key]->_data); return safe_cast^>(tmp)->Contains(item); } /// /// Returns an enumerator that iterates through the collection. /// /// /// A that can be used to iterate through the collection. /// /// MRW: 02/03/2007 virtual Generic::IEnumerator^ GetEnumerator2() sealed = Generic::IEnumerable::GetEnumerator { LOCKTHREAD; Generic::Dictionary^ tmp = gcnew Generic::Dictionary(this->_data->Count); for each( String^ key in this->_data->Keys ) tmp->Add(key, this->_data[key]->_data); return tmp->GetEnumerator(); } /// /// Copies the elements of the to an , starting at a particular index. /// /// The one-dimensional that is the destination of the elements copied from . The must have zero-based indexing. /// The zero-based index in array at which copying begins. /// MRW: 02/03/2007 virtual void CopyTo2(array^ arry, int arrayIndex) sealed = Generic::ICollection::CopyTo { LOCKTHREAD; Generic::Dictionary^ tmp = gcnew Generic::Dictionary(this->_data->Count); for each( String^ key in this->_data->Keys ) tmp->Add(key, this->_data[key]->_data); safe_cast^>(tmp)->CopyTo(arry, arrayIndex); } /// /// Removes the first occurrence of a specific object from the . /// /// The object to remove from the . /// /// true if item was successfully removed from the ; otherwise, false. This method also returns false if item is not found in the original . /// /// MRW: 02/03/2007 virtual bool Remove(KEY_PAIR item) sealed = Generic::ICollection::Remove { return this->Remove(item.Key); } /// /// Handles the Elapsed event of the _timer control. /// /// The source of the event. /// The instance containing the event data. /// MRW: 02/03/2007 void _timer_Elapsed(Object^ sender, ElapsedEventArgs^ e) { LOCKTHREAD; try { this->_timer->Stop(); this->InternalExpire(false); } finally { this->_timer->Start(); } } /// /// Internally runs the expiry. /// /// if set to true [force]. /// MRW: 02/03/2007 void InternalExpire(bool force) { if( this->_data->Count > 0 ) { const DateTime now = DateTime::Now; Generic::List^ killList = gcnew Generic::List; for each( String^ key in this->_data->Keys ) { entry^ tmp = this->_data[key]; if( tmp->_expire < now && ( force || tmp->_allowExpire ) ) killList->Add(key); } for each( String^ key in killList ) this->Remove(key); } } /// /// Represents a cache entry and all of its associated data /// /// Anything... literally /// MRW: 02/03/2007 generic ref class entry sealed { public: U _data; DateTime _stamp; TimeSpan _slide; DateTime _expire; bool _allowExpire; EventHandler^ _onExpire; /// /// Initializes a new instance of the class. /// /// The data. /// The expire. /// The slide. /// The expire handler. /// MRW: 02/03/2007 entry(U data, TimeSpan expire, TimeSpan slide, EventHandler^ expireHandler) { this->_data = data; this->_stamp = DateTime::Now; this->_slide = slide; this->_expire = this->_stamp.Add(expire); this->_onExpire = expireHandler; if( expire == TimeSpan::Zero ) this->_allowExpire = false; else this->_allowExpire = true; } /// /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources. /// /// MRW: 02/03/2007 ~entry() { this->!entry(); } /// /// Releases unmanaged resources and performs other cleanup operations before the /// is reclaimed by garbage collection. /// /// MRW: 02/03/2007 !entry() { delete this->_data; } }; }; } }