diff --git a/Framework/ProcessSequence/ProcessSequence.h b/Framework/ProcessSequence/ProcessSequence.h index b3182b7385ac0fe76daa9b29e50eeb355f5b69a4..adffdd9ebfe443cbcc590c472b18c2ed1f4ecdcd 100644 --- a/Framework/ProcessSequence/ProcessSequence.h +++ b/Framework/ProcessSequence/ProcessSequence.h @@ -44,8 +44,8 @@ namespace corsika::process { template <typename TProcess1, typename TProcess2 = NullModel> class ProcessSequence : public BaseProcess<ProcessSequence<TProcess1, TProcess2>> { - using TProcess1type = typename std::decay<TProcess1>::type; - using TProcess2type = typename std::decay<TProcess2>::type; + using TProcess1type = typename std::decay_t<TProcess1>; + using TProcess2type = typename std::decay_t<TProcess2>; static bool constexpr t1ProcSeq = is_process_sequence_v<TProcess1type>; static bool constexpr t2ProcSeq = is_process_sequence_v<TProcess2type>; @@ -316,22 +316,22 @@ namespace corsika::process { **/ template <typename... TProcesses, typename TProcess1> - inline typename std::enable_if< - std::is_base_of<BaseProcess<typename std::decay<TProcess1>::type>, - typename std::decay<TProcess1>::type>::value, - ProcessSequence<TProcess1, decltype(sequence(std::declval<TProcesses>()...))>>::type + inline typename std::enable_if_t< + std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess1>>, + typename std::decay_t<TProcess1>>, + ProcessSequence<TProcess1, decltype(sequence(std::declval<TProcesses>()...))>> sequence(TProcess1&& vA, TProcesses&&... vBs) { return ProcessSequence<TProcess1, decltype(sequence(std::declval<TProcesses>()...))>( vA, sequence(std::forward<TProcesses>(vBs)...)); } template <typename TProcess1, typename TProcess2> - inline typename std::enable_if< - std::is_base_of<BaseProcess<typename std::decay<TProcess1>::type>, - typename std::decay<TProcess1>::type>::value && - std::is_base_of<BaseProcess<typename std::decay<TProcess2>::type>, - typename std::decay<TProcess2>::type>::value, - ProcessSequence<TProcess1, TProcess2>>::type + inline typename std::enable_if_t< + std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess1>>, + typename std::decay_t<TProcess1>> && + std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess2>>, + typename std::decay_t<TProcess2>>, + ProcessSequence<TProcess1, TProcess2>> sequence(TProcess1&& vA, TProcess2&& vB) { return ProcessSequence<TProcess1, TProcess2>(vA, vB); } @@ -341,17 +341,48 @@ namespace corsika::process { * `NullModel` **/ template <typename TProcess> - inline typename std::enable_if< - std::is_base_of<BaseProcess<typename std::decay<TProcess>::type>, - typename std::decay<TProcess>::type>::value, - ProcessSequence<TProcess, NullModel>>::type + inline typename std::enable_if_t< + std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess>>, + typename std::decay_t<TProcess>>, + ProcessSequence<TProcess, NullModel>> sequence(TProcess&& vA) { return ProcessSequence<TProcess, NullModel>(vA, NullModel()); } - /// traits marker to identify objectas ProcessSequence + /** + * traits marker to identify objectas ProcessSequence + **/ + template <typename TProcess1, typename TProcess2> + struct is_process_sequence<ProcessSequence<TProcess1, TProcess2>> : std::true_type { + // only switch on for BaseProcesses + template <typename std::enable_if_t< + std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess1>>, + typename std::decay_t<TProcess1>> && + std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess2>>, + typename std::decay_t<TProcess2>>, + int>> + is_process_sequence() {} + }; + + /** + * traits marker to identify objects containing any StackProcesses + **/ + namespace detail { + // need helper alias to achieve this: + template <typename TProcess1, typename TProcess2, + typename = typename std::enable_if_t< + contains_stack_process_v<TProcess1> || + std::is_base_of_v<StackProcess<typename std::decay_t<TProcess1>>, + typename std::decay_t<TProcess1>> || + contains_stack_process_v<TProcess2> || + std::is_base_of_v<StackProcess<typename std::decay_t<TProcess2>>, + typename std::decay_t<TProcess2>>, + int>> + using enable_if_stack = ProcessSequence<TProcess1, TProcess2>; + } // namespace detail + template <typename TProcess1, typename TProcess2> - struct is_process_sequence<corsika::process::ProcessSequence<TProcess1, TProcess2>> + struct contains_stack_process<detail::enable_if_stack<TProcess1, TProcess2>> : std::true_type {}; } // namespace corsika::process diff --git a/Framework/ProcessSequence/ProcessTraits.h b/Framework/ProcessSequence/ProcessTraits.h index 5f8b2f39fff84bc935cb0c2c40060c4b1e751921..e0cb00ebfde8827bbb098dc34d13df1c94a72eb2 100644 --- a/Framework/ProcessSequence/ProcessTraits.h +++ b/Framework/ProcessSequence/ProcessTraits.h @@ -29,4 +29,13 @@ namespace corsika::process { template <typename TClass> bool constexpr is_switch_process_sequence_v = is_switch_process_sequence<TClass>::value; + /** + * A traits marker to identify ProcessSequence that contain a StackProcess + **/ + template <typename TClass> + struct contains_stack_process : std::false_type {}; + + template <typename TClass> + bool constexpr contains_stack_process_v = contains_stack_process<TClass>::value; + } // namespace corsika::process diff --git a/Framework/ProcessSequence/SwitchProcessSequence.h b/Framework/ProcessSequence/SwitchProcessSequence.h index 537336d647ed0e32a78bc064a34d0f22625795c8..f1b1dfcf5eee747f2007d207788ad2f686285766 100644 --- a/Framework/ProcessSequence/SwitchProcessSequence.h +++ b/Framework/ProcessSequence/SwitchProcessSequence.h @@ -58,17 +58,42 @@ namespace corsika::process { class SwitchProcessSequence : public BaseProcess<SwitchProcessSequence<TProcess1, TProcess2, TSelect>> { - using TProcess1type = typename std::decay<TProcess1>::type; - using TProcess2type = typename std::decay<TProcess2>::type; - - // static_assert(std::is_base_of_v<!StackProcess<TProcess1>, TProcess1type>, "canot - // use StackProcess in SwitchProcessSequence"); - // static_assert(std::is_base_of_v<!StackProcess<TProcess2>, TProcess2type>, "canot - // use StackProcess in SwitchProcessSequence"); + using TProcess1type = typename std::decay_t<TProcess1>; + using TProcess2type = typename std::decay_t<TProcess2>; static bool constexpr t1ProcSeq = is_process_sequence_v<TProcess1type>; static bool constexpr t2ProcSeq = is_process_sequence_v<TProcess2type>; + // make sure only BaseProcess types TProcess1/2 are passed + static_assert(std::is_base_of_v<BaseProcess<TProcess1type>, TProcess1type>, + "can only use process derived from BaseProcess in " + "SwitchProcessSequence, for Process 1"); + static_assert(std::is_base_of_v<BaseProcess<TProcess2type>, TProcess2type>, + "can only use process derived from BaseProcess in " + "SwitchProcessSequence, for Process 2"); + + // make sure TSelect is a function + static_assert(!std::is_function_v<TSelect>, "TSelect must be a function type"); + + // make sure none of TProcess1/2 is a StackProcess + static_assert(!std::is_base_of_v<StackProcess<TProcess1type>, TProcess1type>, + "cannot use StackProcess in SwitchProcessSequence, for Process 1"); + static_assert(!std::is_base_of_v<StackProcess<TProcess2type>, TProcess2type>, + "cannot use StackProcess in SwitchProcessSequence, for Process 2"); + + // if TProcess1/2 are already ProcessSequences, make sure they do not contain + // StackProcess + // if constexpr (t1ProcSeq) { + static_assert(!contains_stack_process_v<TProcess1type>, + "cannot use StackProcess in SwitchProcessSequence, remove from " + "ProcessSequence 1"); + //} + + // if constexpr (t2ProcSeq) + static_assert(!contains_stack_process_v<TProcess2type>, + "cannot use StackProcess in SwitchProcessSequence, remove from " + "ProcessSequence 2"); + TSelect select_; // this is a reference, if possible TProcess1 A_; // this is a reference, if possible @@ -83,7 +108,6 @@ namespace corsika::process { template <typename TParticle, typename TVTNType> EProcessReturn DoBoundaryCrossing(TParticle& particle, TVTNType const& from, TVTNType const& to) { - switch (select_(particle)) { case SwitchResult::First: { if constexpr (std::is_base_of_v<BoundaryCrossingProcess<TProcess1type>, @@ -154,7 +178,6 @@ namespace corsika::process { template <typename TParticle, typename TTrack> inline corsika::units::si::LengthType MaxStepLength(TParticle& particle, TTrack& vTrack) { - switch (select_(particle)) { case SwitchResult::First: { if constexpr (std::is_base_of_v<ContinuousProcess<TProcess1type>, @@ -215,7 +238,6 @@ namespace corsika::process { [[maybe_unused]] corsika::units::si::InverseGrammageType lambda_inv_select, [[maybe_unused]] corsika::units::si::InverseGrammageType lambda_inv_sum = corsika::units::si::InverseGrammageType::zero()) { - switch (select_(view.parent())) { case SwitchResult::First: { if constexpr (t1ProcSeq) { @@ -294,7 +316,6 @@ namespace corsika::process { [[maybe_unused]] corsika::units::si::InverseTimeType decay_inv_select, [[maybe_unused]] corsika::units::si::InverseTimeType decay_inv_sum = corsika::units::si::InverseTimeType::zero()) { - switch (select_(view.parent())) { case SwitchResult::First: { if constexpr (t1ProcSeq) { @@ -347,12 +368,12 @@ namespace corsika::process { // Both, Processes1 and Processes2, must derive from BaseProcesses template <typename TProcess1, typename TProcess2, typename TSelect> - inline typename std::enable_if< - std::is_base_of<BaseProcess<typename std::decay<TProcess1>::type>, - typename std::decay<TProcess1>::type>::value && - std::is_base_of<BaseProcess<typename std::decay<TProcess2>::type>, - typename std::decay<TProcess2>::type>::value, - SwitchProcessSequence<TProcess1, TProcess2, TSelect>>::type + inline typename std::enable_if_t< + std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess1>>, + typename std::decay_t<TProcess1>> && + std::is_base_of_v<BaseProcess<typename std::decay_t<TProcess2>>, + typename std::decay_t<TProcess2>>, + SwitchProcessSequence<TProcess1, TProcess2, TSelect>> select(TProcess1&& vA, TProcess2&& vB, TSelect selector) { return SwitchProcessSequence<TProcess1, TProcess2, TSelect>(vA, vB, selector); } diff --git a/Framework/ProcessSequence/testProcessSequence.cc b/Framework/ProcessSequence/testProcessSequence.cc index eb88c41985199f22a9a051bbbac70728f522fcc8..875cbc5821fe5e67da0ece3977f13446f2a0659a 100644 --- a/Framework/ProcessSequence/testProcessSequence.cc +++ b/Framework/ProcessSequence/testProcessSequence.cc @@ -266,6 +266,8 @@ TEST_CASE("Process Sequence", "[Process Sequence]") { auto sequence1 = process::sequence(m1, m2, m3, m4); CHECK(is_process_sequence_v<decltype(sequence1)> == true); CHECK(is_process_sequence_v<decltype(m2)> == false); + CHECK(is_switch_process_sequence_v<decltype(sequence1)> == false); + CHECK(is_switch_process_sequence_v<decltype(m2)> == false); auto sequence2 = process::sequence(m1, m2, m3); CHECK(is_process_sequence_v<decltype(sequence2)> == true); @@ -358,6 +360,16 @@ TEST_CASE("Process Sequence", "[Process Sequence]") { CHECK(s1.GetCount() == 20); CHECK(s2.GetCount() == 10); + + ContinuousProcess2 cp2(1); // += 0.111 + Process2 m2(2); // /= 1.1 + auto sequence2 = process::sequence(cp2, m2); + auto sequence3 = process::sequence(cp2, m2, s1); + + CHECK(is_process_sequence_v<decltype(sequence2)> == true); + CHECK(is_process_sequence_v<decltype(sequence3)> == true); + CHECK(contains_stack_process_v<decltype(sequence2)> == false); + CHECK(contains_stack_process_v<decltype(sequence3)> == true); } }