All Downloads are FREE. Search and download functionalities are using the official Maven repository.

gw.util.cache.FqnCache Maven / Gradle / Ivy

There is a newer version: 1.18.2
Show newest version
/*
 * Copyright 2014 Guidewire Software, Inc.
 */

package gw.util.cache;

import gw.internal.gosu.parser.StringCache;
import gw.lang.parser.TypeSystemAwareCache;
import gw.util.DynamicArray;
import gw.util.Predicate;

import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;
import java.util.Set;

public class FqnCache implements IFqnCache {
  private static final TypeSystemAwareCache PARTS_CACHE =
     TypeSystemAwareCache.make( "Fqn Parts Cache", 10000, FqnCache::split );

  private FqnCacheNode _root = new FqnCacheNode<>( "root", null );

  public FqnCacheNode getRoot() {
    return _root;
  }

  public FqnCacheNode getNode(String fqn) {
    FqnCacheNode n = _root;
    for (String part : getParts(fqn)) {
      n = n.getChild(part);
      if (n == null) {
        break;
      }
    }
    return n;
  }

  @Override
  public final T get( String fqn ) {
    FqnCacheNode n = getNode( fqn );
    return n == null ? null : n.getUserData();
  }

  @Override
  public final boolean contains( String fqn ) {
    return getNode(fqn) != null;
  }

  @Override
  public final void add( String fqn ) {
    add(fqn, null);
  }

  @Override
  public void add( String fqn, T userData ) {
    FqnCacheNode n = _root;
    for (String part : getParts(fqn)) {
      n = n.getOrCreateChild(part);
    }
    n.setUserData(userData);
  }

  @Override
  public final void remove( String[] fqns ) {
    for (String fqn : fqns) {
      remove(fqn);
    }
  }

  @Override
  public boolean remove( String fqn ) {
    FqnCacheNode n = _root;
    for (String part : getParts(fqn)) {
      n = n.getChild(part);
      if( n == null ) {
        return false;
      }
    }
    n.delete();
    return true;
  }

  @Override
  public final void clear() {
    _root.clear();
  }

  @Override
  public Set getFqns() {
    Set names = new HashSet<>();
    _root.collectNames(names, "");
    return names;
  }

  public void visitDepthFirst( Predicate visitor ) {
    List> copy = new ArrayList<>( _root.getChildren() );
    for( FqnCacheNode child: copy ) {
      if( !child.visitDepthFirst( visitor ) ) {
        return;
      }
    }
  }

  public void visitNodeDepthFirst( Predicate visitor ) {
    List> copy = new ArrayList<>( _root.getChildren() );
    for( FqnCacheNode child: copy ) {
      if( !child.visitNodeDepthFirst( visitor ) ) {
        return;
      }
    }
  }

  public void visitBreadthFirst( Predicate visitor ) {
    List> copy = new ArrayList<>( _root.getChildren() );
    for( FqnCacheNode child: copy ) {
      child.visitBreadthFirst( visitor );
    }
  }

  private static String[] split( String fqn ) {
    String theRest = fqn;
    DynamicArray parts = new DynamicArray<>();
    while( theRest != null ) {
      int iParam = theRest.indexOf( '<' );
      int iDot = theRest.indexOf( '.' );
      int iArray = theRest.indexOf( '[' );
      String part;
      if( iParam == 0 ) {
        if( iArray > 0 ) {
          part = theRest.substring( 0, iArray );
          theRest = iArray < theRest.length() ? theRest.substring( iArray ) : null;
        }
        else {
          if( theRest.charAt( theRest.length()-1 ) != '>' ) {
            throw new RuntimeException( "\"" + theRest + "\" does not end with '>'" );
          }
          part = theRest;
          theRest = null;
        }
      }
      else if( iArray == 0 ) {
        part = theRest.substring( 0, 2 );
        theRest = part.length() == theRest.length() ? null : theRest.substring( 2 );
      }
      else if( iParam > 0 ) {
        if( iDot > 0 && iDot < iParam ) {
          part = theRest.substring( 0, iDot );
          theRest = iDot + 1 < theRest.length() ? theRest.substring( iDot + 1 ) : null;
        }
        else {
          part = theRest.substring( 0, iParam );
          theRest = iParam < theRest.length() ? theRest.substring( iParam ) : null;
        }
      }
      else if( iDot > 0 ) {
        part = theRest.substring( 0, iDot );
        theRest = iDot + 1 < theRest.length() ? theRest.substring( iDot + 1 ) : null;
      }
      else {
        part = theRest;
        theRest = null;
      }
      parts.add( isCacheableString(part) ? StringCache.get( part ) : part );
    }
    return parts.toArray(new String[parts.size()]);
  }

  private static boolean isCacheableString(String part) {
    //Gosu fragment names that start with this pattern are created at runtime and
    //can be too numerous to cache in the string pool
    //We cannot reference GosuFragment.FRAGMENT_NAME_PREFIX because it would introduce a circular module dependency
    //between gosu-core and gosu-core-api so we are inlining the constant value here.
    return !part.startsWith("__Fragment__");
  }

  public static String[] getParts( String fqn ) {
    return PARTS_CACHE.get( fqn );
  }
}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy