1  /*
     2   * Copyright the original author or authors.
     3   * 
     4   * Licensed under the MOZILLA PUBLIC LICENSE, Version 1.1 (the "License");
     5   * you may not use this file except in compliance with the License.
     6   * You may obtain a copy of the License at
     7   * 
     8   *      http://www.mozilla.org/MPL/MPL-1.1.html
     9   * 
    10   * Unless required by applicable law or agreed to in writing, software
    11   * distributed under the License is distributed on an "AS IS" BASIS,
    12   * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
    13   * See the License for the specific language governing permissions and
    14   * limitations under the License.
    15   */
    16  
    17  import org.as2lib.core.BasicClass;
    18  import org.as2lib.env.overload.Overload;
    19  import org.as2lib.env.reflect.ClassInfo;
    20  import org.as2lib.env.reflect.PackageInfo;
    21  import org.as2lib.env.reflect.Cache;
    22  
    23  /**
    24   * {@code SimpleCache} is a simple and performant implementation of the {@code Cache}
    25   * interface.
    26   * 
    27   * <p>The caching of classes and packages leads to better performance. You also
    28   * must cache them because for example the parent of two classes residing in the
    29   * same package should be the same {@code PackageInfo} instance.
    30   * 
    31   * <p>This cache is mostly used internally. But you can also use it to add
    32   * {@code ClassInfo} or {@code PackageInfo} instances directly so that they do not
    33   * have to be searched for. This can improve the performance dramatically with
    34   * classes or packages that are needed quite often.
    35   *
    36   * <p>This implementation sets a variable with name {@code "__as2lib__hashCode"} on
    37   * every cached class and package to offer better performance. Do not delete this
    38   * property.
    39   *
    40   * @author Simon Wacker
    41   */
    42  class org.as2lib.env.reflect.SimpleCache extends BasicClass implements Cache {
    43  	
    44  	/** The number of generated hash codes. */
    45  	private static var hashCodeCounter:Number = 0;
    46  
    47  	/** The added infos. */
    48  	private var cache:Array;
    49  	
    50  	/** The root package. */
    51  	private var root:PackageInfo;
    52  	
    53  	/**
    54  	 * Constructs a new {@code SimpleCache} instance.
    55  	 *
    56  	 * <p>The root/default package determines where the {@code ClassAlgorithm} and
    57  	 * {@code PackageAlgorithm} classes start their search.
    58  	 * 
    59  	 * @param root the root/default package of the package hierarchy
    60  	 */
    61  	public function SimpleCache(root:PackageInfo) {
    62  		this.root = root;
    63  		releaseAll();
    64  	}
    65  	
    66  	/**
    67  	 * @overload #getClassByClass
    68  	 * @overload #getClassByInstance
    69  	 */
    70  	public function getClass():ClassInfo {
    71  		var o:Overload = new Overload(this);
    72  		o.addHandler([Function], getClassByClass);
    73  		o.addHandler([Object], getClassByInstance);
    74  		return o.forward(arguments);
    75  	}
    76  	
    77  	/**
    78  	 * Returns the class info representing the passed-in {@code clazz}.
    79  	 * 
    80  	 * <p>{@code null} will be returned if:
    81  	 * <ul>
    82  	 *   <li>There is no corresponding {@code ClassInfo} instance cached.</li>
    83  	 *   <li>The passed-in {@code clazz} is {@code null} or {@code undefined}.</li>
    84  	 * </ul>
    85  	 *
    86  	 * @param clazz the class to return the class info for
    87  	 * @return the class info representing the passed-in {@code clazz}
    88  	 */
    89  	public function getClassByClass(clazz:Function):ClassInfo {
    90  		if (clazz === null || clazz === undefined) return null;
    91  		var p:Object = clazz.prototype;
    92  		var c:Number = p.__as2lib__hashCode;
    93  		if (c == undefined) return null;
    94  		if (c == p.__proto__.__as2lib__hashCode) {
    95  			return null;
    96  		}
    97  		return cache[c];
    98  	}
    99  	
   100  	/**
   101  	 * Returns the class info representing the class the {@code instance} was
   102  	 * instantiated of.
   103  	 * 
   104  	 * <p>{@code null} will be returned if:
   105  	 * <ul>
   106  	 *   <li>There is no corresponding {@code ClassInfo} instance cached.</li>
   107  	 *   <li>The passed-in {@code instance} is {@code null} or {@code undefined}.</li>
   108  	 * </ul>
   109  	 *
   110  	 * @param instance the instance to return the appropriate class info for
   111  	 * @return the class info representing the instance's class
   112  	 */
   113  	public function getClassByInstance(instance):ClassInfo {
   114  		if (instance === null || instance === undefined) return null;
   115  		var p:Object = instance.__proto__;
   116  		var c:Number = p.__as2lib__hashCode;
   117  		if (c == undefined) return null;
   118  		if (c == p.__proto__.__as2lib__hashCode) {
   119  			return null;
   120  		}
   121  		return cache[c];
   122  	}
   123  	
   124  	/**
   125  	 * Adds the passed-in {@code classInfo} to the list of cached class infos and returns
   126  	 * this {@code classInfo}.
   127  	 * 
   128  	 * @param classInfo the class info to add
   129  	 * @return the passed-in and added {@code classInfo}
   130  	 */
   131  	public function addClass(info:ClassInfo):ClassInfo {
   132  		if (!info) return null;
   133  		var p = info.getType().prototype;
   134  		var h:Number = p.__as2lib__hashCode;
   135  		if (h != null && h != p.__proto__.__as2lib__hashCode) {
   136  			cache[h] = info;
   137  		} else {
   138  			cache[p.__as2lib__hashCode = hashCodeCounter++] = info;
   139  			_global.ASSetPropFlags(p, "__as2lib__hashCode", 1, true);
   140  		}
   141  		return info;
   142  	}
   143  	
   144  	/**
   145  	 * Returns the package info representing the passed-in {@code package}. 
   146  	 *
   147  	 * <p>{@code null} will be returned if:
   148  	 * <ul>
   149  	 *   <li>There is no corresponding {@code PackageInfo} instance cached.</li>
   150  	 *   <li>The passed-in {@code package} is {@code null} or {@code undefined}.</li>
   151  	 * </ul>
   152  	 *
   153  	 * @param package the package to return the appropriate package info for
   154  	 * @return the pakcage info representing the passed-in {@code package}
   155  	 */
   156  	public function getPackage(package):PackageInfo {
   157  		if (package === null || package === undefined) return null;
   158  		var c:Number = package.__as2lib__hashCode;
   159  		if (c == null) return null;
   160  		if (c == package.__proto__.__as2lib__hashCode) {
   161  			return null;
   162  		}
   163  		return cache[c];
   164  	}
   165  	
   166  	/**
   167  	 * Adds the passed-in {@code packageInfo} to this cache and returns this added
   168  	 * {@code packageInfo}.
   169  	 * 
   170  	 * @param packageInfo the package info to add
   171  	 * @return the passed-in and added {@code packageInfo}
   172  	 */
   173  	public function addPackage(info:PackageInfo):PackageInfo {
   174  		if (!info) return null;
   175  		var p = info.getPackage();
   176  		var h:Number = p.__as2lib__hashCode;
   177  		if (h != null && h != p.__proto__.__as2lib__hashCode) {
   178  			cache[h] = info;
   179  		} else {
   180  			cache[p.__as2lib__hashCode = hashCodeCounter++] = info;
   181  			_global.ASSetPropFlags(p, "__as2lib__hashCode", 1, true);
   182  		}
   183  		return info;
   184  	}
   185  	
   186  	/**
   187  	 * Returns the root package of the whole package hierarchy.
   188  	 * 
   189  	 * <p>The root package is also refered to as the default package.
   190  	 *
   191  	 * <p>The root/default package determines where the {@code ClassAlgorithm} and
   192  	 * {@code PackageAlgorithm} classes start their search.
   193  	 *
   194  	 * @return the root/default package
   195  	 */
   196  	public function getRoot(Void):PackageInfo {
   197  		return root;
   198  	}
   199  	
   200  	/**
   201  	 * Releases all cached class and package infos.
   202  	 *
   203  	 * <p>Note that their {@code __as2lib__hashCode} variable stays the same.
   204  	 */
   205  	public function releaseAll(Void):Void {
   206  		cache = new Array();
   207  		addPackage(root);
   208  	}
   209  	
   210  }