diff options
Diffstat (limited to 'src/ModuleCache.cc')
-rw-r--r-- | src/ModuleCache.cc | 105 |
1 files changed, 105 insertions, 0 deletions
diff --git a/src/ModuleCache.cc b/src/ModuleCache.cc new file mode 100644 index 0000000..e974a03 --- /dev/null +++ b/src/ModuleCache.cc @@ -0,0 +1,105 @@ +#include "ModuleCache.h" +#include "module.h" +#include "printutils.h" +#include "openscad.h" + +#include "boosty.h" +#include <boost/format.hpp> +#include <boost/filesystem.hpp> +#include <boost/foreach.hpp> + +#include <stdio.h> +#include <fstream> +#include <sstream> +#include <time.h> +#include <sys/stat.h> + +/*! + FIXME: Implement an LRU scheme to avoid having an ever-growing module cache +*/ + +ModuleCache *ModuleCache::inst = NULL; + +static bool is_modified(const std::string &filename, const time_t &mtime) +{ + struct stat st; + memset(&st, 0, sizeof(struct stat)); + stat(filename.c_str(), &st); + return (st.st_mtime > mtime); +} + +Module *ModuleCache::evaluate(const std::string &filename) +{ + Module *lib_mod = NULL; + + // Create cache ID + struct stat st; + memset(&st, 0, sizeof(struct stat)); + stat(filename.c_str(), &st); + + std::string cache_id = str(boost::format("%x.%x") % st.st_mtime % st.st_size); + + // Lookup in cache + if (this->entries.find(filename) != this->entries.end() && + this->entries[filename].cache_id == cache_id) { +#ifdef DEBUG + PRINTB("Using cached library: %s (%s)", filename % cache_id); +#endif + lib_mod = &(*this->entries[filename].module); + + BOOST_FOREACH(const Module::IncludeContainer::value_type &item, lib_mod->includes) { + if (is_modified(item.first, item.second)) { + lib_mod = NULL; + break; + } + } + } + + // If cache lookup failed (non-existing or old timestamp), compile module + if (!lib_mod) { +#ifdef DEBUG + if (this->entries.find(filename) != this->entries.end()) { + PRINTB("Recompiling cached library: %s (%s)", filename % cache_id); + } + else { + PRINTB("Compiling library '%s'.", filename); + } +#endif + + std::ifstream ifs(filename.c_str()); + if (!ifs.is_open()) { + PRINTB("WARNING: Can't open library file '%s'\n", filename); + return NULL; + } + std::string text((std::istreambuf_iterator<char>(ifs)), std::istreambuf_iterator<char>()); + + print_messages_push(); + + cache_entry e = { NULL, cache_id }; + if (this->entries.find(filename) != this->entries.end()) { + delete this->entries[filename].module; + } + this->entries[filename] = e; + + std::string pathname = boosty::stringy(fs::path(filename).parent_path()); + lib_mod = dynamic_cast<Module*>(parse(text.c_str(), pathname.c_str(), 0)); + + if (lib_mod) { + this->entries[filename].module = lib_mod; + } else { + this->entries.erase(filename); + } + + print_messages_pop(); + } + + if (lib_mod) lib_mod->handleDependencies(); + + return lib_mod; +} + +void ModuleCache::clear() +{ + this->entries.clear(); +} + |