[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[lmi-commits] (no subject)
From: |
Greg Chicares |
Subject: |
[lmi-commits] (no subject) |
Date: |
Fri, 29 Jul 2016 00:01:49 +0000 (UTC) |
branch: master
commit 3085b77c86dce36685a646d387d920f577c04abe
Author: Gregory W. Chicares <address@hidden>
Date: Thu Jul 28 23:21:57 2016 +0000
Add a reusable caching class for data expensively read from disk (VS)
See:
http://lists.nongnu.org/archive/html/lmi/2016-07/msg00046.html
---
Makefile.am | 1 +
cache_file_reads.hpp | 119 ++++++++++++++++++++++++++++++++++++++++++++++++++
2 files changed, 120 insertions(+)
diff --git a/Makefile.am b/Makefile.am
index 5425e8b..42d9b1c 100644
--- a/Makefile.am
+++ b/Makefile.am
@@ -1074,6 +1074,7 @@ noinst_HEADERS = \
assert_lmi.hpp \
authenticity.hpp \
basic_values.hpp \
+ cache_file_reads.hpp \
calendar_date.hpp \
callback.hpp \
catch_exceptions.hpp \
diff --git a/cache_file_reads.hpp b/cache_file_reads.hpp
new file mode 100644
index 0000000..b079e73
--- /dev/null
+++ b/cache_file_reads.hpp
@@ -0,0 +1,119 @@
+// Caching of loaded files.
+//
+// Copyright (C) 2016 Gregory W. Chicares.
+//
+// This program is free software; you can redistribute it and/or modify
+// it under the terms of the GNU General Public License version 2 as
+// published by the Free Software Foundation.
+//
+// This program is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+// GNU General Public License for more details.
+//
+// You should have received a copy of the GNU General Public License
+// along with this program; if not, write to the Free Software Foundation,
+// Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
+//
+// http://savannah.nongnu.org/projects/lmi
+// email: <address@hidden>
+// snail: Chicares, 186 Belle Woods Drive, Glastonbury CT 06033, USA
+
+#ifndef cache_file_reads_hpp
+#define cache_file_reads_hpp
+
+#include "config.hpp"
+
+#include "uncopyable_lmi.hpp"
+
+#include <boost/filesystem/operations.hpp>
+#include <boost/shared_ptr.hpp>
+
+#include <ctime> // std::time_t
+#include <map>
+#include <string>
+
+/// Cache of objects loaded from files.
+///
+/// Used for holding objects that are expensively loaded from a file in memory.
+/// For example, loading actuarial_table from an XML file is costly, so we keep
+/// loaded instances in memory until the program terminates or until the file
+/// is modified.
+///
+/// T must have a constructor that takes a single string argument, the
+/// filename, as well as the default constructor.
+template<typename T>
+class file_cache
+ :private lmi::uncopyable<file_cache<T> >
+{
+ public:
+ typedef T value_type;
+ typedef boost::shared_ptr<value_type const> value_ptr_type;
+ typedef std::string key_type;
+
+ // Return singleton instance of the cache.
+ static file_cache& instance()
+ {
+ static file_cache z;
+ return z;
+ }
+
+ // Get object corresponding to the given file, either getting it from the
+ // cache or loading from the file. Checks file's timestamp and reloads it
+ // if it was modified since the cached copy was read.
+ value_ptr_type get(key_type const& filename)
+ {
+ std::time_t const write_time = fs::last_write_time(filename);
+
+ typename map_type::iterator i = cache_.lower_bound(filename);
+ if
+ ( cache_.end() != i
+ && filename == i->first
+ && write_time == i->second.write_time
+ )
+ {
+ return i->second.data;
+ }
+
+ // create the value before calling insert() because the call may throw
+ value_ptr_type value(new value_type(filename));
+
+ // insert() doesn't update the value if the key is already present, so
+ // insert a dummy value and then modify it -- this will work for both
+ // existing and new keys.
+ i = cache_.insert(i, typename map_type::value_type(filename,
record()));
+ record& rec = i->second;
+ rec.data = value;
+ rec.write_time = write_time;
+
+ return value;
+ }
+
+ private:
+ struct record
+ {
+ value_ptr_type data;
+ std::time_t write_time;
+ };
+
+ typedef std::map<key_type,record> map_type;
+ map_type cache_;
+};
+
+/// Base class for cached types.
+/// Its only purpose is providing convenience read_from_cache() function.
+template<typename T>
+class cache_file_reads
+{
+ public:
+ typedef file_cache<T> cache_type;
+ typedef typename cache_type::value_ptr_type ptr_type;
+
+ static ptr_type read_from_cache(std::string const& filename)
+ {
+ return cache_type::instance().get(filename);
+ }
+};
+
+#endif // cache_file_reads_hpp
+