Ranides Atterwim 3 năm trước cách đây
mục cha
commit
b45579e18a

+ 15 - 11
assira.core/src/main/java/net/ranides/assira/lexer/ByteStreamer.java

@@ -44,6 +44,7 @@ public class ByteStreamer<T> implements Closeable {
     private static final byte[] EMPTY = new byte[0];
     private final BiConsumer<T, byte[]> consumer;
     private byte[] array;
+    private int length;
     private int recent;
     private int position;
 
@@ -55,6 +56,7 @@ public class ByteStreamer<T> implements Closeable {
      */
     public ByteStreamer(BiConsumer<T, byte[]> consumer) {
         this.array     = EMPTY;
+        this.length    = 0;
         this.recent    = 0;
         this.position  = 0;
         this.consumer = consumer;
@@ -83,14 +85,16 @@ public class ByteStreamer<T> implements Closeable {
      * @return this
      */
     public ByteStreamer<T> put(byte[] input) {
-        int pending = array.length - recent;
-        byte[] appended = new byte[pending + input.length];
-        // @todo #90
+        int pending = length - recent;
 
-        System.arraycopy(array, recent, appended, 0, pending);
-        System.arraycopy(input, 0, appended, pending, input.length);
+        length = pending + input.length;
+
+        byte[] appended = length <= array.length ? array : new byte[length];
 
+        System.arraycopy(array, recent, appended, 0, pending);
         array = appended;
+        System.arraycopy(input, 0, array, pending, input.length);
+
         position = position - recent;
         recent = 0;
 
@@ -163,7 +167,7 @@ public class ByteStreamer<T> implements Closeable {
      * @return boolean
      */
     public boolean end() {
-        return position >= array.length;
+        return position >= length;
     }
 
     /**
@@ -172,7 +176,7 @@ public class ByteStreamer<T> implements Closeable {
      * @return int
      */
     public int available() {
-        return Math.max(0, array.length - position);
+        return Math.max(0, length - position);
     }
 
     /**
@@ -206,7 +210,7 @@ public class ByteStreamer<T> implements Closeable {
      * @param rclip rclip
      */
     public void send(T extra, int lclip, int rclip) {
-        if(recent < position && position <= array.length) {
+        if(recent < position && position <= length) {
             send(extra, Arrays.copyOfRange(array, recent+lclip, position-rclip) );
         }
         mark();
@@ -223,14 +227,14 @@ public class ByteStreamer<T> implements Closeable {
     }
 
     private void check() {
-        if(position >= array.length) {
+        if(position >= length) {
             throw new IllegalStateException("Steamer: EOS");
         }
     }
 
     private void check(int offset) {
-        if(position+offset > array.length) {
-            position = array.length;
+        if(position+offset > length) {
+            position = length;
             throw new IllegalStateException("EOS");
         }
     }

+ 20 - 11
assira.core/src/main/java/net/ranides/assira/lexer/CharStreamer.java

@@ -44,6 +44,7 @@ public class CharStreamer<T> implements Closeable {
     private static final char[] EMPTY = new char[0];
     private final BiConsumer<T, char[]> consumer;
     private char[] array;
+    private int length;
     private int recent;
     private int position;
 
@@ -55,6 +56,7 @@ public class CharStreamer<T> implements Closeable {
      */
     public CharStreamer(BiConsumer<T, char[]> consumer) {
         this.array     = EMPTY;
+        this.length    = 0;
         this.recent    = 0;
         this.position  = 0;
         this.consumer  = consumer;
@@ -83,14 +85,21 @@ public class CharStreamer<T> implements Closeable {
      * @return this
      */
     public CharStreamer<T> put(char[] input) {
-        int pending = array.length - recent;
-        char[] appended = new char[pending + input.length];
-        // @todo #90
+        int pending = length - recent;
 
-        System.arraycopy(array, recent, appended, 0, pending);
-        System.arraycopy(input, 0, appended, pending, input.length);
+        length = pending + input.length;
+
+        char[] appended;
+        if(length <= array.length) {
+            appended = array;
+        } else {
+            appended = new char[length];
+        }
 
+        System.arraycopy(array, recent, appended, 0, pending);
         array = appended;
+        System.arraycopy(input, 0, array, pending, input.length);
+
         position = position - recent;
         recent = 0;
 
@@ -163,7 +172,7 @@ public class CharStreamer<T> implements Closeable {
      * @return boolean
      */
     public boolean end() {
-        return position >= array.length;
+        return position >= length;
     }
 
     /**
@@ -172,7 +181,7 @@ public class CharStreamer<T> implements Closeable {
      * @return int
      */
     public int available() {
-        return Math.max(0, array.length - position);
+        return Math.max(0, length - position);
     }
 
     /**
@@ -206,7 +215,7 @@ public class CharStreamer<T> implements Closeable {
      * @param right right
      */
     public void send(T extra, int left, int right) {
-        if(recent < position && position <= array.length) {
+        if(recent < position && position <= length) {
             send(extra, Arrays.copyOfRange(array, recent+left, position-right) );
         }
         mark();
@@ -223,14 +232,14 @@ public class CharStreamer<T> implements Closeable {
     }
 
     private void check() {
-        if(position >= array.length) {
+        if(position >= length) {
             throw new IllegalStateException("Steamer: EOS");
         }
     }
 
     private void check(int offset) {
-        if(position+offset > array.length) {
-            position = array.length;
+        if(position+offset > length) {
+            position = length;
             throw new IllegalStateException("EOS");
         }
     }

+ 34 - 0
assira.core/src/test/java/net/ranides/assira/lexer/ByteStreamerTest.java

@@ -0,0 +1,34 @@
+package net.ranides.assira.lexer;
+
+import org.junit.Test;
+
+import static org.junit.Assert.*;
+
+public class ByteStreamerTest {
+
+    @Test
+    public void allocation() {
+        StringBuilder target = new StringBuilder();
+        ByteStreamer<Object> stream = new ByteStreamer<>((type, data) -> {
+            target.append(type).append("<").append(new String(data)).append(">");
+        });
+
+        stream.put("hello ".getBytes());
+        stream.put("world!".getBytes());
+        stream.forward(8);
+        stream.send("a");
+        stream.put("somewhere".getBytes());
+        stream.forward(8);
+        stream.send("b");
+        stream.put("here".getBytes());
+        stream.forward(stream.available());
+        stream.send("c");
+
+        assertThrows(IllegalStateException.class, () -> {
+            stream.forward(3);
+        });
+
+        assertEquals("a<hello wo>b<rld!some>c<wherehere>", target.toString());
+    }
+
+}

+ 36 - 0
assira.core/src/test/java/net/ranides/assira/lexer/CharStreamerTest.java

@@ -0,0 +1,36 @@
+package net.ranides.assira.lexer;
+
+import net.ranides.assira.text.StringUtils;
+import org.junit.Test;
+
+import java.util.Arrays;
+
+import static org.junit.Assert.*;
+
+public class CharStreamerTest {
+
+    @Test
+    public void allocation() {
+        StringBuilder target = new StringBuilder();
+        CharStreamer<Object> stream = new CharStreamer<>((type, data) -> {
+            target.append(type).append("<").append(new String(data)).append(">");
+        });
+
+        stream.put("hello ".toCharArray());
+        stream.put("world!".toCharArray());
+        stream.forward(8);
+        stream.send("a");
+        stream.put("somewhere".toCharArray());
+        stream.forward(8);
+        stream.send("b");
+        stream.put("here".toCharArray());
+        stream.forward(stream.available());
+        stream.send("c");
+
+        assertThrows(IllegalStateException.class, () -> {
+            stream.forward(3);
+        });
+
+        assertEquals("a<hello wo>b<rld!some>c<wherehere>", target.toString());
+    }
+}