diff graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/BaseArrayStore.java @ 13514:0fbee3eb71f0

Ruby: import project.
author Chris Seaton <chris.seaton@oracle.com>
date Mon, 06 Jan 2014 17:12:09 +0000
parents
children
line wrap: on
line diff
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/graal/com.oracle.truffle.ruby.runtime/src/com/oracle/truffle/ruby/runtime/core/array/BaseArrayStore.java	Mon Jan 06 17:12:09 2014 +0000
@@ -0,0 +1,149 @@
+/*
+ * Copyright (c) 2013 Oracle and/or its affiliates. All rights reserved. This
+ * code is released under a tri EPL/GPL/LGPL license. You can use it,
+ * redistribute it and/or modify it under the terms of the:
+ *
+ * Eclipse Public License version 1.0
+ * GNU General Public License version 2
+ * GNU Lesser General Public License version 2.1
+ */
+package com.oracle.truffle.ruby.runtime.core.array;
+
+/**
+ * Contains implementations of as much of the array stores that we could easily share. Much of the
+ * rest depends on static types in method signatures, so is lexically almost the same, but isn't the
+ * same in type, and as the whole point is to avoid boxing, we can't use Java's generics.
+ */
+public abstract class BaseArrayStore implements ArrayStore {
+
+    protected int capacity;
+    protected int size;
+
+    @Override
+    public int size() {
+        return size;
+    }
+
+    /**
+     * Set a range in the array to be another range. You must ensure that the otherValues array is
+     * of the same type as your values array.
+     */
+    protected void setRangeArrayMatchingTypes(int normalisedBegin, int normalisedExclusiveEnd, Object otherValues, int otherSize) {
+        // Is the range the whole array?
+
+        if (normalisedBegin == 0 && normalisedExclusiveEnd == size) {
+            // Do we already have enough space?
+
+            if (otherSize <= capacity) {
+                // Copy to our existing array.
+                final Object values = getValuesArrayObject();
+                System.arraycopy(otherValues, 0, values, 0, otherSize);
+            } else {
+                // Create a new copy of their array.
+                setCapacityWithNewArray(otherSize);
+                final Object values = getValuesArrayObject();
+                System.arraycopy(otherValues, 0, values, 0, otherSize);
+            }
+
+            size = otherSize;
+        } else {
+            final int rangeLength = normalisedExclusiveEnd - normalisedBegin;
+
+            // Create extra space - might be negative if the new range is shorter, or zero.
+
+            final int extraSpaceNeeded = otherSize - rangeLength;
+
+            if (extraSpaceNeeded > 0) {
+                createSpace(normalisedBegin, extraSpaceNeeded);
+            } else if (extraSpaceNeeded < 0) {
+                deleteSpace(normalisedBegin, -extraSpaceNeeded);
+            }
+
+            // Copy across the new values.
+            final Object values = getValuesArrayObject();
+            System.arraycopy(otherValues, 0, values, normalisedBegin, otherSize);
+        }
+    }
+
+    protected void createSpace(int normalisedBegin, int count) {
+        /*
+         * Is this space at the end or in the middle?
+         */
+
+        if (normalisedBegin == size) {
+            createSpaceAtEnd(count);
+        } else {
+            /*
+             * Create space in the middle - is the array already big enough?
+             */
+
+            final int elementsToMove = size - normalisedBegin;
+
+            if (size + count > capacity) {
+                /*
+                 * The array isn't big enough. We don't want to use Arrays.copyOf because that will
+                 * do wasted copying of the elements we are about to move. However - is
+                 * Arrays.copyOf clever enough to see that only one instance of Array is using the
+                 * block and use realloc, potentially avoiding a malloc and winning?
+                 */
+
+                final Object values = getValuesArrayObject();
+                setCapacityWithNewArray(ArrayUtilities.capacityFor(size + count));
+                final Object newValues = getValuesArrayObject();
+                System.arraycopy(values, 0, newValues, 0, normalisedBegin);
+                System.arraycopy(values, normalisedBegin, newValues, normalisedBegin + count, elementsToMove);
+            } else {
+                /*
+                 * The array is already big enough - we can copy elements already in the array to
+                 * make space.
+                 */
+
+                final Object values = getValuesArrayObject();
+                System.arraycopy(values, normalisedBegin, values, normalisedBegin + count, elementsToMove);
+            }
+
+            size += count;
+        }
+    }
+
+    protected void createSpaceAtEnd(int count) {
+        /*
+         * Create space at the end - we can do this by creating a copy of the array if needed.
+         */
+
+        if (size + count > capacity) {
+            setCapacityByCopying(ArrayUtilities.capacityFor(size + count));
+        }
+
+        size += count;
+    }
+
+    protected void deleteSpace(int normalisedBegin, int count) {
+        final Object values = getValuesArrayObject();
+        final int elementsToMove = size - normalisedBegin - count;
+
+        if (elementsToMove > 0) {
+            System.arraycopy(values, normalisedBegin + count, values, normalisedBegin, elementsToMove);
+        }
+
+        size -= count;
+    }
+
+    protected abstract void setCapacityByCopying(int newCapacity);
+
+    protected abstract void setCapacityWithNewArray(int newCapacity);
+
+    protected abstract Object getValuesArrayObject();
+
+    @Override
+    public boolean equals(ArrayStore other) {
+        for (int n = 0; n < size; n++) {
+            if (!other.get(n).equals(get(n))) {
+                return false;
+            }
+        }
+
+        return true;
+    }
+
+}