Back to home page

EIC code displayed by LXR

 
 

    


File indexing completed on 2026-11-02 10:27:28

0001 //------------------------------- -*- C++ -*- -------------------------------//
0002 // Copyright Celeritas contributors: see top-level COPYRIGHT file for details
0003 // SPDX-License-Identifier: (Apache-2.0 OR MIT)
0004 //---------------------------------------------------------------------------//
0005 //! \file orange/univ/detail/InfixEvaluator.hh
0006 //---------------------------------------------------------------------------//
0007 #pragma once
0008 
0009 #include "corecel/Assert.hh"
0010 #include "corecel/cont/LdgSpan.hh"
0011 #include "orange/OrangeTypes.hh"
0012 
0013 namespace celeritas
0014 {
0015 namespace detail
0016 {
0017 //---------------------------------------------------------------------------//
0018 /*!
0019  * Evaluate an explicit infix logical expression applied to a vector of senses.
0020  *
0021  * Explicit infix notation explicitly spells out the intersection operator,
0022  * i.e., \c logic::land whereas implicit infix notation omits it.
0023  *
0024  * These two expressions are equivalent:
0025  * Implicit notation: A(BC | DE)
0026  * Explicit notation: A&((B&C) | (D&E))
0027  */
0028 class InfixEvaluator
0029 {
0030   public:
0031     //@{
0032     //! \name Type aliases
0033     using SpanConstLogic = LdgSpan<logic_int const>;
0034     //@}
0035 
0036   public:
0037     // Construct with a view to some logic definition
0038     explicit CELER_FORCEINLINE_FUNCTION InfixEvaluator(SpanConstLogic logic);
0039 
0040     // Evaluate a logical expression, substituting bools from the vector
0041     template<class F>
0042     inline CELER_FUNCTION bool operator()(F&& eval_sense) const;
0043 
0044   private:
0045     // Short-circuit evaluation of the second operand
0046     inline CELER_FUNCTION size_type short_circuit(size_type i) const;
0047 
0048     //// DATA ////
0049 
0050     SpanConstLogic logic_;
0051 };
0052 
0053 //---------------------------------------------------------------------------//
0054 /*!
0055  * Construct with a view to some logic definition.
0056  */
0057 CELER_FUNCTION InfixEvaluator::InfixEvaluator(SpanConstLogic logic)
0058     : logic_(logic)
0059 {
0060     CELER_EXPECT(!logic_.empty());
0061 }
0062 
0063 //---------------------------------------------------------------------------//
0064 /*!
0065  * Evaluate a logical expression, substituting bools from the vector.
0066  *
0067  * The functor eval_sense takes as argument a \c celeritas::FaceId present in
0068  * the logic expression passed to the constructor and returns a boolean value
0069  * matching \c celeritas::Sense
0070  */
0071 template<class F>
0072 CELER_FUNCTION bool InfixEvaluator::operator()(F&& eval_sense) const
0073 {
0074     bool result{true};
0075 
0076     int par_depth{0};
0077     size_type i{0};
0078     while (i < logic_.size())
0079     {
0080         if (logic_int const lgc{logic_[i]}; !logic::is_operator_token(lgc))
0081         {
0082             result = static_cast<bool>(eval_sense(FaceId{lgc}));
0083         }
0084         else if ((lgc == logic::lor && result)
0085                  || (lgc == logic::land && !result))
0086         {
0087             if (par_depth == 0)
0088             {
0089                 break;
0090             }
0091             --par_depth;
0092             i = this->short_circuit(i);
0093         }
0094         else if (lgc == logic::ltrue)
0095         {
0096             result = true;
0097         }
0098         else if (lgc == logic::lopen)
0099         {
0100             ++par_depth;
0101         }
0102         else if (lgc == logic::lclose)
0103         {
0104             CELER_ASSERT(par_depth > 0);
0105             --par_depth;
0106         }
0107         else if (lgc == logic::lnot)
0108         {
0109             // negation of a sub-expression is not supported
0110             CELER_ASSUME(i + 1 < logic_.size());
0111             CELER_EXPECT(!logic::is_operator_token(logic_[i + 1])
0112                          || logic_[i + 1] == logic::ltrue);
0113             auto const& operand = logic_[++i];
0114             result = !((operand == logic::ltrue)
0115                        || static_cast<bool>(eval_sense(FaceId{operand})));
0116         }
0117         ++i;
0118     }
0119     return result;
0120 }
0121 
0122 //---------------------------------------------------------------------------//
0123 /*!
0124  * Short-circuit evaluation of the second operand.
0125  */
0126 CELER_FUNCTION size_type InfixEvaluator::short_circuit(size_type i) const
0127 {
0128     int par_depth{1};
0129     while (par_depth > 0)
0130     {
0131         CELER_ASSUME(i + 1 < logic_.size());
0132         if (logic_int lgc = logic_[++i]; lgc == logic::lopen)
0133         {
0134             ++par_depth;
0135         }
0136         else if (lgc == logic::lclose)
0137         {
0138             --par_depth;
0139         }
0140     }
0141     return i;
0142 }
0143 
0144 //---------------------------------------------------------------------------//
0145 }  // namespace detail
0146 }  // namespace celeritas