diff --git a/common/Makefile.am b/common/Makefile.am index ff0c1315f0fa6499e57e6ad3aa5a3727bd661822..c7bb9f19d897a3c76c3c44d04c5b0ceaab9995a9 100644 --- a/common/Makefile.am +++ b/common/Makefile.am @@ -21,7 +21,7 @@ commoninclude_HEADERS = dlist.cc stdstreams.cc alignment.hh \ gcd.hh lcm.hh configparser.hh propertymap.hh \ collectivecommunication.hh mpihelper.hh singleton.hh \ mpicollectivecommunication.hh geometrytype.hh utility.hh \ - bartonnackmanifcheck.hh binaryfunctions.hh + bartonnackmanifcheck.hh binaryfunctions.hh lru.hh if EXPRESSIONTEMPLATES commoninclude_HEADERS += exprtmpl.hh exprtmpl/scalar.inc exprtmpl/exprexpr.inc diff --git a/common/lru.hh b/common/lru.hh new file mode 100644 index 0000000000000000000000000000000000000000..ca6032ee2780ee00d068fd8ae020e1c743777ed6 --- /dev/null +++ b/common/lru.hh @@ -0,0 +1,190 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: +#ifndef DUNE_COMMON_LRU_HH +#define DUNE_COMMON_LRU_HH + +#include <list> +#include <utility> +#include <map> + +/** @file + @author Christian Engwer + @brief LRU Cache Container, using an STL like interface + + Implementatation of an LRU (least recently used) cache + container. This implementation follows the approach presented in + + \url + http://aim.adc.rmit.edu.au/phd/sgreuter/papers/graphite2003.pdf + + */ + +namespace Dune { + + template <typename _Key, typename _Tp, + typename _Alloc = std::allocator<_Tp> > + struct _lru_default_traits + { + typedef _Key key_type; + typedef _Alloc allocator; + typedef std::list< std::pair<_Key, _Tp> > list_type; + typedef typename list_type::iterator iterator; + typedef typename std::less<key_type> cmp; + typedef std::map< key_type, iterator, cmp, allocator > map_type; + }; + + template <typename _Key, typename _Tp, + typename _Traits = _lru_default_traits<_Key, _Tp> > + class lru + { + typedef typename _Traits::list_type list_type; + typedef typename _Traits::map_type map_type; + typedef typename _Traits::allocator allocator; + typedef typename map_type::iterator map_iterator; + typedef typename map_type::const_iterator const_map_iterator; + + public: + typedef typename _Traits::key_type key_type; + typedef typename allocator::value_type value_type; + typedef typename allocator::pointer pointer; + typedef typename allocator::const_pointer const_pointer; + typedef typename allocator::const_reference const_reference; + typedef typename allocator::reference reference; + typedef typename allocator::size_type size_type; + typedef typename list_type::iterator iterator; + typedef typename list_type::const_iterator const_iterator; + + /** + * Returns a read/write reference to the data of the most + * recently used entry. + */ + reference front() + { + return _data.front().second; + } + + /** + * Returns a read-only (constant) reference to the data of the + * most recently used entry. + */ + const_reference front() const + { + return _data.front().second; + } + + /** + * Returns a read/write reference to the data of the least + * recently used entry. + */ + reference back() + { + return _data.back().second; + } + + /** + * Returns a read-only (constant) reference to the data of the + * least recently used entry. + */ + const_reference back (int i) const + { + return _data.back().second; + } + + + /** + * @brief Removes the first element. + */ + const void pop_front() + { + key_type k = _data.front().first; + _data.pop_front(); + _index.erase(k); + } + /** + * @brief Removes the last element. + */ + const void pop_back() + { + key_type k = _data.back().first; + _data.pop_back(); + _index.erase(k); + } + + /** + * @brief Finds the element whose key is k. + * + * @return iterator + */ + iterator find (const key_type & key) + { + const map_iterator it = _index.find(key); + if (it == _index.end()) return _data.end(); + return it->second; + } + + /** + * @brief Finds the element whose key is k. + * + * @return const_iterator + */ + const_iterator find (const key_type & key) const + { + const map_iterator it = _index.find(key); + if (it == _index.end()) return _data.end(); + return it->second; + } + + /** + * @brief Insert a value into the container + * + * Stores value under key and marks it as most recent. + * + * @param key associated with data + * @param data to store + * + * @return reference of stored data + */ + reference insert (const key_type & key, const_reference data) + { + std::pair<key_type, value_type> x(key, data); + /* insert item as mru */ + iterator it = _data.insert(_data.begin(), x); + /* store index */ + _index[key] = it; + + return it->second; + } + + /** + * @copydoc touch + */ + reference insert (const key_type & key) + { + return touch (key); + } + + /** + * @brief mark data associateed with key as most recent + * + * @return reference of stored data + */ + reference touch (const key_type & key) + { + /* query _index for iterator */ + iterator it = _index[key]; + /* update _data + move it to the front + */ + _data.splice(_data.begin(), _data, it); + return it->second; + } + + private: + list_type _data; + map_type _index; + + }; + +} // namespace Dune + +#endif // DUNE_COMMON_LRU_HH diff --git a/common/test/.gitignore b/common/test/.gitignore index 2b2410ca92080b9f3e5345a02b96ea80156b1ac0..d9ec82012f909541e2ecf1058c68a3b8f718090b 100644 --- a/common/test/.gitignore +++ b/common/test/.gitignore @@ -3,6 +3,7 @@ Makefile.in .deps .libs semantic.cache +lrutest parsetest test-stack arraylisttest diff --git a/common/test/Makefile.am b/common/test/Makefile.am index 1d617d308ab0521b9ebe4cb1bd04eea6da2596d7..937b548e4ea489ce8325f5c20b61379183b1c275 100644 --- a/common/test/Makefile.am +++ b/common/test/Makefile.am @@ -4,7 +4,7 @@ TESTPROGS = parsetest test-stack arraylisttest smartpointertest \ sllisttest iteratorfacadetest tuplestest fvectortest fmatrixtest \ poolallocatortest settest gcdlcdtest streamtest \ bigunsignedinttest mpihelpertest singletontest mpicollcomm \ - utilitytest + utilitytest lrutest # which tests to run TESTS = $(TESTPROGS) @@ -21,6 +21,9 @@ bigunsignedinttest_DEPENDENCIES = $(LOCAL_LIBS) parsetest_SOURCES = parsetest.cc parsetest_DEPENDENCIES = $(LOCAL_LIBS) +lrutest_SOURCES = lrutest.cc +lrutest_DEPENDENCIES = $(LOCAL_LIBS) + sllisttest_SOURCES = sllisttest.cc sllisttest_DEPENDENCIES = $(LOCAL_LIBS) diff --git a/common/test/lrutest.cc b/common/test/lrutest.cc new file mode 100644 index 0000000000000000000000000000000000000000..a4ef1b50e07788dd7c1f3a3b0da2cd301ec67612 --- /dev/null +++ b/common/test/lrutest.cc @@ -0,0 +1,42 @@ +// -*- tab-width: 4; indent-tabs-mode: nil; c-basic-offset: 2 -*- +// vi: set et ts=4 sw=2 sts=2: +#include <assert.h> +#include <iostream> +#include <dune/common/lru.hh> + +void lru_test() +{ + std::cout << "testing Dune::lru<int,double>\n"; + + Dune::lru<int, double> lru; + lru.insert(10, 1.0); + assert(lru.front() == lru.back()); + lru.insert(11, 2.0); + assert(lru.front() == 2.0 && lru.back() == 1.0); + lru.insert(12, 99); + lru.insert(13, 1.3); + lru.insert(14, 12345); + lru.insert(15, -17); + assert(lru.front() == -17 && lru.back() == 1.0); + // update + lru.insert(10); + assert(lru.front() == 1.0 && lru.back() == 2.0); + // update + lru.touch(13); + assert(lru.front() == 1.3 && lru.back() == 2.0); + // remove item + lru.pop_front(); + assert(lru.front() == 1.0 && lru.back() == 2.0); + // remove item + lru.pop_back(); + assert(lru.front() == 1.0 && lru.back() == 99); + + std::cout << "... passed\n"; +} + +int main () +{ + lru_test(); + + return 0; +}