001/*
002 *  This file is part of the Jikes RVM project (http://jikesrvm.org).
003 *
004 *  This file is licensed to You under the Eclipse Public License (EPL);
005 *  You may not use this file except in compliance with the License. You
006 *  may obtain a copy of the License at
007 *
008 *      http://www.opensource.org/licenses/eclipse-1.0.php
009 *
010 *  See the COPYRIGHT.txt file distributed with this work for information
011 *  regarding copyright ownership.
012 */
013package org.jikesrvm.classloader;
014
015import java.util.WeakHashMap;
016
017/**
018 *  Lightweight implementation of a vector of Fields. This class is intended
019 *  to be used by a single thread and is therefore not thread-safe.
020 */
021final class FieldVector {
022  //-----------//
023  // interface //
024  //-----------//
025
026  FieldVector() {
027    array = new RVMField[10];
028  }
029
030  void addElement(RVMField item) {
031    if (cnt == array.length) {
032      adjustLength(cnt << 1); // double size of array
033    }
034    array[cnt++] = item;
035  }
036
037  /**
038   * @return an array of fields, trimmed to size. The returned array
039   *  is canonical: Adding the same set of fields in the same order
040   *  to different newly-created vectors {@code v1} and {@code v2}
041   *  will lead to the same array being returned for both {@code v1}
042   *  and {@code v2} when this method is called.
043   */
044  public RVMField[] finish() {
045    synchronized (RVMField.class) {
046      RVMField[] result = popularFVs.get(this);
047      if (result != null) {
048        array = result;
049        return result;
050      } else {
051        adjustLength(cnt);
052        popularFVs.put(this, array);
053        return array;
054      }
055    }
056  }
057
058  @Override
059  public int hashCode() {
060    int val = 0;
061    for (int i = cnt - 1; i >= 0; i--) {
062      val ^= array[i].hashCode();
063    }
064    return val;
065  }
066
067  @Override
068  public boolean equals(Object obj) {
069    if (obj instanceof FieldVector) {
070      FieldVector that = (FieldVector)obj;
071      if (cnt != that.cnt) return false;
072      for (int i = cnt - 1; i >= 0; i--) {
073        if (array[i] != that.array[i]) return false;
074      }
075      return true;
076    } else {
077      return false;
078    }
079  }
080
081  //----------------//
082  // implementation //
083  //----------------//
084
085  private RVMField[] array;
086  private int cnt;
087
088  private static final RVMField[] empty = new RVMField[0];
089  private static final WeakHashMap<FieldVector, RVMField[]>
090    popularFVs = new WeakHashMap<FieldVector, RVMField[]>();
091
092  private void adjustLength(int newLength) {
093    if (newLength == 0) {
094      array = empty;
095    } else {
096      RVMField[] newElements = new RVMField[newLength];
097      int n = array.length;
098      if (n > newLength) {
099        n = newLength;
100      }
101
102      for (int i = 0; i < n; ++i) {
103        newElements[i] = array[i];
104      }
105
106      array = newElements;
107    }
108  }
109}