File indexing completed on 2025-04-19 09:13:37
0001
0002
0003
0004
0005
0006 #ifndef YODA_AnalysisObject_h
0007 #define YODA_AnalysisObject_h
0008
0009 #include "YODA/Exceptions.h"
0010 #include "YODA/Utils/StringUtils.h"
0011 #include "YODA/Config/BuildConfig.h"
0012 #include <iomanip>
0013 #include <string>
0014 #include <limits>
0015 #include <map>
0016
0017 namespace YODA {
0018
0019
0020
0021 class AnalysisObject {
0022
0023 public:
0024
0025
0026 typedef std::map<std::string, std::string> Annotations;
0027
0028
0029
0030
0031
0032
0033 AnalysisObject() { }
0034
0035
0036 AnalysisObject(const std::string& type, const std::string& path, const std::string& title="") {
0037 setAnnotation("Type", type);
0038 setPath(path);
0039 setTitle(title);
0040 }
0041
0042
0043 AnalysisObject(const std::string& type, const std::string& path,
0044 const AnalysisObject& ao, const std::string& title="") {
0045 AnalysisObject::operator = (ao);
0046 setAnnotation("Type", type);
0047 setPath(path);
0048 setTitle(title);
0049 }
0050
0051
0052
0053
0054
0055
0056
0057
0058 virtual ~AnalysisObject() { }
0059
0060
0061 virtual AnalysisObject& operator = (const AnalysisObject& ao) noexcept {
0062 for (const std::string& a : ao.annotations()) {
0063 if (a == "Type") continue;
0064 if (a == "Path" && !ao.path().length()) continue;
0065 if (a == "Title" && !ao.title().length()) continue;
0066 setAnnotation(a, ao.annotation(a));
0067 }
0068 return *this;
0069 }
0070
0071
0072 virtual AnalysisObject* newclone() const = 0;
0073
0074
0075
0076
0077
0078
0079
0080
0081
0082 virtual void reset() = 0;
0083
0084
0085
0086
0087
0088
0089
0090 virtual void _renderYODA(std::ostream& os, const int width = 13) const noexcept = 0;
0091
0092
0093 virtual void _renderFLAT(std::ostream& os, const int width = 13) const noexcept = 0;
0094
0095
0096 virtual std::string _config() const noexcept { return ""; }
0097
0098
0099
0100
0101
0102
0103
0104
0105
0106
0107 std::vector<std::string> annotations() const {
0108 std::vector<std::string> rtn;
0109 rtn.reserve(_annotations.size());
0110 for (const Annotations::value_type& kv : _annotations) rtn.push_back(kv.first);
0111 return rtn;
0112 }
0113
0114
0115
0116 bool hasAnnotation(const std::string& name) const {
0117 return _annotations.find(name) != _annotations.end();
0118 }
0119
0120
0121
0122 const std::string& annotation(const std::string& name) const {
0123 Annotations::const_iterator v = _annotations.find(name);
0124
0125 if (v == _annotations.end()) {
0126 std::string missing = "YODA::AnalysisObject: No annotation named " + name;
0127 throw AnnotationError(missing);
0128 }
0129 return v->second;
0130 }
0131
0132
0133
0134 const std::string& annotation(const std::string& name, const std::string& defaultreturn) const {
0135 Annotations::const_iterator v = _annotations.find(name);
0136 if (v != _annotations.end()) return v->second;
0137 return defaultreturn;
0138 }
0139
0140
0141
0142
0143
0144 template <typename T>
0145 const T annotation(const std::string& name) const {
0146 std::string s = annotation(name);
0147 return Utils::lexical_cast<T>(s);
0148 }
0149
0150
0151
0152
0153
0154 template <typename T>
0155 const T annotation(const std::string& name, const T& defaultreturn) const {
0156 Annotations::const_iterator v = _annotations.find(name);
0157 if (v != _annotations.end()) return Utils::lexical_cast<T>(v->second);
0158 return defaultreturn;
0159 }
0160
0161
0162
0163
0164
0165 template <typename T>
0166 void setAnnotation(const std::string& name, const T& value) {
0167 if constexpr( std::is_floating_point<T>::value ) {
0168
0169 std::stringstream ss;
0170 ss << std::setprecision(std::numeric_limits<double>::max_digits10) << std::scientific << value;
0171 setAnnotation(name, ss.str());
0172 }
0173 else if constexpr( std::is_same<T, std::string>::value ) {
0174 _annotations[name] = value;
0175 }
0176 else {
0177 _annotations[name] = Utils::lexical_cast<std::string>(value);
0178 }
0179 }
0180
0181
0182
0183 void setAnnotations(const Annotations& anns) {
0184 _annotations = anns;
0185 }
0186
0187
0188
0189
0190
0191 template <typename T>
0192 void addAnnotation(const std::string& name, const T& value) {
0193 setAnnotation(name, value);
0194 }
0195
0196
0197
0198 void rmAnnotation(const std::string& name) {
0199 _annotations.erase(name);
0200 }
0201
0202
0203
0204 void clearAnnotations() {
0205 _annotations.clear();
0206 }
0207
0208
0209
0210
0211
0212
0213
0214
0215
0216
0217 const std::string title() const {
0218 return annotation("Title", "");
0219 }
0220
0221
0222 void setTitle(const std::string& title) {
0223 setAnnotation("Title", title);
0224 }
0225
0226
0227
0228
0229
0230 const std::string path() const {
0231 const std::string p = annotation("Path", "");
0232
0233 if (p.empty()) return p;
0234
0235 return p.find("/") == 0 ? p : ("/"+p);
0236 }
0237
0238
0239
0240
0241 void setPath(const std::string& path) {
0242 const std::string p = (path.find("/") == 0) ? path : "/"+path;
0243
0244
0245
0246 setAnnotation("Path", p);
0247 }
0248
0249
0250
0251
0252 const std::string name() const {
0253 const std::string p = path();
0254 const size_t lastslash = p.rfind("/");
0255 if (lastslash == std::string::npos) return p;
0256 return p.substr(lastslash+1);
0257 }
0258
0259
0260
0261
0262 public:
0263
0264
0265
0266
0267
0268 virtual std::string type() const {
0269 return annotation("Type");
0270 }
0271
0272
0273
0274
0275
0276 virtual size_t dim() const noexcept = 0;
0277
0278
0279 virtual AnalysisObject* mkInert(const std::string& path = "",
0280 const std::string& source = "") const noexcept {
0281 (void)source;
0282 AnalysisObject* rtn = this->newclone();
0283 rtn->setPath(path);
0284 return rtn;
0285 }
0286
0287
0288
0289
0290
0291
0292
0293 virtual size_t lengthContent(bool fixed_length = false) const noexcept = 0;
0294
0295
0296 virtual std::vector<double> serializeContent(bool fixed_length = false) const noexcept = 0;
0297
0298
0299 virtual void deserializeContent(const std::vector<double>& data) = 0;
0300
0301
0302 size_t lengthMeta(const bool skipPath = true,
0303 const bool skipTitle = true) const noexcept {
0304 return 2*(_annotations.size() - skipPath - skipTitle);
0305 }
0306
0307
0308 std::vector<std::string> serializeMeta(const bool skipPath = true,
0309 const bool skipTitle = true) const noexcept {
0310
0311
0312 std::vector<std::string> rtn;
0313 rtn.reserve(2*(_annotations.size() - skipPath - skipTitle));
0314 for (const auto& item : _annotations) {
0315 if (item.first == "Type") continue;
0316 if (skipPath && item.first == "Path") continue;
0317 if (skipTitle && item.first == "Title") continue;
0318 rtn.push_back(item.first);
0319 rtn.push_back(item.second);
0320 }
0321 return rtn;
0322 }
0323
0324
0325 virtual void deserializeMeta(const std::vector<std::string>& data,
0326 const bool resetPath = false, const bool resetTitle = false) {
0327
0328 if (data.empty()) return;
0329 if (data.size() % 2)
0330 throw UserError("Expected even number of annotation elements (key-value pairs)!");
0331
0332 const std::string path = annotation("Path");
0333 const std::string type = annotation("Type");
0334 const std::string title = annotation("Title");
0335 _annotations.clear();
0336 _annotations["Type"] = type;
0337 if (!resetPath) _annotations["Path"] = path;
0338 if (!resetTitle) _annotations["Title"] = title;
0339
0340 auto itr = data.cbegin();
0341 const auto itrEnd = data.cend();
0342 while (itr != itrEnd) {
0343 const std::string key = *itr; ++itr;
0344 const std::string val = *itr; ++itr;
0345 _annotations[key] = val;
0346 }
0347 }
0348
0349
0350
0351 private:
0352
0353
0354 std::map<std::string,std::string> _annotations;
0355
0356 };
0357
0358
0359
0360 using AO = AnalysisObject;
0361
0362
0363 }
0364
0365 #endif