DataSet.h

Go to the documentation of this file.
00001 /***************************************************************************
00002  *
00003  * Copyright (C) 2009-2011 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  * If you modify this library, or any covered work, by linking or combining
00021  * it with Excel (or a modified version of that program), containing parts
00022  * covered by the terms of End-User License Agreement for Microsoft
00023  * Software, the licensors of KeyValue grant you additional permission to
00024  * convey the resulting work.
00025  *
00026  **************************************************************************/
00027 
00034 #ifndef KEYVALUE_MNGT_DATASET_H_
00035 #define KEYVALUE_MNGT_DATASET_H_
00036 
00037 #include <map>
00038 #include <typeinfo>
00039 
00040 #include <boost/any.hpp>
00041 #include <boost/utility.hpp>
00042 #include <boost/weak_ptr.hpp>
00043 
00044 #include "keyvalue/extern/String.h"
00045 #include "keyvalue/extern/SharedPtr.h"
00046 #include "keyvalue/key/Key.h"
00047 #include "keyvalue/mngt/AbstractBuilder.h"
00048 #include "keyvalue/value/ObjectPtr.h"
00049 #include "keyvalue/value/Result.h"
00050 #include "keyvalue/value/TypeName.h"
00051 #include "keyvalue/value/Value.h"
00052 #include "keyvalue/sys/exception/Exception.h"
00053 
00054 #ifndef NDEBUG
00055 #include "keyvalue/sys/logger/Logger.h"
00056 #include "keyvalue/util/Global.h"
00057 #endif
00058 
00059 namespace keyvalue {
00060 
00061 // Forward declaration
00062 class Processor;
00063 
00069 class DataSet: private ::boost::noncopyable {
00070 
00071 public:
00072 
00078   explicit
00079   DataSet(const string& name);
00080 
00086   string
00087   getName() const;
00088 
00095   void
00096   add(const string& key, const value::Value& value);
00097 
00130   template <typename KeyType>
00131   typename KeyType::OutputType_*
00132   find(const KeyType& key) const;
00133 
00143   template <typename KeyType>
00144   typename KeyType::OutputType_
00145   getValue(const KeyType& key) const;
00146 
00159   value::Result
00160   process() const;
00161 
00174   template <typename ObjectType>
00175   typename value::PtrTraits<ObjectType>::Type_
00176   build() const;
00177 
00193   bool
00194   mustUpdate() const;
00195 
00199   friend ::std::ostream&
00200   operator<<(::std::ostream& os, const DataSet& dataSet);
00201 
00202 private:
00203 
00211   struct Record {
00212 
00213     typedef ::boost::weak_ptr<Record> WeakPtr;
00214 
00215     explicit
00216     Record(const value::Value& rawValue);
00217 
00218     Record(WeakPtr next, WeakPtr driver);
00219 
00220     value::Value      rawValue_;
00221     bool              isBusy_;
00222     WeakPtr           next_;
00223     WeakPtr           driver_;
00224     ::boost::any      cache_;
00225     ::std::type_info* keyType_;
00226   };
00227 
00236   struct Graph {
00237 
00238     Graph();
00239 
00240     Graph(shared_ptr<Record> first, shared_ptr<Record> last,
00241       bool hasChanged);
00242 
00243     shared_ptr<Record>  first_;
00244     shared_ptr<Record>  last_;
00245     bool                hasChanged_;
00246   };
00247 
00248   class CircularReference : public RuntimeError {
00249   };
00250 
00268   Graph
00269   getGraph(const string& key, bool start = true) const;
00270 
00271   Graph
00272   getGraph(shared_ptr<Record> first, const string& key) const;
00273 
00286   const Processor&
00287   getProcessor() const;
00288 
00299   value::Result
00300   process(const Processor& processor) const;
00301 
00302   typedef ::std::map<string, shared_ptr<Record> > MapType_;
00303   typedef MapType_::value_type                    ValueType_;
00304   string                                          name_;
00305 
00306   mutable MapType_                                map_;
00307   mutable bool                                    mustUpdate_;
00308   mutable value::Result                           result_;
00309 
00310 }; // class DataSet
00311 
00312 /*--------------------------------------------------------------------------
00313  * DataSet::find()
00314  *------------------------------------------------------------------------*/
00315 
00316 template <typename KeyType>
00317 typename KeyType::OutputType_*
00318 DataSet::find(const KeyType& key) const {
00319 
00320   typedef typename KeyType::OutputType_ OutputType;
00321 
00326   Graph graph(getGraph(key.getName()));
00327   if (!graph.last_)
00328     return static_cast<OutputType*>(0);
00329 
00330   // Syntactic sugar.
00331   shared_ptr<Record>& last(graph.last_);
00332 
00337   if (KeyType::isBasicOrEnum) {
00338     if (!graph.hasChanged_ && &typeid(KeyType) == last->keyType_) {
00339 
00340       #ifndef NDEBUG
00341       util::Global<logger::Logger>::get()->log(Debug(10) & "Returning "
00342         "cached value for key '" & key.getName() & "'.");
00343       #endif
00344 
00345       return ::boost::any_cast<OutputType>(&last->cache_);
00346     }
00347     mustUpdate_ = true;
00348   }
00349 
00354   typedef typename KeyType::InputType_ InputType;
00355 
00356   const InputType* container(last->rawValue_.get<InputType>());
00357 
00358   if (!container)
00359     throw RuntimeError() & "Value for key '" & key.getName() & "' in "
00360       "data set '" & name_ & "' must be a " &
00361       value::TypeName<InputType>::value_ & "!";
00362 
00367   key.checkInput(*container);
00368 
00369   // If execution gets here, then the memoization above didn't work. In
00370   // particular:
00371   //
00372   // (1) If the output container element type is a basic type, then the
00373   // cached value (if any) is out of date and must be recalculated.
00374   //
00375   // (2) If the output container element type is an object type, then even
00376   // if the raw value (a container of object names) haven't changed since
00377   // last time this key was processed, the objects themselves could have
00378   // been rebuilt. Hence, the cached value (if any) might be out of date.
00379   // To check that, we provide the cached value to the container converter
00380   // which compares old objects with new ones.
00381 
00382   OutputType* cache(0);
00383   if (!KeyType::isBasicOrEnum && &typeid(KeyType) == last->keyType_)
00384     cache = ::boost::any_cast<OutputType>(&last->cache_);
00385 
00386   typename KeyType::ConverterType_ converter(*container, cache);
00387 
00388   while (!converter.isEmpty()) {
00389     converter.insert(key.map(converter.pop()));
00390     key.checkSoFar(converter);
00391   }
00392 
00393   OutputType output(converter.getOutput());
00394   key.checkOutput(output);
00395 
00396   mustUpdate_ = mustUpdate_ || converter.mustUpdate();
00397 
00402   last->cache_   = output;
00403   last->keyType_ = const_cast< ::std::type_info*>(&typeid(KeyType));
00404 
00405   return ::boost::any_cast<OutputType>(&last->cache_);
00406 }
00407 
00408 /*--------------------------------------------------------------------------
00409  * DataSet::getValue()
00410  *------------------------------------------------------------------------*/
00411 
00412 template <typename KeyType>
00413 typename KeyType::OutputType_
00414 DataSet::getValue(const KeyType& key) const {
00415 
00416   typename KeyType::OutputType_* result(find(key));
00417 
00418   if (result)
00419     return *result;
00420 
00421   throw RuntimeError() & "Cannot resolve key '" & key.getName() & "' for "
00422     "data set '" & name_ & "'!";
00423 }
00424 
00425 /*--------------------------------------------------------------------------
00426  * DataSet::build()
00427  *------------------------------------------------------------------------*/
00428 
00429 template <typename ObjectType>
00430 typename value::PtrTraits<ObjectType>::Type_
00431 DataSet::build() const {
00432 
00433   const Processor& processor(getProcessor());
00434 
00435   // Checks if processor is a builder.
00436   const AbstractBuilder*
00437     builder(dynamic_cast<const AbstractBuilder*>(&processor));
00438 
00439   if (!builder)
00440     throw RuntimeError() & "Data set '" & name_ & "' is supposed to "
00441       "define an object but its processor '" & processor.getName() &
00442       "' is not a builder.";
00443 
00444   // Checks if builder can build ObjectType
00445   if (!builder->canBuild<ObjectType>())
00446     throw RuntimeError() & "Data set '" & name_ & "' asks for builder '" &
00447       builder->getName() & "' which cannot build the required type.";
00448 
00449   value::Result result(process(processor));
00450   value::ObjectPtr prt(result.getObjectPtr());
00451   return prt.cast<ObjectType>();
00452 }
00453 
00454 } // namespace keyvalue
00455 
00456 #endif // KEYVALUE_MNGT_DATASET_H_