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
00022
00023
00024
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/value/Result.h"
00048 #include "keyvalue/value/TypeName.h"
00049 #include "keyvalue/value/Value.h"
00050 #include "keyvalue/sys/exception/Exception.h"
00051
00052 #ifndef NDEBUG
00053 #include "keyvalue/sys/logger/Logger.h"
00054 #include "keyvalue/util/Global.h"
00055 #endif
00056
00057 namespace keyvalue {
00058
00059
00060 class Processor;
00061
00067 class DataSet: private boost::noncopyable {
00068
00069 public:
00070
00076 explicit
00077 DataSet(const string& name);
00078
00084 string
00085 getName() const;
00086
00093 void
00094 add(const string& key, const value::Value& value);
00095
00129 template<typename KeyType>
00130 typename KeyType::OutputType_*
00131 find(const KeyType& key) const;
00132
00142 template<typename KeyType>
00143 typename KeyType::OutputType_
00144 getValue(const KeyType& key) const;
00145
00158 value::Result
00159 process() const;
00160
00178 value::Result
00179 process(const Processor& processor) const;
00180
00198 bool
00199 mustUpdate() const;
00200
00204 friend std::ostream&
00205 operator<<(std::ostream& os, const DataSet& dataSet);
00206
00207 private:
00208
00216 struct Record {
00217
00218 typedef boost::weak_ptr<Record> WeakPtr;
00219
00220 explicit
00221 Record(const value::Value& rawValue);
00222
00223 Record(WeakPtr next, WeakPtr driver);
00224
00225 value::Value rawValue_;
00226 bool isBusy_;
00227 WeakPtr next_;
00228 WeakPtr driver_;
00229 boost::any cache_;
00230 std::type_info* keyType_;
00231 };
00232
00241 struct Graph {
00242
00243 Graph();
00244
00245 Graph(shared_ptr<Record> first, shared_ptr<Record> last,
00246 bool hasChanged);
00247
00248 shared_ptr<Record> first_;
00249 shared_ptr<Record> last_;
00250 bool hasChanged_;
00251 };
00252
00253 class CircularReference : public RuntimeError {
00254 };
00255
00273 Graph
00274 getGraph(const string& key, bool start = true) const;
00275
00276 Graph
00277 getGraph(shared_ptr<Record> first, const string& key) const;
00278
00279 value::Result
00280 doProcess(const Processor& processor) const;
00281
00282 typedef std::map<string, shared_ptr<Record> > MapType_;
00283 typedef MapType_::value_type ValueType_;
00284 string name_;
00285
00286 mutable MapType_ map_;
00287 mutable bool mustUpdate_;
00288 mutable value::Result result_;
00289
00290 };
00291
00292
00293
00294
00295
00296 template<typename KeyType>
00297 typename KeyType::OutputType_*
00298 DataSet::find(const KeyType& key) const {
00299
00300 typedef typename KeyType::OutputType_ OutputType;
00301
00306 Graph graph(getGraph(key.getName()));
00307 if (!graph.last_)
00308 return static_cast<OutputType*>(0);
00309
00310
00311 shared_ptr<Record>& last(graph.last_);
00312
00317 if (KeyType::isBasicOrEnum) {
00318 if (!graph.hasChanged_ && &typeid(KeyType) == last->keyType_) {
00319
00320 #ifndef NDEBUG
00321 util::Global<logger::Logger>::get()->log(Debug(10) & "Returning "
00322 "cached value for key '" & key.getName() & "'.");
00323 #endif
00324
00325 return boost::any_cast<OutputType>(&last->cache_);
00326 }
00327 mustUpdate_ = true;
00328 }
00329
00334 typedef typename KeyType::InputType_ InputType;
00335
00336 const InputType* container(last->rawValue_.get<InputType>());
00337
00338 if (!container)
00339 throw RuntimeError() & "Value for key '" & key.getName() & "' in "
00340 "data set '" & name_ & "' must be a " &
00341 value::TypeName<InputType>::value_ & "!";
00342
00347 key.checkInput(*container);
00348
00349
00350
00351
00352
00353
00354
00355
00356
00357
00358
00359
00360
00361
00362 OutputType* cache(0);
00363 if (!KeyType::isBasicOrEnum && &typeid(KeyType) == last->keyType_)
00364 cache = boost::any_cast<OutputType>(&last->cache_);
00365
00366 typename KeyType::ConverterType_ converter(*container, cache);
00367
00368 while (!converter.isEmpty()) {
00369 converter.insert(key.map(converter.pop()));
00370 key.checkSoFar(converter);
00371 }
00372
00373 OutputType output(converter.getOutput());
00374 key.checkOutput(output);
00375
00376 mustUpdate_ = mustUpdate_ || converter.mustUpdate();
00377
00382 last->cache_ = output;
00383 last->keyType_ = const_cast<std::type_info*>(&typeid(KeyType));
00384
00385 return boost::any_cast<OutputType>(&last->cache_);
00386 }
00387
00388
00389
00390
00391
00392 template<typename KeyType>
00393 typename KeyType::OutputType_
00394 DataSet::getValue(const KeyType& key) const {
00395
00396 typename KeyType::OutputType_* result(find(key));
00397
00398 if (result)
00399 return *result;
00400
00401 throw RuntimeError() & "Cannot resolve key '" & key.getName() & "' for "
00402 "data set '" & name_ & "'!";
00403 }
00404
00405 }
00406
00407 #endif // KEYVALUE_MNGT_DATASET_H_