Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-08-26 08:38:39

0001 // This file is part of the ACTS project.
0002 //
0003 // Copyright (C) 2016 CERN for the benefit of the ACTS project
0004 //
0005 // This Source Code Form is subject to the terms of the Mozilla Public
0006 // License, v. 2.0. If a copy of the MPL was not distributed with this
0007 // file, You can obtain one at https://mozilla.org/MPL/2.0/.
0008 
0009 #pragma once
0010 
0011 #include <cstddef>
0012 #include <functional>
0013 #include <stdexcept>
0014 #include <string>
0015 #include <string_view>
0016 #include <type_traits>
0017 #include <unordered_map>
0018 #include <utility>
0019 
0020 #include <nlohmann/json.hpp>
0021 
0022 namespace Acts {
0023 
0024 /// JSON-specific dispatcher that routes decoder functions based on a string
0025 /// kind tag found in the encoded payload.
0026 template <typename return_t, typename... args_t>
0027 class JsonKindDispatcher {
0028  public:
0029   /// Type of the dispatcher specialization
0030   using self_type = JsonKindDispatcher<return_t, args_t...>;
0031   /// Function signature type
0032   using decoder_signature = return_t(const nlohmann::json&, args_t...);
0033   /// Decoder callable type
0034   using decoder_type = std::function<decoder_signature>;
0035   /// Decoder callable pointer type
0036   using decoder_pointer_type = return_t (*)(args_t...);
0037 
0038   /// Explicit constructor of the dispatcher
0039   ///
0040   /// @param kindKey the key containing the type kind in json
0041   /// @param context context string for error signaling
0042   explicit JsonKindDispatcher(std::string kindKey = "kind",
0043                               std::string context = "JSON payload")
0044       : m_kindKey(std::move(kindKey)), m_context(std::move(context)) {
0045     if (m_kindKey.empty()) {
0046       throw std::invalid_argument(
0047           "JsonKindDispatcher kind key must be non-empty");
0048     }
0049     if (m_context.empty()) {
0050       m_context = "JSON payload";
0051     }
0052   }
0053 
0054   /// Register a kind and the corresponding decoder
0055   ///
0056   /// @param kind kind to register
0057   /// @param decoder corresponding decoder
0058   ///
0059   /// @return reference to this dispatcher instance
0060   self_type& registerKind(std::string kind, decoder_type decoder) {
0061     if (kind.empty()) {
0062       throw std::invalid_argument("JsonKindDispatcher kind must be non-empty");
0063     }
0064     if (!decoder) {
0065       throw std::invalid_argument("JsonKindDispatcher decoder must be valid");
0066     }
0067     auto [_, inserted] =
0068         m_decoders.emplace(std::move(kind), std::move(decoder));
0069     if (!inserted) {
0070       throw std::invalid_argument(
0071           "JsonKindDispatcher duplicate kind registration");
0072     }
0073     return *this;
0074   }
0075 
0076   /// Decode the registered kind from a json file
0077   ///
0078   /// @param encoded json file to decode
0079   /// @param args forwarding reference to the decoder arguments
0080   ///
0081   /// @return the object constructed from the json encoding
0082   template <typename... func_args_t>
0083   return_t operator()(const nlohmann::json& encoded,
0084                       func_args_t&&... args) const
0085     requires std::invocable<decoder_pointer_type, func_args_t...>
0086   {
0087     if (!encoded.contains(m_kindKey)) {
0088       throw std::invalid_argument("Missing '" + m_kindKey + "' in " +
0089                                   m_context);
0090     }
0091 
0092     const auto& kindValue = encoded.at(m_kindKey);
0093     if (!kindValue.is_string()) {
0094       throw std::invalid_argument("Invalid '" + m_kindKey + "' type in " +
0095                                   m_context);
0096     }
0097 
0098     const auto kind = kindValue.template get<std::string>();
0099     auto decoder = m_decoders.find(kind);
0100     if (decoder == m_decoders.end()) {
0101       throw std::invalid_argument("Unsupported " + m_context +
0102                                   " kind: " + kind);
0103     }
0104 
0105     if constexpr (std::is_void_v<return_t>) {
0106       decoder->second(encoded, std::forward<func_args_t>(args)...);
0107       return;
0108     } else {
0109       return decoder->second(encoded, std::forward<func_args_t>(args)...);
0110     }
0111   }
0112 
0113   /// Check if a certain kind is registered
0114   ///
0115   /// @param kind the kind to check for registration
0116   ///
0117   /// @return boolean showing registration status
0118   bool hasKind(std::string_view kind) const {
0119     return m_decoders.contains(std::string{kind});
0120   }
0121 
0122   /// Clear the registered decoders list
0123   void clear() { m_decoders.clear(); }
0124 
0125   /// Get the number of registered decoders
0126   ///
0127   /// @return number of registered decoders
0128   std::size_t size() const { return m_decoders.size(); }
0129 
0130  private:
0131   std::string m_kindKey;
0132   std::string m_context;
0133   std::unordered_map<std::string, decoder_type> m_decoders;
0134 };
0135 
0136 }  // namespace Acts