DataSet.h
Go to the documentation of this file.00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
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
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 };
00285
00286
00287
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
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
00342
00343
00344
00345
00346
00347
00348
00349
00350
00351
00352
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
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 }
00398
00399 #endif // KEYVALUE_MNGT_DATASET_H_