MurmurHash SharedDataHolder<PathMatcher>::hash() const { IECore::MurmurHash result; HashStack stack; PathMatcher m = readable(); for( PathMatcher::RawIterator it = m.begin(), eIt = m.end(); it != eIt; ++it ) { // The iterator is recursive, so we use a stack to keep // track of where we are. Resize the stack to match our // current depth. The required size has the +1 because // we need a stack entry for the root item. size_t requiredStackSize = it->size() + 1; if( requiredStackSize > stack.size() ) { // Going a level deeper. stack.push( HashNodes() ); assert( stack.size() == requiredStackSize ); } else if( requiredStackSize < stack.size() ) { // Returning from recursion to the child nodes. // Output the hashes for the children we visited // and stored on the stack previously. popHashNodes( stack, requiredStackSize, result ); } stack.top().push_back( HashNode( it->size() ? it->back().c_str() : "", it.exactMatch() ) ); } popHashNodes( stack, 0, result ); return result; }
void GafferSceneTest::testPathMatcherRawIterator() { vector<InternedString> root; vector<InternedString> a = assign::list_of( "a" ); vector<InternedString> ab = assign::list_of( "a" )( "b" ); vector<InternedString> abc = assign::list_of( "a" )( "b" )( "c" ); PathMatcher m; PathMatcher::RawIterator it = m.begin(); GAFFERTEST_ASSERT( it == m.end() ); m.addPath( abc ); it = m.begin(); GAFFERTEST_ASSERT( *it == root ); GAFFERTEST_ASSERT( it.exactMatch() == false ); GAFFERTEST_ASSERT( it != m.end() ); ++it; GAFFERTEST_ASSERT( *it == a ); GAFFERTEST_ASSERT( it.exactMatch() == false ); GAFFERTEST_ASSERT( it != m.end() ); ++it; GAFFERTEST_ASSERT( *it == ab ); GAFFERTEST_ASSERT( it.exactMatch() == false ); GAFFERTEST_ASSERT( it != m.end() ); ++it; GAFFERTEST_ASSERT( *it == abc ); GAFFERTEST_ASSERT( it.exactMatch() == true ); GAFFERTEST_ASSERT( it != m.end() ); ++it; GAFFERTEST_ASSERT( it == m.end() ); }
GafferScene::ConstPathMatcherDataPtr BranchCreator::computeSet( const IECore::InternedString &setName, const Gaffer::Context *context, const ScenePlug *parent ) const { ConstPathMatcherDataPtr inputSetData = inPlug()->set( setName ); ConstCompoundDataPtr mapping = boost::static_pointer_cast<const CompoundData>( mappingPlug()->getValue() ); if( !mapping->readable().size() ) { return inputSetData; } ScenePlug::ScenePath parentPath = mapping->member<InternedStringVectorData>( g_parentKey )->readable(); ConstPathMatcherDataPtr branchSetData = computeBranchSet( parentPath, setName, context ); if( !branchSetData ) { return inputSetData; } const PathMatcher &branchSet = branchSetData->readable(); if( branchSet.isEmpty() ) { return inputSetData; } const CompoundData *forwardMapping = mapping->member<CompoundData>( g_forwardMappingKey ); PathMatcherDataPtr outputSetData = inputSetData->copy(); PathMatcher &outputSet = outputSetData->writable(); vector<InternedString> outputPrefix( parentPath ); for( PathMatcher::RawIterator pIt = branchSet.begin(), peIt = branchSet.end(); pIt != peIt; ++pIt ) { const ScenePlug::ScenePath &branchPath = *pIt; if( !branchPath.size() ) { continue; // Skip root } assert( branchPath.size() == 1 ); const InternedStringData *outputName = forwardMapping->member<InternedStringData>( branchPath[0], /* throwExceptions = */ true ); outputPrefix.resize( parentPath.size() + 1 ); outputPrefix.back() = outputName->readable(); outputSet.addPaths( branchSet.subTree( *pIt ), outputPrefix ); pIt.prune(); // We only want to visit the first level } return outputSetData; }
GafferScene::ConstPathMatcherDataPtr Prune::computeSet( const IECore::InternedString &setName, const Gaffer::Context *context, const ScenePlug *parent ) const { ConstPathMatcherDataPtr inputSetData = inPlug()->setPlug()->getValue(); const PathMatcher &inputSet = inputSetData->readable(); if( inputSet.isEmpty() ) { return inputSetData; } PathMatcherDataPtr outputSetData = inputSetData->copy(); PathMatcher &outputSet = outputSetData->writable(); FilterPlug::SceneScope sceneScope( context, inPlug() ); for( PathMatcher::RawIterator pIt = inputSet.begin(), peIt = inputSet.end(); pIt != peIt; ) { sceneScope.set( ScenePlug::scenePathContextName, *pIt ); const int m = filterPlug()->getValue(); if( m & ( Filter::ExactMatch | Filter::AncestorMatch ) ) { // This path and all below it are pruned, so we can // ignore it and prune the traversal to the descendant // paths. outputSet.prune( *pIt ); pIt.prune(); ++pIt; } else if( m & Filter::DescendantMatch ) { // This path isn't pruned, so we continue our traversal // as normal to find out which descendants _are_ pruned. ++pIt; } else { // This path isn't pruned, and neither is anything // below it. We can avoid retesting the filter for // all descendant paths, since we know they're not // pruned. assert( m == Filter::NoMatch ); pIt.prune(); ++pIt; } } return outputSetData; }
void PathMatcherData::save( SaveContext *context ) const { Data::save( context ); IndexedIOPtr container = context->container( staticTypeName(), g_ioVersion ); std::vector<InternedString> strings; std::vector<unsigned int> pathLengths; std::vector<unsigned char> exactMatches; for( PathMatcher::RawIterator it = readable().begin(), eIt = readable().end(); it != eIt; ++it ) { pathLengths.push_back( it->size() ); if( it->size() ) { strings.push_back( it->back() ); } exactMatches.push_back( it.exactMatch() ); } container->write( "strings", strings.data(), strings.size() ); container->write( "pathLengths", pathLengths.data(), pathLengths.size() ); container->write( "exactMatches", exactMatches.data(), exactMatches.size() ); }
GafferScene::ConstPathMatcherDataPtr Isolate::computeSet( const IECore::InternedString &setName, const Gaffer::Context *context, const ScenePlug *parent ) const { ConstPathMatcherDataPtr inputSetData = inPlug()->setPlug()->getValue(); const PathMatcher &inputSet = inputSetData->readable(); if( inputSet.isEmpty() ) { return inputSetData; } PathMatcherDataPtr outputSetData = new PathMatcherData; PathMatcher &outputSet = outputSetData->writable(); ContextPtr tmpContext = filterContext( context ); Context::Scope scopedContext( tmpContext.get() ); const std::string fromString = fromPlug()->getValue(); ScenePlug::ScenePath fromPath; ScenePlug::stringToPath( fromString, fromPath ); for( PathMatcher::RawIterator pIt = inputSet.begin(), peIt = inputSet.end(); pIt != peIt; ) { tmpContext->set( ScenePlug::scenePathContextName, *pIt ); const int m = filterPlug()->getValue(); if( m & ( Filter::ExactMatch | Filter::AncestorMatch ) ) { // We want to keep everything below this point, and // we can speed things up by not checking the filter // for our descendants. PathMatcher::RawIterator next = pIt; next.prune(); ++next; while( pIt != next ) { if( pIt.exactMatch() ) { outputSet.addPath( *pIt ); } ++pIt; } } else if( m & Filter::DescendantMatch ) { // We might be removing things below here, // so just continue our iteration normally // so we can find out. if( pIt.exactMatch() ) { outputSet.addPath( *pIt ); } ++pIt; } else { assert( m == Filter::NoMatch ); if( boost::starts_with( *pIt, fromPath ) ) { // Not going to keep anything below // here, so we can prune traversal // entirely. pIt.prune(); } else if( pIt.exactMatch() ) { outputSet.addPath( *pIt ); } ++pIt; } } return outputSetData; }
GafferScene::ConstPathMatcherDataPtr Isolate::computeSet( const IECore::InternedString &setName, const Gaffer::Context *context, const ScenePlug *parent ) const { ConstPathMatcherDataPtr inputSetData = inPlug()->setPlug()->getValue(); if( ( setName == g_lightsSetName && keepLightsPlug()->getValue() ) || ( setName == g_camerasSetName && keepCamerasPlug()->getValue() ) ) { return inputSetData; } const PathMatcher &inputSet = inputSetData->readable(); if( inputSet.isEmpty() ) { return inputSetData; } PathMatcherDataPtr outputSetData = inputSetData->copy(); PathMatcher &outputSet = outputSetData->writable(); FilterPlug::SceneScope sceneScope( context, inPlug() ); const std::string fromString = fromPlug()->getValue(); ScenePlug::ScenePath fromPath; ScenePlug::stringToPath( fromString, fromPath ); const SetsToKeep setsToKeep( this ); for( PathMatcher::RawIterator pIt = inputSet.begin(), peIt = inputSet.end(); pIt != peIt; ) { sceneScope.set( ScenePlug::scenePathContextName, *pIt ); const int m = filterPlug()->getValue() || setsToKeep.match( *pIt ); if( m & ( Filter::ExactMatch | Filter::AncestorMatch ) ) { // We want to keep everything below this point, so // can just prune our iteration. pIt.prune(); ++pIt; } else if( m & Filter::DescendantMatch ) { // We might be removing things below here, // so just continue our iteration normally // so we can find out. ++pIt; } else { assert( m == Filter::NoMatch ); if( boost::starts_with( *pIt, fromPath ) ) { // Not going to keep anything below // here, so we can prune traversal // entirely. outputSet.prune( *pIt ); pIt.prune(); } ++pIt; } } return outputSetData; }