otsdaq-mu2e-stm  5.02.01
operations_base.hh
1 #ifndef OPERATIONS_BASE_HH
2 #define OPERATIONS_BASE_HH
3 
4 #include <functional>
5 #include <iostream>
6 #include <memory>
7 #include <string>
8 #include <unordered_map>
9 #include <variant>
10 
11 // Adjust these includes to match your project layout
12 #include "Mu2e-STMDAQ/buffers/data_struct.hh"
13 
14 // -----------------------------------------------------------------------------
15 // Abstract base for all operations
16 // -----------------------------------------------------------------------------
18 public:
19  virtual ~OperationBase() = default;
20 
21  // OperationManager calls this with an operation name and buffer
22  virtual void execute(const std::string& operation_name,
23  std::shared_ptr<DataStruct>& buffer) = 0;
24 
25  // Optional: operation can be executed with a second buffer as well
26  virtual void execute(const std::string& operation_name,
27  std::shared_ptr<DataStruct>& buffer,
28  std::shared_ptr<DataStruct>& prev_buffer) = 0;
29 
30 
31  virtual bool requires_two_buffers(const std::string& methodName) const = 0;
32 
33 };
34 
35 using op1 = std::function<void(std::shared_ptr<DataStruct>&)>;
36 using op2 = std::function<void(std::shared_ptr<DataStruct>&,
37  std::shared_ptr<DataStruct>&)>;
38 using op_any = std::variant<op1, op2>;
39 
40 // -----------------------------------------------------------------------------
41 // Operation map + a shared execute() implementation
42 // -----------------------------------------------------------------------------
43 class OperationMap : public OperationBase {
44 
45 protected:
46 
47 
48  std::unordered_map<std::string, op_any> operation_map;
49 
50  // Derived classes register their operations in the constructor
51  void register_operation(const std::string& name, op1 fn) {
52  operation_map.emplace(name, op_any{std::move(fn)});
53  }
54 
55  // Derived classes register their operations in the constructor
56  void register_operation(const std::string& name, op2 fn) {
57  operation_map.emplace(name, op_any{std::move(fn)});
58  }
59 
60  // Optional: derived can override for better error messages
61  virtual const char* op_name() const { return "Operation"; }
62 
63 public:
64 
65  // Execute operation (1-buffer)
66  void execute(const std::string& operation_name,
67  std::shared_ptr<DataStruct>& buffer) override {
68  auto it = operation_map.find(operation_name);
69  if (it == operation_map.end()) {
70  std::cerr << "Error: Invalid operation name '" << operation_name
71  << "' in " << op_name() << "\n";
72  return;
73  }
74 
75  if (auto* f1 = std::get_if<op1>(&it->second)) {
76  (*f1)(buffer);
77  return;
78  }
79 
80  // A 2-buffer op was registered, but only 1 buffer was provided
81  std::cerr << "Error: Operation '" << operation_name << "' in " << op_name()
82  << " requires 2 buffers.\n";
83  }
84 
85  // Execute operation (2-buffer)
86  void execute(const std::string& operation_name,
87  std::shared_ptr<DataStruct>& buffer,
88  std::shared_ptr<DataStruct>& prev_buffer) override {
89  auto it = operation_map.find(operation_name);
90  if (it == operation_map.end()) {
91  std::cerr << "Error: Invalid operation name '" << operation_name
92  << "' in " << op_name() << "\n";
93  return;
94  }
95 
96  if (auto* f2 = std::get_if<op2>(&it->second)) {
97  (*f2)(buffer, prev_buffer);
98  return;
99  }
100 
101  // A 1-buffer op was registered; ignore prev_buffer safely
102  auto* f1 = std::get_if<op1>(&it->second);
103  (*f1)(buffer);
104  }
105 
106  bool requires_two_buffers(const std::string& operation_name) const override {
107  auto it = operation_map.find(operation_name);
108  if (it == operation_map.end()) {
109  return false;
110  }
111  return std::holds_alternative<op2>(it->second);
112  }
113 
114 
115 };
116 
117 #endif