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/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
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 };
00311
00312
00313
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
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
00370
00371
00372
00373
00374
00375
00376
00377
00378
00379
00380
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
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
00427
00428
00429 template <typename ObjectType>
00430 typename value::PtrTraits<ObjectType>::Type_
00431 DataSet::build() const {
00432
00433 const Processor& processor(getProcessor());
00434
00435
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
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 }
00455
00456 #endif // KEYVALUE_MNGT_DATASET_H_