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 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() );
}