DataSet.h

Go to the documentation of this file.
00001 /***************************************************************************
00002  *
00003  * Copyright (C) 2009-2010 Cassio Neri Moreira
00004  *
00005  * This file is part of the KeyValue library.
00006  *
00007  * The KeyValue library is free software; you can redistribute it and/or
00008  * modify it under the terms of the GNU General Public License as published
00009  * by the Free Software Foundation, either version 3 of the License, or (at
00010  * your option) any later version.
00011  *
00012  * The KeyValue library is distributed in the hope that it will be useful,
00013  * but WITHOUT ANY WARRANTY; without even the implied warranty of
00014  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General
00015  * Public License for more details.
00016  *
00017  * You should have received a copy of the GNU General Public License along
00018  * with KeyValue. If not, see <http://www.gnu.org/licenses/>.
00019  *
00020  **************************************************************************/
00021 
00028 #ifndef KEYVALUE_MNGT_DATASET_H_
00029 #define KEYVALUE_MNGT_DATASET_H_
00030 
00031 #include <map>
00032 #include <typeinfo>
00033 
00034 #include <boost/any.hpp>
00035 #include <boost/utility.hpp>
00036 #include <boost/weak_ptr.hpp>
00037 
00038 #include "keyvalue/extern/String.h"
00039 #include "keyvalue/extern/SharedPtr.h"
00040 #include "keyvalue/key/Key.h"
00041 #include "keyvalue/value/Result.h"
00042 #include "keyvalue/value/TypeName.h"
00043 #include "keyvalue/value/Value.h"
00044 #include "keyvalue/sys/exception/Exception.h"
00045 
00046 #ifndef NDEBUG
00047 #include "keyvalue/sys/logger/GlobalLogger.h"
00048 #endif
00049 
00050 namespace keyvalue {
00051 
00052 // Forward declaration
00053 class Processor;
00054 
00060 class DataSet: private boost::noncopyable {
00061 
00062 public:
00063 
00069   explicit
00070   DataSet(const string& name);
00071 
00077   string
00078   getName() const;
00079 
00086   void
00087   add(const string& key, const value::Value& value);
00088 
00123   template<typename KeyType>
00124   typename KeyType::OutputType_*
00125   find(const KeyType& key) const;
00126 
00136   template<typename KeyType>
00137   typename KeyType::OutputType_
00138   getValue(const KeyType& key) const;
00139 
00153   value::Result
00154   process() const;
00155 
00172   value::Result
00173   process(const Processor& processor) const;
00174 
00192   bool
00193   mustUpdate() const;
00194 
00198   friend std::ostream&
00199   operator<<(std::ostream& os, const DataSet& dataSet);
00200 
00201 private:
00202 
00210   struct Record {
00211 
00212     typedef boost::weak_ptr<Record> WeakPtr;
00213 
00214     explicit
00215     Record(const value::Value& rawValue);
00216 
00217     Record(WeakPtr next, WeakPtr driver);
00218 
00219     value::Value    rawValue_;
00220     bool            isBusy_;
00221     WeakPtr         next_;
00222     WeakPtr         driver_;
00223     boost::any      cache_;
00224     std::type_info* keyType_;
00225   };
00226 
00235   struct Graph {
00236 
00237     Graph();
00238 
00239     Graph(shared_ptr<Record> first, shared_ptr<Record> last,
00240       bool hasChanged);
00241 
00242     shared_ptr<Record>  first_;
00243     shared_ptr<Record>  last_;
00244     bool                hasChanged_;
00245   };
00246 
00247   class CircularReference : public RuntimeError {
00248   };
00249 
00267   Graph
00268   getGraph(const string& key, bool start = true) const;
00269 
00270   Graph
00271   getGraph(shared_ptr<Record> first, const string& key) const;
00272 
00273   value::Result
00274   doProcess(const Processor& processor) const;
00275 
00276   typedef std::map<string, shared_ptr<Record> > MapType_;
00277   typedef MapType_::value_type                  ValueType_;
00278   string                                        name_;
00279 
00280   mutable MapType_                              map_;
00281   mutable bool                                  mustUpdate_;
00282   mutable value::Result                         result_;
00283 
00284 }; // class DataSet
00285 
00286 /*--------------------------------------------------------------------------
00287  * DataSet::find()
00288  *------------------------------------------------------------------------*/
00289 
00290 template<typename KeyType>
00291 typename KeyType::OutputType_*
00292 DataSet::find(const KeyType& key) const {
00293 
00294   typedef typename KeyType::OutputType_ OutputType;
00295 
00300   Graph graph(getGraph(key.getName()));
00301   if (!graph.last_)
00302     return static_cast<OutputType*>(0);
00303 
00304   // Syntactic sugar.
00305   shared_ptr<Record>& last(graph.last_);
00306 
00311   if (KeyType::isBasicOrEnum_) {
00312     if (!graph.hasChanged_ && &typeid(KeyType) == last->keyType_) {
00313 #ifndef NDEBUG
00314       logger::GlobalLogger::getInstance().log(Debug(10) & "Returning "
00315         "cached value for key '" & key.getName() & "'.");
00316 #endif
00317       return boost::any_cast<OutputType>(&last->cache_);
00318     }
00319     mustUpdate_ = true;
00320   }
00321 
00326   typedef typename KeyType::InputType_ InputType;
00327 
00328   const InputType* container(last->rawValue_.get<InputType>());
00329 
00330   if (!container)
00331     throw RuntimeError() & "Value for key '" & key.getName() & "' in "
00332       "data set '" & name_ & "' must be a " &
00333       value::TypeName<InputType>::value_ & "!";
00334 
00339   key.checkInput(*container);
00340 
00341   // If execution gets here, then the memoization above didn't work. In
00342   // particular:
00343   //
00344   // (1) If the output container element type is a basic type, then the
00345   // cached value (if any) is out of date and must be recalculated.
00346   //
00347   // (2) If the output container element type is an object type, then even
00348   // if the raw value (a container of object names) haven't changed since
00349   // last time this key was processed, the objects themselves could have
00350   // been rebuilt. Hence, the cached value (if any) might be out of date.
00351   // To check that, we provide the cached value to the container converter
00352   // which compares old objects with new ones.
00353 
00354   OutputType* cache(0);
00355   if (!KeyType::isBasicOrEnum_&& &typeid(KeyType) == last->keyType_)
00356     cache = boost::any_cast<OutputType>(&last->cache_);
00357 
00358   typename KeyType::ConverterType_ converter(*container, cache);
00359 
00360   while (!converter.isEmpty()) {
00361     converter.insert(key.map(converter.pop()));
00362     key.checkSoFar(converter);
00363   }
00364 
00365   OutputType output(converter.getOutput());
00366   key.checkOutput(output);
00367 
00368   mustUpdate_ = mustUpdate_ || converter.mustUpdate();
00369 
00374   last->cache_   = output;
00375   last->keyType_ = const_cast<std::type_info*>(&typeid(KeyType));
00376 
00377   return boost::any_cast<OutputType>(&last->cache_);
00378 }
00379 
00380 /*--------------------------------------------------------------------------
00381  * DataSet::getValue()
00382  *------------------------------------------------------------------------*/
00383 
00384 template<typename KeyType>
00385 typename KeyType::OutputType_
00386 DataSet::getValue(const KeyType& key) const {
00387 
00388   typename KeyType::OutputType_* result(find(key));
00389 
00390   if (result)
00391     return *result;
00392 
00393   throw RuntimeError() & "Cannot resolve key '" & key.getName() & "' for "
00394     "data set '" & name_ & "'!";
00395 }
00396 
00397 } // namespace keyvalue
00398 
00399 #endif // KEYVALUE_MNGT_DATASET_H_

Generated on Sat Mar 20 15:08:29 2010 for KeyValue by  doxygen 1.6.1