Analysis Software
Documentation for sPHENIX simulation software
 All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Macros Groups Pages
WhiteBoard.hpp
Go to the documentation of this file. Or view the newest version in sPHENIX GitHub for file WhiteBoard.hpp
1 // This file is part of the Acts project.
2 //
3 // Copyright (C) 2017-2019 CERN for the benefit of the Acts project
4 //
5 // This Source Code Form is subject to the terms of the Mozilla Public
6 // License, v. 2.0. If a copy of the MPL was not distributed with this
7 // file, You can obtain one at http://mozilla.org/MPL/2.0/.
8 
9 #pragma once
10 
12 
13 #include <algorithm>
14 #include <cstddef>
15 #include <memory>
16 #include <ostream>
17 #include <stdexcept>
18 #include <string>
19 #include <string_view>
20 #include <type_traits>
21 #include <typeinfo>
22 #include <unordered_map>
23 #include <utility>
24 #include <vector>
25 
26 namespace ActsExamples {
27 
34 class WhiteBoard {
35  public:
36  WhiteBoard(std::unique_ptr<const Acts::Logger> logger =
38  std::unordered_map<std::string, std::string> objectAliases = {});
39 
40  // A WhiteBoard holds unique elements and can not be copied
41  WhiteBoard(const WhiteBoard& other) = delete;
42  WhiteBoard& operator=(const WhiteBoard&) = delete;
43 
44  bool exists(const std::string& name) const;
45 
46  private:
52  template <typename T>
53  void add(const std::string& name, T&& object);
54 
60  template <typename T>
61  const T& get(const std::string& name) const;
62 
63  private:
65  std::vector<std::string_view> similarNames(const std::string_view& name,
66  int distThreshold,
67  std::size_t maxNumber) const;
68 
69  // type-erased value holder for move-constructible types
70  struct IHolder {
71  virtual ~IHolder() = default;
72  virtual const std::type_info& type() const = 0;
73  };
74  template <typename T,
75  typename =
77  struct HolderT : public IHolder {
79 
80  HolderT(T&& v) : value(std::move(v)) {}
81  const std::type_info& type() const override { return typeid(T); }
82  };
83 
84  std::unique_ptr<const Acts::Logger> m_logger;
85  std::unordered_map<std::string, std::shared_ptr<IHolder>> m_store;
86  std::unordered_map<std::string, std::string> m_objectAliases;
87 
88  const Acts::Logger& logger() const { return *m_logger; }
89 
90  static std::string typeMismatchMessage(const std::string& name,
91  const char* req, const char* act);
92 
93  template <typename T>
94  friend class WriteDataHandle;
95 
96  template <typename T>
97  friend class ReadDataHandle;
98 };
99 
100 } // namespace ActsExamples
101 
103  std::unique_ptr<const Acts::Logger> logger,
104  std::unordered_map<std::string, std::string> objectAliases)
105  : m_logger(std::move(logger)), m_objectAliases(std::move(objectAliases)) {}
106 
107 template <typename T>
108 inline void ActsExamples::WhiteBoard::add(const std::string& name, T&& object) {
109  if (name.empty()) {
110  throw std::invalid_argument("Object can not have an empty name");
111  }
112  if (0 < m_store.count(name)) {
113  throw std::invalid_argument("Object '" + name + "' already exists");
114  }
115  auto holder = std::make_shared<HolderT<T>>(std::forward<T>(object));
116  m_store.emplace(name, holder);
117  ACTS_VERBOSE("Added object '" << name << "' of type " << typeid(T).name());
118  if (auto it = m_objectAliases.find(name); it != m_objectAliases.end()) {
119  m_store[it->second] = holder;
120  ACTS_VERBOSE("Added alias object '" << it->second << "'");
121  }
122 }
123 
124 template <typename T>
125 inline const T& ActsExamples::WhiteBoard::get(const std::string& name) const {
126  ACTS_VERBOSE("Attempt to get object '" << name << "' of type "
127  << typeid(T).name());
128  auto it = m_store.find(name);
129  if (it == m_store.end()) {
130  const auto names = similarNames(name, 10, 3);
131 
132  std::stringstream ss;
133  if (not names.empty()) {
134  ss << ", similar ones are: [ ";
135  for (std::size_t i = 0; i < std::min(3ul, names.size()); ++i) {
136  ss << "'" << names[i] << "' ";
137  }
138  ss << "]";
139  }
140 
141  throw std::out_of_range("Object '" + name + "' does not exists" + ss.str());
142  }
143 
144  const IHolder* holder = it->second.get();
145 
146  const auto* castedHolder = dynamic_cast<const HolderT<T>*>(holder);
147  if (castedHolder == nullptr) {
148  throw std::out_of_range(
149  typeMismatchMessage(name, typeid(T).name(), holder->type().name()));
150  }
151 
152  ACTS_VERBOSE("Retrieved object '" << name << "'");
153  return castedHolder->value;
154 }
155 
157  return m_store.find(name) != m_store.end();
158 }