@@ -778,21 +778,6 @@ class CFrontendIR : public CNodePool
778778inline bool CFrontendIR::valid (const TypedHandle<const CLayer> rootHandle, system::logger_opt_ptr logger) const
779779{
780780 constexpr auto ELL_ERROR = system::ILogger::E_LOG_LEVEL::ELL_ERROR;
781-
782- core::stack<const CLayer*> layerStack;
783- auto pushLayer = [&](const TypedHandle<const CLayer> layerHandle)->bool
784- {
785- const auto * layer = deref (layerHandle);
786- if (!layer)
787- {
788- logger.log (" Layer node %u of type %s not a `CLayer` node!" ,ELL_ERROR,layerHandle.untyped .value ,getTypeName (layerHandle).data ());
789- return false ;
790- }
791- layerStack.push (layer);
792- return true ;
793- };
794- if (!pushLayer (rootHandle))
795- return false ;
796781
797782 enum class SubtreeContributorState : uint8_t
798783 {
@@ -807,6 +792,11 @@ inline bool CFrontendIR::valid(const TypedHandle<const CLayer> rootHandle, syste
807792 SubtreeContributorState contribState = SubtreeContributorState::Required;
808793 };
809794 core::stack<StackEntry> exprStack;
795+ // unused yet
796+ core::unordered_set<TypedHandle<const INode>,HandleHash> visitedNodes;
797+ // should probably size it better, if I knew total node count allocated or live
798+ visitedNodes.reserve (m_rootNodes.size ()<<3 );
799+ //
810800 auto validateExpression = [&](const TypedHandle<const IExprNode> exprRoot, const bool isBTDF) -> bool
811801 {
812802 if (!exprRoot)
@@ -865,6 +855,8 @@ inline bool CFrontendIR::valid(const TypedHandle<const CLayer> rootHandle, syste
865855 logger.log (" Expression too complex, more than %d contributors encountered" ,ELL_ERROR,MaxContributors);
866856 return false ;
867857 }
858+ // cannot optimize with `unordered_set visitedNodes` because we need to check contributor slots, if we really wanted to we could do it with an
859+ // `unordered_map` telling us the contributor slot range remapping (and presence of contributor) but right now it would be premature optimization.
868860 exprStack.push (newEntry);
869861 }
870862 else if (childHandle)
@@ -893,15 +885,30 @@ inline bool CFrontendIR::valid(const TypedHandle<const CLayer> rootHandle, syste
893885 }
894886 return true ;
895887 };
896- while (!layerStack.empty ())
888+
889+ core::vector<const CLayer*> layerStack;
890+ auto pushLayer = [&](const TypedHandle<const CLayer> layerHandle)->bool
897891 {
898- const auto * layer = layerStack.top ();
899- layerStack.pop ();
900- if (layer->coated && !pushLayer (layer->coated ))
892+ const auto * layer = deref (layerHandle);
893+ if (!layer)
901894 {
902- logger.log (" \t coatee %d was specificed but is of wrong type " ,ELL_ERROR,layer-> coated );
895+ logger.log (" Layer node %u of type %s not a `CLayer` node! " ,ELL_ERROR,layerHandle. untyped . value , getTypeName (layerHandle). data () );
903896 return false ;
904897 }
898+ auto found = std::find (layerStack.begin (),layerStack.end (),layer);
899+ if (found!=layerStack.end ())
900+ {
901+ logger.log (" Layer node %u is involved in a Cycle!" ,ELL_ERROR,layerHandle.untyped .value );
902+ return false ;
903+ }
904+ layerStack.push_back (layer);
905+ return true ;
906+ };
907+ if (!pushLayer (rootHandle))
908+ return false ;
909+ while (true )
910+ {
911+ const auto * layer = layerStack.back ();
905912 if (!layer->brdfTop && !layer->btdf && !layer->brdfBottom )
906913 {
907914 logger.log (" At least one BRDF or BTDF in the Layer is required." ,ELL_ERROR);
@@ -913,6 +920,13 @@ inline bool CFrontendIR::valid(const TypedHandle<const CLayer> rootHandle, syste
913920 return false ;
914921 if (!validateExpression (layer->brdfBottom ,false ))
915922 return false ;
923+ if (!layer->coated )
924+ break ;
925+ if (!pushLayer (layer->coated ))
926+ {
927+ logger.log (" \t coatee %d was specificed but is invalid!" ,ELL_ERROR,layer->coated );
928+ return false ;
929+ }
916930 }
917931 return true ;
918932}
0 commit comments