From: James Turner Date: Fri, 21 Sep 2012 09:17:16 +0000 (+0100) Subject: Cached joystick config loading. X-Git-Url: https://git.mxchange.org/?a=commitdiff_plain;h=6e7ac46751fc10fd03d1637a63a1ca5beade657d;p=flightgear.git Cached joystick config loading. Avoid parsing all the joystick configs every launch. --- diff --git a/src/Input/FGDeviceConfigurationMap.cxx b/src/Input/FGDeviceConfigurationMap.cxx index b4b6b1baf..b27d6816c 100644 --- a/src/Input/FGDeviceConfigurationMap.cxx +++ b/src/Input/FGDeviceConfigurationMap.cxx @@ -28,55 +28,113 @@ #include "FGDeviceConfigurationMap.hxx" +#include + #include #include +#include + #include
+#include using simgear::PropertyList; +using std::string; -FGDeviceConfigurationMap::FGDeviceConfigurationMap( const char * relative_path, SGPropertyNode_ptr aBase, const char * aChildname ) : - base(aBase), - childname(aChildname) +FGDeviceConfigurationMap::FGDeviceConfigurationMap( const string& relative_path) { - int index = 1000; - scan_dir( SGPath(globals->get_fg_home(), relative_path), &index); - scan_dir( SGPath(globals->get_fg_root(), relative_path), &index); + scan_dir( SGPath(globals->get_fg_home(), relative_path)); + scan_dir( SGPath(globals->get_fg_root(), relative_path)); +} - PropertyList childNodes = base->getChildren(childname); - for (int k = (int)childNodes.size() - 1; k >= 0; k--) { - SGPropertyNode *n = childNodes[k]; - PropertyList names = n->getChildren("name"); - if (names.size() ) // && (n->getChildren("axis").size() || n->getChildren("button").size())) - for (unsigned int j = 0; j < names.size(); j++) - (*this)[names[j]->getStringValue()] = n; +FGDeviceConfigurationMap::~FGDeviceConfigurationMap() +{ +} + +SGPropertyNode_ptr +FGDeviceConfigurationMap::configurationForDeviceName(const std::string& name) +{ + NamePathMap::iterator it = namePathMap.find(name); + if (it == namePathMap.end()) { + return SGPropertyNode_ptr(); + } + + SGPropertyNode_ptr result(new SGPropertyNode); + try { + readProperties(it->second.str(), result); + result->setStringValue("source", it->second.c_str()); + } catch (sg_exception& e) { + SG_LOG(SG_INPUT, SG_WARN, "parse failure reading:" << it->second); + return NULL; } + return result; } -FGDeviceConfigurationMap::~FGDeviceConfigurationMap() +bool FGDeviceConfigurationMap::hasConfiguration(const std::string& name) const { - // Ensure that the children don't hang around when deleted, as if - // re-created, we need to ensure that the set of names doesn't contain - // any unexpected history. - base->removeChildren( childname, false ); + return namePathMap.find(name) != namePathMap.end(); } -void FGDeviceConfigurationMap::scan_dir(const SGPath & path, int *index) +void FGDeviceConfigurationMap::scan_dir(const SGPath & path) { + if (!path.exists()) + return; + simgear::Dir dir(path); simgear::PathList children = dir.children(simgear::Dir::TYPE_FILE | simgear::Dir::TYPE_DIR | simgear::Dir::NO_DOT_OR_DOTDOT); - - for (unsigned int c=0; cgetChild(childname, (*index)++, true); - readProperties(path.str(), n); - n->setStringValue("source", path.c_str()); - } - } + if (cache->isCachedFileModified(path)) { + refreshCacheForFile(path); + } else { + readCachedData(path); + } // of cached file stamp is valid + } // of child is a file with '.xml' extension + } // of directory children iteration } +void FGDeviceConfigurationMap::readCachedData(const SGPath& path) +{ + flightgear::NavDataCache* cache = flightgear::NavDataCache::instance(); + NamePathMap::iterator it; + BOOST_FOREACH(string s, cache->readStringListProperty(path.str())) { + // important - only insert if not already present. This ensures + // user configs can override those in the base package, since they are + // searched first. + it = namePathMap.find(s); + if (it == namePathMap.end()) { + namePathMap.insert(std::make_pair(s, path)); + } + } // of cached names iteration +} +void FGDeviceConfigurationMap::refreshCacheForFile(const SGPath& path) +{ + SG_LOG(SG_INPUT, SG_DEBUG, "Reading joystick file " << path.str()); + SGPropertyNode_ptr n(new SGPropertyNode); + try { + readProperties(path.str(), n); + } catch (sg_exception& e) { + SG_LOG(SG_INPUT, SG_WARN, "parse failure reading:" << path); + return; + } + + NamePathMap::iterator it; + string_list names; + BOOST_FOREACH(SGPropertyNode* nameProp, n->getChildren("name")) { + names.push_back(nameProp->getStringValue()); + // same comment as readCachedData: only insert if not already present + it = namePathMap.find(names.back()); + if (it == namePathMap.end()) { + namePathMap.insert(std::make_pair(names.back(), path)); + } + } + + flightgear::NavDataCache* cache = flightgear::NavDataCache::instance(); + cache->stampCacheFile(path); + cache->writeStringListProperty(path.str(), names); +} diff --git a/src/Input/FGDeviceConfigurationMap.hxx b/src/Input/FGDeviceConfigurationMap.hxx index 6a6aceae3..283973d28 100644 --- a/src/Input/FGDeviceConfigurationMap.hxx +++ b/src/Input/FGDeviceConfigurationMap.hxx @@ -30,19 +30,28 @@ #endif #include +#include #include -class SGPath; - -class FGDeviceConfigurationMap : public std::map { +class FGDeviceConfigurationMap +{ public: - FGDeviceConfigurationMap ( const char * relative_path, SGPropertyNode_ptr base, const char * childname ); + FGDeviceConfigurationMap ( const std::string& relative_path); virtual ~FGDeviceConfigurationMap(); + + SGPropertyNode_ptr configurationForDeviceName(const std::string& name); + + bool hasConfiguration(const std::string& name) const; private: - void scan_dir(const SGPath & path, int *index); - SGPropertyNode_ptr base; - const char * childname; + void scan_dir(const SGPath & path); + + void readCachedData(const SGPath& path); + void refreshCacheForFile(const SGPath& path); + + typedef std::map NamePathMap; +// mapping from joystick name to XML configuration file path + NamePathMap namePathMap; }; #endif diff --git a/src/Input/FGEventInput.cxx b/src/Input/FGEventInput.cxx index 4a53a63d0..a6db87b31 100644 --- a/src/Input/FGEventInput.cxx +++ b/src/Input/FGEventInput.cxx @@ -294,7 +294,7 @@ void FGInputDevice::SetName( string name ) const char * FGEventInput::PROPERTY_ROOT = "/input/event"; FGEventInput::FGEventInput() : - configMap( "Input/Event", fgGetNode( PROPERTY_ROOT, true ), "device-named" ) + configMap( "Input/Event") { } @@ -329,7 +329,7 @@ unsigned FGEventInput::AddDevice( FGInputDevice * inputDevice ) SGPropertyNode_ptr deviceNode = NULL; // look for configuration in the device map - if( configMap.count( inputDevice->GetName() ) > 0 ) { + if ( configMap.hasConfiguration( inputDevice->GetName() ) ) { // found - copy to /input/event/device[n] // find a free index @@ -347,7 +347,7 @@ unsigned FGEventInput::AddDevice( FGInputDevice * inputDevice ) deviceNode = baseNode->getNode( "device", index, true ); // and copy the properties from the configuration tree - copyProperties( configMap[ inputDevice->GetName() ], deviceNode ); + copyProperties( configMap.configurationForDeviceName(inputDevice->GetName()), deviceNode ); } diff --git a/src/Input/FGJoystickInput.cxx b/src/Input/FGJoystickInput.cxx index 046106abe..e9ecc33ee 100644 --- a/src/Input/FGJoystickInput.cxx +++ b/src/Input/FGJoystickInput.cxx @@ -91,7 +91,7 @@ void FGJoystickInput::_remove(bool all) for (int i = 0; i < MAX_JOYSTICKS; i++) { // do not remove predefined joysticks info on reinit - if ((all)||(!bindings[i].predefined)) + if (all || (!bindings[i].predefined)) js_nodes->removeChild("js", i, false); if (bindings[i].js) delete bindings[i].js; @@ -106,7 +106,7 @@ void FGJoystickInput::init() SGPropertyNode_ptr js_nodes = fgGetNode("/input/joysticks", true); status_node = fgGetNode("/devices/status/joysticks", true); - FGDeviceConfigurationMap configMap("Input/Joysticks", js_nodes, "js-named"); + FGDeviceConfigurationMap configMap("Input/Joysticks"); for (int i = 0; i < MAX_JOYSTICKS; i++) { jsJoystick * js = new jsJoystick(i); @@ -128,11 +128,12 @@ void FGJoystickInput::init() SG_LOG(SG_INPUT, SG_INFO, "Looking for bindings for joystick \"" << name << '"'); SGPropertyNode_ptr named; - if ((named = configMap[name])) { + if (configMap.hasConfiguration(name)) { + named = configMap.configurationForDeviceName(name); string source = named->getStringValue("source", "user defined"); SG_LOG(SG_INPUT, SG_INFO, "... found joystick: " << source); - } else if ((named = configMap["default"])) { + } else if ((named = configMap.configurationForDeviceName("default"))) { string source = named->getStringValue("source", "user defined"); SG_LOG(SG_INPUT, SG_INFO, "No config found for joystick \"" << name << "\"\nUsing default: \"" << source << '"'); diff --git a/src/Navaids/NavDataCache.cxx b/src/Navaids/NavDataCache.cxx index 3506d64fe..5737b7972 100644 --- a/src/Navaids/NavDataCache.cxx +++ b/src/Navaids/NavDataCache.cxx @@ -423,7 +423,7 @@ public: void prepareQueries() { clearProperty = prepare("DELETE FROM properties WHERE key=?1"); - writePropertyMulti = prepare("INSERT INTO properties (key, value) VALUES(?,?)"); + writePropertyMulti = prepare("INSERT INTO properties (key, value) VALUES(?1,?2)"); #define POSITIONED_COLS "rowid, type, ident, name, airport, lon, lat, elev_m, octree_node" #define AND_TYPED "AND type>=?2 AND type <=?3" @@ -1064,7 +1064,7 @@ string_list NavDataCache::readStringListProperty(const string& key) sqlite_bind_stdstring(d->readPropertyQuery, 1, key); string_list result; while (d->stepSelect(d->readPropertyQuery)) { - result.push_back((char*) sqlite3_column_text(d->readPropertyQuery, 1)); + result.push_back((char*) sqlite3_column_text(d->readPropertyQuery, 0)); } return result; @@ -1076,9 +1076,9 @@ void NavDataCache::writeStringListProperty(const string& key, const string_list& sqlite_bind_stdstring(d->clearProperty, 1, key); d->execUpdate(d->clearProperty); - sqlite_bind_stdstring(d->writePropertyMulti, 1, key); BOOST_FOREACH(string value, values) { d->reset(d->writePropertyMulti); + sqlite_bind_stdstring(d->writePropertyMulti, 1, key); sqlite_bind_stdstring(d->writePropertyMulti, 2, value); d->execInsert(d->writePropertyMulti); }