Pārlūkot izejas kodu

new: BenchmarkRunner

new: io.MultiOutputStream # tee
new: reflection.MemberUtils - overloads for Class<?>

new: text.StringEncoder - decodeURL(text, charset)
new: text.StringLoader # linesFromStream
new: text.StringLoader # linesFromReader

change: reflection.PackageScanner - less exceptions in "throws"
change: SetUtils#asTreeSet - return SortedSet

fix: RuntimeUtils # forceGC - better strategy
fix: RuntimeUtils # forceGC - return value
Ranides Atterwim 11 gadi atpakaļ
vecāks
revīzija
0b9987410d
24 mainītis faili ar 1022 papildinājumiem un 411 dzēšanām
  1. 1 1
      src/main/java/net/ranides/assira/collection/SetUtils.java
  2. 18 16
      src/main/java/net/ranides/assira/io/MultiOutputStream.java
  3. 2 2
      src/main/java/net/ranides/assira/nio/Streamable.java
  4. 28 0
      src/main/java/net/ranides/assira/reflection/MemberUtils.java
  5. 5 7
      src/main/java/net/ranides/assira/reflection/PackageScanner.java
  6. 5 3
      src/main/java/net/ranides/assira/system/RuntimeUtils.java
  7. 6 2
      src/main/java/net/ranides/assira/text/StringEncoder.java
  8. 14 5
      src/main/java/net/ranides/assira/text/StringLoader.java
  9. 1 1
      src/main/java/net/ranides/assira/text/StringUtils.java
  10. 298 0
      src/test/java/net/ranides/assira/BenchmarkFormatter.java
  11. 135 0
      src/test/java/net/ranides/assira/BenchmarkRunner.java
  12. 112 205
      src/test/java/net/ranides/assira/collection/map/SwitchMapBenchmark.java
  13. 1 0
      src/test/java/net/ranides/assira/events/ThreadBenchmark.java
  14. 4 25
      src/test/java/net/ranides/assira/reflection/BeanModelTest.java
  15. 53 0
      src/test/java/net/ranides/assira/reflection/MemberUtilsTest.java
  16. 34 0
      src/test/java/net/ranides/assira/reflection/mock/Bean1.java
  17. 42 0
      src/test/java/net/ranides/assira/reflection/mock/ForMemberUtils.java
  18. 34 0
      src/test/java/net/ranides/assira/reflection/mock/StrictFP.java
  19. 3 2
      src/test/java/net/ranides/assira/text/LexicalCastBenchmark.java
  20. 99 0
      src/test/java/net/ranides/assira/text/StringCompilerBenchmark.java
  21. 1 63
      src/test/java/net/ranides/assira/text/StringCompilerTest.java
  22. 63 0
      src/test/java/net/ranides/assira/text/StringUtilsBenchmark.java
  23. 1 46
      src/test/java/net/ranides/assira/text/StringUtilsTest.java
  24. 62 33
      src/test/java/net/ranides/assira/text/StringsBenchmark.java

+ 1 - 1
src/main/java/net/ranides/assira/collection/SetUtils.java

@@ -46,7 +46,7 @@ public final class SetUtils {
      * @param values
      * @return
      */
-    public static <K> Set<K> asTreeSet(K... values) {
+    public static <K> SortedSet<K> asTreeSet(K... values) {
         return new TreeSet<>(Arrays.asList(values));
     }
 

+ 18 - 16
src/main/java/net/ranides/assira/io/MultiOutputStream.java

@@ -9,15 +9,18 @@ package net.ranides.assira.io;
 
 import java.io.IOException;
 import java.io.OutputStream;
+import java.io.PrintStream;
 import java.util.LinkedList;
 import java.util.List;
+import static net.ranides.assira.io.MultiOutputStream.tee;
+import net.ranides.assira.text.TextOutputStream;
 import net.ranides.assira.trace.MultiException;
 
 /**
  * Strumień zapisujący dane do więcej niż jednego celu jednocześnie.
  * @author ranides
  */
-public abstract class MultiOutputStream extends OutputStream {
+public class MultiOutputStream extends OutputStream {
     
     private final OutputStream[] streams;
 
@@ -30,15 +33,22 @@ public abstract class MultiOutputStream extends OutputStream {
         this.streams = streams;
     }
     
+    public static <T extends OutputStream> T tee(T observer) {
+        System.setOut(new PrintStream(new MultiOutputStream(System.out, observer)));
+        return observer;
+    }
+    
+    public static TextOutputStream tee() {
+        return tee(new TextOutputStream());
+    }
+    
     @Override
     public void write(int data) throws IOException {
         List<IOException> errors = null;
         for(OutputStream stream : streams) {
             try {
                 stream.write(data);
-            } catch(IOException cause) {
-                errors = addErrors(errors, stream, cause);
-            } catch(RuntimeException cause) {
+            } catch(IOException | RuntimeException cause) {
                 errors = addErrors(errors, stream, cause);
             }
         }
@@ -52,9 +62,7 @@ public abstract class MultiOutputStream extends OutputStream {
         for(OutputStream stream : streams) {
             try {
                 stream.write(data);
-            } catch(IOException cause) {
-                errors = addErrors(errors, stream, cause);
-            } catch(RuntimeException cause) {
+            } catch(IOException | RuntimeException cause) {
                 errors = addErrors(errors, stream, cause);
             }
         }
@@ -67,9 +75,7 @@ public abstract class MultiOutputStream extends OutputStream {
         for(OutputStream stream : streams) {
             try {
                 stream.write(data, offset, length);
-            } catch(IOException cause) {
-                errors = addErrors(errors, stream, cause);
-            } catch(RuntimeException cause) {
+            } catch(IOException | RuntimeException cause) {
                 errors = addErrors(errors, stream, cause);
             }
         }
@@ -82,9 +88,7 @@ public abstract class MultiOutputStream extends OutputStream {
         for(OutputStream stream : streams) {
             try {
                 stream.close();
-            } catch(IOException cause) {
-                errors = addErrors(errors, stream, cause);
-            } catch(RuntimeException cause) {
+            } catch(IOException | RuntimeException cause) {
                 errors = addErrors(errors, stream, cause);
             }
         }
@@ -97,9 +101,7 @@ public abstract class MultiOutputStream extends OutputStream {
         for(OutputStream stream : streams) {
             try {
                 stream.flush();
-            } catch(IOException cause) {
-                errors = addErrors(errors, stream, cause);
-            } catch(RuntimeException cause) {
+            } catch(IOException | RuntimeException cause) {
                 errors = addErrors(errors, stream, cause);
             }
         }

+ 2 - 2
src/main/java/net/ranides/assira/nio/Streamable.java

@@ -41,8 +41,8 @@ package net.ranides.assira.nio;
  *          <td>I/O random</td>
  *      </tr>
  *      <tr>
- *          <td>{@link java.lang.Readable}</td>
- *          <td>{@link java.lang.Appendable}</td>
+ *          <td>{@link java.io.Reader}</td>
+ *          <td>{@link java.io.Writer}</td>
  *          <td>I/O formatted</td>
  *      </tr>
  *      <tr>

+ 28 - 0
src/main/java/net/ranides/assira/reflection/MemberUtils.java

@@ -21,6 +21,34 @@ public final class MemberUtils {
     
     private MemberUtils() { /* utility class */ }
     
+    public static boolean isStatic(Class<?> clazz) {
+        return Modifier.isStatic(clazz.getModifiers());
+    }
+
+    public static boolean isPublic(Class<?> clazz) {
+        return Modifier.isPublic(clazz.getModifiers());
+    }
+
+    public static boolean isProtected(Class<?> clazz) {
+        return Modifier.isProtected(clazz.getModifiers());
+    }
+
+    public static boolean isPrivate(Class<?> clazz) {
+        return Modifier.isPrivate(clazz.getModifiers());
+    }
+
+    public static boolean isInterface(Class<?> clazz) {
+        return Modifier.isInterface(clazz.getModifiers());
+    }
+
+    public static boolean isFinal(Class<?> clazz) {
+        return Modifier.isFinal(clazz.getModifiers());
+    }
+
+    public static boolean isAbstract(Class<?> clazz) {
+        return Modifier.isAbstract(clazz.getModifiers());
+    }
+    
     public static boolean isVolatile(Member member) {
         return Modifier.isVolatile(member.getModifiers());
     }

+ 5 - 7
src/main/java/net/ranides/assira/reflection/PackageScanner.java

@@ -9,10 +9,7 @@ package net.ranides.assira.reflection;
 import java.io.File;
 import java.io.FileInputStream;
 import java.io.IOException;
-import java.net.URISyntaxException;
 import java.net.URL;
-import java.net.URLDecoder;
-import java.util.Collections;
 import java.util.Enumeration;
 import java.util.HashSet;
 import java.util.Set;
@@ -21,6 +18,7 @@ import java.util.jar.JarInputStream;
 import net.ranides.assira.io.DirectoryHelper;
 import net.ranides.assira.io.PathConvertException;
 import net.ranides.assira.io.PathHelper;
+import net.ranides.assira.text.StringEncoder;
 import net.ranides.assira.text.StringUtils;
 import net.ranides.assira.text.TextEncoding;
 import net.ranides.assira.trace.AdvLogger;
@@ -46,22 +44,22 @@ public final class PackageScanner {
         this.target = new HashSet<>();
     }
     
-    public static Set<Class<?>> list(String packageName) throws IOException, ClassNotFoundException, URISyntaxException {
+    public static Set<Class<?>> list(String packageName) throws IOException {
         return list(packageName, Thread.currentThread().getContextClassLoader());
     }
     
-    public static Set<Class<?>> list(String packageName, ClassLoader loader) throws IOException, ClassNotFoundException, URISyntaxException {
+    public static Set<Class<?>> list(String packageName, ClassLoader loader) throws IOException {
         return new PackageScanner(packageName, loader).list();
     }
 
-    private Set<Class<?>> list() throws IOException, ClassNotFoundException, URISyntaxException {
+    private Set<Class<?>> list() throws IOException {
         Enumeration<URL> resources = loader.getResources(packagePath);
         if (resources == null) {
             return target;
         }
 
         while (resources.hasMoreElements()) {
-            String path = URLDecoder.decode(resources.nextElement().getPath(), TextEncoding.IO_DEFAULT);
+            String path = StringEncoder.decodeURL(resources.nextElement().getPath(), TextEncoding.NIO_DEFAULT);
             File file = new File(path);
             if(file.isDirectory()) {
                 getFromDirectory(file);

+ 5 - 3
src/main/java/net/ranides/assira/system/RuntimeUtils.java

@@ -11,6 +11,7 @@ import java.util.List;
 import net.ranides.assira.generic.PrivilegedActions;
 import net.ranides.assira.math.MathUtils;
 import net.ranides.assira.math.Numeric;
+import net.ranides.assira.time.TimeUtils;
 import net.ranides.assira.trace.AdvLogger;
 import net.ranides.assira.trace.LoggerUtils;
 
@@ -50,16 +51,17 @@ public final class RuntimeUtils {
      *      Estimated amount of memory released by GC
      */
     public static long forceGC() {
-        long prev = getMemoryUse();
+        long prev = Runtime.getRuntime().totalMemory();
+        int block = (int)Math.min(Integer.MAX_VALUE, Runtime.getRuntime().freeMemory());
         try {
             final List<long[]> memhog = new LinkedList<>();
             while(true) {
-                memhog.add(new long[102400]);
+                memhog.add(new long[block]);
             }
         }
         catch(final OutOfMemoryError e) {
             // at this point all SoftReferences have been released - GUARANTEED
-            long alloc = getMemoryUse() - prev;
+            long alloc = Runtime.getRuntime().totalMemory() - prev;
             LOGGER.fdebug("Forced OutOfMemoryError by allocation %s bytes", Numeric.format(alloc));
             Runtime.getRuntime().gc();
             // at this point we should use minimal amount of memory

+ 6 - 2
src/main/java/net/ranides/assira/text/StringEncoder.java

@@ -107,10 +107,14 @@ public final class StringEncoder {
     }
 
     public static String decodeURL(String input) {
+        return decodeURL(input, TextEncoding.NIO_UTF8);
+    }
+    
+    public static String decodeURL(String input, Charset charset) {
         try {
-            return URLDecoder.decode(input, "UTF-8");
+            return URLDecoder.decode(input, charset.name());
         } catch(UnsupportedEncodingException cause) {
-            throw ExceptionInspector.assertError("UTF-8 unsupported", cause);
+            throw ExceptionInspector.assertError("Unsupported charset: " + charset, cause);
         }
     }
 

+ 14 - 5
src/main/java/net/ranides/assira/text/StringLoader.java

@@ -110,13 +110,11 @@ public final class StringLoader {
         }
     }
     
-    public static List<String> linesFromFile(File file, Charset charset) throws RIOException {
-        FileInputStream istream = null;
+    public static List<String> linesFromReader(Reader ireader) throws RIOException {
         BufferedReader reader = null;
         ArrayList<String> result = new ArrayList<>();
         try {
-            istream = new FileInputStream(file);
-            reader = new BufferedReader(new InputStreamReader(istream, charset));
+            reader = new BufferedReader(ireader);
             String line;
             while( null != (line=reader.readLine())) {
                 result.add(line);
@@ -125,12 +123,23 @@ public final class StringLoader {
             throw new RIOException(cause);
         } finally {
             FileHelper.close(reader);
-            FileHelper.close(istream);
         }
         result.trimToSize();
         return result;
     }
     
+    public static List<String> linesFromStream(InputStream istream, Charset charset) throws RIOException {
+        return linesFromReader(new BufferedReader(new InputStreamReader(istream, charset)));
+    }
+    
+    public static List<String> linesFromFile(File file, Charset charset) throws RIOException {
+        try {
+            return linesFromStream(new FileInputStream(file), charset);
+        } catch(IOException cause) {
+            throw new RIOException(cause);
+        }
+    }
+    
     public static List<String> linesFromFile(String file, Charset charset) throws RIOException {
         return linesFromFile(new File(file), charset);
     }

+ 1 - 1
src/main/java/net/ranides/assira/text/StringUtils.java

@@ -485,5 +485,5 @@ public final class StringUtils {
     public static String escapeRegex(String text) {
         return REGEX_SPECIAL.matcher(text).replaceAll("\\\\$1");
     }
-
+    
 }

+ 298 - 0
src/test/java/net/ranides/assira/BenchmarkFormatter.java

@@ -0,0 +1,298 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira;
+
+import com.google.caliper.SimpleBenchmark;
+import java.io.IOException;
+import java.io.PrintStream;
+import java.io.PrintWriter;
+import java.util.ArrayList;
+import java.util.Collections;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Map;
+import java.util.Set;
+import java.util.TreeMap;
+import java.util.regex.Matcher;
+import java.util.regex.Pattern;
+import net.ranides.assira.collection.CollectionUtils;
+import net.ranides.assira.collection.map.SwitchMapBenchmark;
+import net.ranides.assira.reflection.ClassInspector;
+import net.ranides.assira.reflection.InspectException;
+import net.ranides.assira.text.StringUtils;
+import net.ranides.assira.text.Strings;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public final class BenchmarkFormatter {
+    
+    private final Map<String, ParamTable> params = new HashMap<>();
+    
+    public static List<Integer> parseParams(Class<?> clazz) {
+        try {
+            return parseParams((String)ClassInspector.getStaticField(clazz, "PARAMS"));
+        } catch(InspectException cause) {
+            return Collections.emptyList();
+        }
+    }
+    
+    public static List<Integer> parseParams(String input) {
+        BenchmarkFormatter bfr = new BenchmarkFormatter();
+        bfr.putParams(input);
+        ParamTable table = CollectionUtils.first(bfr.params.values());
+        
+        List<Integer> ret = new ArrayList<>();
+        for(String[] row : table.values) {
+            ret.add( Integer.parseInt(row[0]) );
+        }
+        return ret;
+    }
+    
+    public static void report(List<Class<?>> list, String data) {
+        BenchmarkFormatter formatter = new BenchmarkFormatter();
+        for(Class<?> clazz : list ) {
+            if( SimpleBenchmark.class.isAssignableFrom(clazz) ) {
+                formatter.putParams(clazz);
+            }
+        }
+        formatter.print(data);
+    }
+    
+    public static void report(Class<?> clazz, String data) {
+        BenchmarkFormatter formatter = new BenchmarkFormatter();
+        if( SimpleBenchmark.class.isAssignableFrom(clazz) ) {
+            formatter.putParams(clazz);
+        }
+        formatter.print(data);
+    }
+    
+    private void putParams(Class<?> clazz) {
+        try {
+            putParams((String)ClassInspector.getStaticField(clazz, "PARAMS"));
+        } catch(InspectException cause) {
+            // do nothing
+        }
+    }
+    
+    private void putParams(String input) {
+        ParamBuilder builder = new ParamBuilder();
+
+        for(String line : input.split("[\\n\\r]+")) {
+            line = line.trim();
+            if( line.startsWith("FOR:") ) {
+                builder.name(line);
+            }
+            else if( line.startsWith("HEADER:") ) {
+                builder.open(line);
+            } 
+            else {
+                builder.row(line);
+            }
+        }
+        builder.close();
+    }
+    
+    private void print(String input) {
+        format(System.out, input);
+    }
+    
+    private void format(PrintStream out, String input) {
+        Pattern RE_BENCHMARK = Pattern.compile("\\{vm=(.+?), trial=(.+?), benchmark=(.+?)(?:, param=(.+?))?\\} ([0-9,]+) ns; \\?=([0-9,]+) ns @ ([0-9]+) trials");
+        
+        BInfoCollection result = new BInfoCollection();
+        for(String line : input.split("[\\n\\r]+")) {
+            Matcher hit = RE_BENCHMARK.matcher(line);
+            if(hit.find()) {
+                result.add(new BInfo(hit));
+            }
+        }
+        
+        for(BInfoForName biname : result.map.values()) {
+            ParamTable ptable = params.get( biname.first().name );
+            
+            out.printf("name,");
+            if( null != ptable ) {
+                ptable.formatHeader(out);
+            } else {
+                out.printf("param,");
+            }
+            out.printf("trials,average,deviation%n");
+            
+            for(BInfoForParam biparam : biname.map.values()) {
+                int trials = biparam.list.size();
+                double avg = 0;
+                double dev = 0;
+                for(BInfo info : biparam.list) {
+                    avg += info.time;
+                }
+                avg = avg / trials;
+                
+                for(BInfo info : biparam.list) {
+                    dev += (avg - info.time) * (avg - info.time);
+                }
+                dev = Math.sqrt(dev);
+                
+                out.printf("%s,", biparam.list.get(0).name);
+                if( null != ptable ) {
+                    ptable.formatRow(out, biparam.list.get(0).param);
+                } else {
+                    out.printf("%d,", biparam.list.get(0).param);
+                }
+                out.printf("%d,%.0f,%.0f%n", trials, avg, dev);
+            }
+            out.println();
+        }
+    }
+        
+    private class ParamBuilder {
+
+        public Set<String> keys = new HashSet<>();
+        
+        public ParamTable table = null;
+        
+        public void open(String line) {
+            assert null == table;
+            table = new ParamTable(line);
+        }
+
+        public void close()  {
+            if(null == table) {
+                return;
+            }
+            for(String name : keys) {
+                params.put(name, table);
+            }
+            keys.clear();
+            table = null;
+        }
+        
+        public void name(String line) {
+            close();
+            keys.add(StringUtils.after(line, "FOR:").trim());
+        }
+        
+        public void row(String line) {
+            if(null != table ) {
+                table.add(line);
+            }
+        }
+        
+    }
+    
+    private static class ParamTable {
+        
+        public String[] columns;
+        public List<String[]> values = new ArrayList<>();
+
+        public ParamTable(String header) {
+            columns = StringUtils.after(header, "HEADER:").split(",");
+            for(int i=0; i<columns.length; i++) {
+                columns[i] = columns[i].trim();
+            }
+        }
+        
+        public void add(String line) {
+            int n = columns.length;
+            String[] irow = line.split(",");
+            if(irow.length != n) {
+                return;
+            }
+            String[] row = new String[columns.length];
+            for(int i=0; i<columns.length; i++) {
+                row[i] = irow[i].trim();
+            }
+            values.add(row);
+        }
+        
+        public void formatHeader(PrintStream out) {
+            for(String c : columns) {
+                out.printf("%s,",c);
+            }
+        }
+        
+        public void formatRow(PrintStream out, int row) {
+            for(String c : values.get(row)) {
+                out.printf("%s,",c);
+            }
+        }
+        
+    }
+    
+    private static class BInfoCollection {
+        
+        public final TreeMap<String, BInfoForName> map = new TreeMap<>();
+        
+        public void add(BInfo info) {
+            if( !map.containsKey(info.name) ) {
+                map.put(info.name, new BInfoForName());
+            }
+            map.get(info.name).add(info);
+        }
+        
+        public BInfo first() {
+            return map.firstEntry().getValue().first();
+        }
+        
+                
+    }
+
+    private static class BInfoForName {
+        
+        public final TreeMap<Integer, BInfoForParam> map = new TreeMap<>();
+        
+        public void add(BInfo info) {
+            if( !map.containsKey(info.param) ) {
+                map.put(info.param, new BInfoForParam());
+            }
+            map.get(info.param).add(info);
+        }
+        
+        public BInfo first() {
+            return map.firstEntry().getValue().first();
+        }
+        
+    }
+    
+    private static class BInfoForParam {
+        
+        public final List<BInfo> list = new ArrayList<>();
+        
+        public void add(BInfo info) {
+            list.add(info);
+        }
+        
+        public BInfo first() {
+            return list.get(0);
+        }
+        
+    }
+    
+    private static class BInfo {
+        
+        public final String name;
+        public final int param;
+        public final String trial;
+        public final double time;
+        public final double timeDev;
+        
+        public BInfo(Matcher hit) {
+            this.name = hit.group(3);
+            this.param = Integer.parseInt(Strings.or(hit.group(4),"0"));
+            this.trial = hit.group(2);
+            this.time = Double.parseDouble(hit.group(5).replace(',', '.'));
+            this.timeDev = Double.parseDouble(hit.group(6).replace(',', '.'));
+        }
+        
+        public void print(PrintStream out) {
+            out.printf("%s(%s):%s = %s+%s%n", name, trial, param, time, timeDev);
+        }
+    }
+
+}

+ 135 - 0
src/test/java/net/ranides/assira/BenchmarkRunner.java

@@ -0,0 +1,135 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira;
+
+import com.google.caliper.SimpleBenchmark;
+import java.io.IOException;
+import java.io.OutputStream;
+import java.lang.reflect.Method;
+import java.util.ArrayList;
+import java.util.List;
+import net.ranides.assira.io.MultiOutputStream;
+import net.ranides.assira.reflection.ClassInspector;
+import net.ranides.assira.reflection.Invoker;
+import net.ranides.assira.reflection.MemberUtils;
+import net.ranides.assira.reflection.PackageScanner;
+import net.ranides.assira.trace.StackInspector;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public final class BenchmarkRunner {
+    
+    private BenchmarkRunner() {
+        // utility class
+    }
+    
+    public static void main(String[] args) throws IOException {
+        List<Class<?>> found = find();
+        print(found);
+        OutputStream collector = MultiOutputStream.tee();
+        for(Class<?> clazz : found) {
+            invoke(clazz);
+        }
+        BenchmarkFormatter.report(found, collector.toString());
+    }
+    
+    public static void run32() {
+        String clazzname = StackInspector.frame(StackInspector.CALLER).getClassName();
+        Class<?> clazz = ClassInspector.forName(clazzname);
+        run32(clazz);
+    }
+    
+    public static void run32(Class<?> clazz) {
+        OutputStream collector = MultiOutputStream.tee();
+        invoke(clazz);
+        BenchmarkFormatter.report(clazz, collector.toString());
+    }
+    
+    private static void invoke(Class<?> clazz) {
+        if (!isBenchmark(clazz) ) {
+            Invoker.invokeStatic(clazz, "main", new Object[]{new String[0]});
+            return;
+        }
+        
+        String[] args = new String[]{
+            "--trials", 
+            "3",
+            "--warmupMillis", 
+            "100",
+            "--runMillis", 
+            "100",
+            "-Dparam=0",
+            clazz.getName()
+        };
+        
+        List<Integer> params = BenchmarkFormatter.parseParams(clazz);
+        if( params.isEmpty() ) {
+            new com.google.caliper.Runner().run(args);
+            return;
+        }
+        
+        for(int param : params) {
+            args[ args.length - 2 ] = String.format("-Dparam=%d",param);
+            new com.google.caliper.Runner().run(args);
+        }
+        
+    }
+    
+    private static void print(List<Class<?>> list) {
+        for(Class<?> clazz : list ) {
+            String type = isBenchmark(clazz) ? 
+                "caliper" : "generic";
+            System.out.printf("[INFO] %s: %s%n", type, clazz.getName());
+        }
+    }
+    
+    private static List<Class<?>> find() throws IOException {
+        List<Class<?>> list = new ArrayList<>();
+        for(Class<?> clazz : PackageScanner.list("net.ranides.assira")) {
+            if(clazz == BenchmarkRunner.class) {
+                continue;
+            }
+            if( isRunnable(clazz) ) {
+                list.add(clazz);
+            }
+        }
+        return list;
+    }
+    
+    private static boolean isRunnable(Class<?> clazz) {
+        if(clazz.isAnonymousClass() || null != clazz.getDeclaringClass()) {
+            return false;
+        }
+        if(MemberUtils.isAbstract(clazz)) {
+            return false;
+        }
+        // only public
+        if(!MemberUtils.isPublic(clazz)) {
+            return false;
+        }
+        // benchmarks
+        if(isBenchmark(clazz)) {
+            return true;
+        }
+        // runnable classes
+        if( !ClassInspector.hasMethod(clazz, "main", String[].class) ) {
+            return false;
+        }
+        Method method = ClassInspector.getMethod(clazz, "main", String[].class);
+        if( !MemberUtils.isPublic(method) || !MemberUtils.isStatic(method) ) {
+            return false;
+        }
+        return true;
+    }
+    
+    private static boolean isBenchmark(Class<?> clazz) {
+        return SimpleBenchmark.class.isAssignableFrom(clazz);
+    }
+}
+

+ 112 - 205
src/test/java/net/ranides/assira/collection/map/SwitchMapBenchmark.java

@@ -6,15 +6,20 @@
  */
 package net.ranides.assira.collection.map;
 
-import com.google.caliper.Runner;
+import com.google.caliper.Param;
 import com.google.caliper.SimpleBenchmark;
+import com.google.caliper.runner.InvalidBenchmarkException;
+import com.google.caliper.util.InvalidCommandException;
 import java.util.HashMap;
 import java.util.Map;
 import java.util.SortedMap;
 import java.util.TreeMap;
+import net.ranides.assira.BenchmarkRunner;
 import net.ranides.assira.math.Randomizer;
+import net.ranides.assira.text.Strings;
 
 /**
+ * @todo (assira # 3) caliper automatic conversion to CSV
  * Comparison of performance #get methods
  * 
  * RESULTS:
@@ -56,82 +61,124 @@ import net.ranides.assira.math.Randomizer;
  * @author ranides
  */
 public class SwitchMapBenchmark extends SimpleBenchmark {
-
-    private IntMaps intTT;
-    private IntMaps intSS;
-    private IntMaps intSM;
-    private IntMaps intSL;
-    private IntMaps intMM;
-    private IntMaps intLL;
-    private IntMaps intED;
     
-    private StrMaps strTT;
-    private StrMaps strSS;
-    private StrMaps strSM;
-    private StrMaps strSL;
-    private StrMaps strMM;
-    private StrMaps strLL;
-    private StrMaps strED;
-        
+    public static final String PARAMS = Strings.raw(/*
+        FOR: Int_hash
+        FOR: Int_tree
+        FOR: Int_hash
+            
+        HEADER: param, in, idomain
+            
+        0,     32,         1000
+        1,    256,         1000
+        2,    256,       100000
+        3,    256,   1000000000
+        4,  10000,   1000000000
+        5, 100000,   1000000000
+        6,  10000,        10000
+    
+        FOR: Str_hash
+        FOR: Str_tree
+        FOR: Str_hash
+            
+        HEADER: param, sn, sdomain
+        0,     32,         100099
+        1,    256,         100099
+        2,    256,       10000099
+        3,    256,   100000000099
+        4,  10000,   100000000099
+        5, 100000,   100000000099
+        6,  10000,        1000099
+    */);
+    
+    private static final IntParams[] IPARAMS = {
+        new IntParams(     32,         1_000 ),
+        new IntParams(    256,         1_000 ),
+        new IntParams(    256,       100_000 ),
+        new IntParams(    256, 1_000_000_000 ),
+        new IntParams( 10_000, 1_000_000_000 ),
+        new IntParams(100_000, 1_000_000_000 ),
+        new IntParams( 10_000,        10_000 )
+    };
+    
+    private static final StrParams[] SPARAMS = {
+        new StrParams(32,         1_000 ),
+        new StrParams(    256,         1_000 ),
+        new StrParams(    256,       100_000 ),
+        new StrParams(    256, 1_000_000_000 ),
+        new StrParams( 10_000, 1_000_000_000 ),
+        new StrParams(100_000, 1_000_000_000 ),
+        new StrParams( 10_000,        10_000 )
+    };
+            
+    @Param
+    private int param;
+    
+    private IntParams iparams;
+    private StrParams sparams;
+    
     @Override
     public void setUp() {
-        intTT = new IntMaps(     32,         1_000 );
-        intSS = new IntMaps(    256,         1_000 );
-        intSM = new IntMaps(    256,       100_000 );
-        intSL = new IntMaps(    256, 1_000_000_000 );
-        intMM = new IntMaps( 10_000, 1_000_000_000 );
-        intLL = new IntMaps(100_000, 1_000_000_000 );
-        intED = new IntMaps( 10_000,        10_000 );
-        
-        strTT = new StrMaps(     32,         1_000 );
-        strSS = new StrMaps(    256,         1_000 );
-        strSM = new StrMaps(    256,       100_000 );
-        strSL = new StrMaps(    256, 1_000_000_000 );
-        strMM = new StrMaps( 10_000, 1_000_000_000 );
-        strLL = new StrMaps(100_000, 1_000_000_000 );
-        strED = new StrMaps( 10_000,        10_000 );
+        iparams = IPARAMS[param].init();
+        sparams = SPARAMS[param].init();
     }
     
-    private static final class IntMaps {
+    private static final class IntParams {
         
+        public final int n;
         public final int domain;
-        public final SortedMap<Integer,Character> tree;
-        public final Map<Integer,Character> smap;
-        public final Map<Integer,Character> hash;
         
-        public IntMaps(int n, int domain) {
+        public transient SortedMap<Integer,Character> tree;
+        public transient Map<Integer,Character> smap;
+        public transient Map<Integer,Character> hash;
+
+        public IntParams(int n, int domain) {
+            this.n = n;
             this.domain = domain;
-            this.tree = new TreeMap<>();
+        }
+        
+        public IntParams init() {
+            tree = new TreeMap<>();
             for(int i=0; i<n; i++) {
                 int key = Randomizer.number(domain);
                 char val = Randomizer.character();
-                this.tree.put(key, val);
+                tree.put(key, val);
             }
-            this.smap = new SwitchMap<>(tree);
-            this.hash = new HashMap<>(tree);
+            smap = new SwitchMap<>(tree);
+            hash = new HashMap<>(tree);
+            
+            return this;
         }
     }
     
-    private static final class StrMaps {
+    private static final class StrParams {
         
+        public final int n;
         public final int domain;
-        public final SortedMap<String,Character> tree;
-        public final Map<String,Character> smap;
-        public final Map<String,Character> hash;
         
-        public StrMaps(int n, int domain) {
+        public transient SortedMap<String,Character> tree;
+        public transient Map<String,Character> smap;
+        public transient Map<String,Character> hash;
+
+        public StrParams(int n, int domain) {
+            this.n = n;
             this.domain = domain;
-            this.tree = new TreeMap<>();
+        }
+        
+        public StrParams init() {
+            tree = new TreeMap<>();
             for(int i=0; i<n; i++) {
                 String key = Integer.toHexString(Randomizer.number(domain));
                 char val = Randomizer.character();
                 this.tree.put(key, val);
             }
-            this.smap = new SwitchMap<>(tree);
-            this.hash = new HashMap<>(tree);
+            smap = new SwitchMap<>(tree);
+            hash = new HashMap<>(tree);
+            
+            return this;
         }
     }
-
+    
     private int itimeIntMap(int reps, int domain, Map<Integer, Character> map) {
         int c = 0;
         for(int i=0; i<reps; i++) {
@@ -151,173 +198,33 @@ public class SwitchMapBenchmark extends SimpleBenchmark {
         }
         return c;
     }
-//    
-//    public int timeIntSS_tree(int reps) {
-//        return itimeIntMap(reps, intSS.domain, intSS.tree);
-//    }
-//    
-//    public int timeIntSM_tree(int reps) {
-//        return itimeIntMap(reps, intSM.domain, intSM.tree);
-//    }
-//    
-//    public int timeIntSL_tree(int reps) {
-//        return itimeIntMap(reps, intSL.domain, intSL.tree);
-//    }
-//    
-//    public int timeIntMM_tree(int reps) {
-//        return itimeIntMap(reps, intMM.domain, intMM.tree);
-//    }
-//    
-//    public int timeIntLL_tree(int reps) {
-//        return itimeIntMap(reps, intLL.domain, intLL.tree);
-//    }
-//    
-//    public int timeIntSS_hash(int reps) {
-//        return itimeIntMap(reps, intSS.domain, intSS.hash);
-//    }
-//    
-//    public int timeIntSM_hash(int reps) {
-//        return itimeIntMap(reps, intSM.domain, intSM.hash);
-//    }
-//    
-//    public int timeIntSL_hash(int reps) {
-//        return itimeIntMap(reps, intSL.domain, intSL.hash);
-//    }
-//    
-//    public int timeIntMM_hash(int reps) {
-//        return itimeIntMap(reps, intMM.domain, intMM.hash);
-//    }
-//    
-//    public int timeIntLL_hash(int reps) {
-//        return itimeIntMap(reps, intLL.domain, intLL.hash);
-//    }
-//    
-//    public int timeIntSS_smap(int reps) {
-//        return itimeIntMap(reps, intSS.domain, intSS.smap);
-//    }
-//    
-//    public int timeIntSM_smap(int reps) {
-//        return itimeIntMap(reps, intSM.domain, intSM.smap);
-//    }
-//    
-//    public int timeIntSL_smap(int reps) {
-//        return itimeIntMap(reps, intSL.domain, intSL.smap);
-//    }
-//    
-//    public int timeIntMM_smap(int reps) {
-//        return itimeIntMap(reps, intMM.domain, intMM.smap);
-//    }
-//    
-//    public int timeIntED_smap(int reps) {
-//        return itimeIntMap(reps, intED.domain, intED.smap);
-//    }
-//    
-//    public int timeIntED_tree(int reps) {
-//        return itimeIntMap(reps, intED.domain, intED.tree);
-//    }
-//    
-//    public int timeIntED_hash(int reps) {
-//        return itimeIntMap(reps, intED.domain, intED.hash);
-//    }
     
-    public int timeIntTT_smap(int reps) {
-        return itimeIntMap(reps, intTT.domain, intTT.smap);
+    public int timeInt_smap(int reps) {
+        return itimeIntMap(reps, iparams.domain, iparams.smap);
     }
     
-    public int timeIntTT_tree(int reps) {
-        return itimeIntMap(reps, intTT.domain, intTT.tree);
+    public int timeInt_tree(int reps) {
+        return itimeIntMap(reps, iparams.domain, iparams.tree);
     }
     
-    public int timeIntTT_hash(int reps) {
-        return itimeIntMap(reps, intTT.domain, intTT.hash);
+    public int timeInt_hash(int reps) {
+        return itimeIntMap(reps, iparams.domain, iparams.hash);
     }
     
-//    
-//    public int timeStrSS_tree(int reps) {
-//        return itimeStrMap(reps, strSS.domain, strSS.tree);
-//    }
-//    
-//    public int timeStrSM_tree(int reps) {
-//        return itimeStrMap(reps, strSM.domain, strSM.tree);
-//    }
-//    
-//    public int timeStrSL_tree(int reps) {
-//        return itimeStrMap(reps, strSL.domain, strSL.tree);
-//    }
-//    
-//    public int timeStrMM_tree(int reps) {
-//        return itimeStrMap(reps, strMM.domain, strMM.tree);
-//    }
-//    
-//    public int timeStrLL_tree(int reps) {
-//        return itimeStrMap(reps, strLL.domain, strLL.tree);
-//    }
-//    
-//    public int timeStrSS_hash(int reps) {
-//        return itimeStrMap(reps, strSS.domain, strSS.hash);
-//    }
-//    
-//    public int timeStrSM_hash(int reps) {
-//        return itimeStrMap(reps, strSM.domain, strSM.hash);
-//    }
-//    
-//    public int timeStrSL_hash(int reps) {
-//        return itimeStrMap(reps, strSL.domain, strSL.hash);
-//    }
-//    
-//    public int timeStrMM_hash(int reps) {
-//        return itimeStrMap(reps, strMM.domain, strMM.hash);
-//    }
-//    
-//    public int timeStrLL_hash(int reps) {
-//        return itimeStrMap(reps, strLL.domain, strLL.hash);
-//    }
-//    
-//    public int timeStrSS_smap(int reps) {
-//        return itimeStrMap(reps, strSS.domain, strSS.smap);
-//    }
-//    
-//    public int timeStrSM_smap(int reps) {
-//        return itimeStrMap(reps, strSM.domain, strSM.smap);
-//    }
-//    
-//    public int timeStrSL_smap(int reps) {
-//        return itimeStrMap(reps, strSL.domain, strSL.smap);
-//    }
-//    
-//    public int timeStrMM_smap(int reps) {
-//        return itimeStrMap(reps, strMM.domain, strMM.smap);
-//    }
-//    
-//    public int timeStrLL_smap(int reps) {
-//        return itimeStrMap(reps, strLL.domain, strLL.smap);
-//    }
-//    
-//    public int timeStrED_smap(int reps) {
-//        return itimeStrMap(reps, strED.domain, strED.smap);
-//    }
-//    
-//    public int timeStrED_tree(int reps) {
-//        return itimeStrMap(reps, strED.domain, strED.tree);
-//    }
-//    
-//    public int timeStrED_hash(int reps) {
-//        return itimeStrMap(reps, strED.domain, strED.hash);
-//    }
-    
-    public int timeStrTT_smap(int reps) {
-        return itimeStrMap(reps, strTT.domain, strTT.smap);
+    public int timeStr_smap(int reps) {
+        return itimeStrMap(reps, iparams.domain, sparams.smap);
     }
     
-    public int timeStrTT_tree(int reps) {
-        return itimeStrMap(reps, strTT.domain, strTT.tree);
+    public int timeStr_tree(int reps) {
+        return itimeStrMap(reps, iparams.domain, sparams.tree);
     }
     
-    public int timeStrTT_hash(int reps) {
-        return itimeStrMap(reps, strTT.domain, strTT.hash);
+    public int timeStr_hash(int reps) {
+        return itimeStrMap(reps, iparams.domain, sparams.hash);
     }
     
-    public static void main(String[] args) {
-        Runner.main(SwitchMapBenchmark.class, args);
+    public static void main(String[] args) throws InvalidCommandException, InvalidBenchmarkException {
+        BenchmarkRunner.run32();
     }
+   
 }

+ 1 - 0
src/test/java/net/ranides/assira/events/ThreadBenchmark.java

@@ -31,6 +31,7 @@ import net.ranides.assira.time.TimeUtils;
  */
 public class ThreadBenchmark {
     
+    @SuppressWarnings("PMD.SystemPrintln")
     public static void main(String[] args) throws InterruptedException {
         TimeStack tsm = new TimeStack();
         final Semaphore count = new Semaphore(Integer.MAX_VALUE, true);

+ 4 - 25
src/test/java/net/ranides/assira/reflection/BeanModelTest.java

@@ -6,11 +6,9 @@
  */
 package net.ranides.assira.reflection;
 
+import net.ranides.assira.reflection.mock.Bean1;
 import java.util.ArrayList;
-import java.util.Arrays;
-import java.util.HashMap;
 import java.util.List;
-import java.util.Map;
 import org.junit.Test;
 import static org.junit.Assert.*;
 
@@ -26,11 +24,11 @@ public class BeanModelTest {
     @Test
     public void testEach() {
         
-        List<A> items = new ArrayList<>(5);
+        List<Bean1> items = new ArrayList<>(5);
         for(int i=0; i<5; i++) {
-            items.add(new A(i,10*i,100*i));
+            items.add(new Bean1(i,10*i,100*i));
         }
-        A item = items.get(3);
+        Bean1 item = items.get(3);
         
         BeanModel model = BeanModel.fromObject(items.get(0));
         
@@ -57,24 +55,5 @@ public class BeanModelTest {
         assertEquals( (Integer)5, model.get(item, "width"));
     }
     
-    static class A {
-        public final int width;
-        public int height;
-        private int hellovalue;
-        
-        public A(int width, int height, int hello) {
-            this.width = width;
-            this.height = height;
-            this.hellovalue = hello;
-        }
-
-        public int getHello() {
-            return hellovalue;
-        }
-
-        public void setHello(int v) {
-            hellovalue = v;
-        }
-    }
     
 }

+ 53 - 0
src/test/java/net/ranides/assira/reflection/MemberUtilsTest.java

@@ -0,0 +1,53 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.reflection;
+
+import java.io.IOException;
+import java.util.SortedSet;
+import java.util.TreeSet;
+import net.ranides.assira.collection.SetUtils;
+import net.ranides.assira.reflection.mock.ForMemberUtils;
+import net.ranides.assira.reflection.mock.StrictFP.*;
+import org.junit.Test;
+import static org.junit.Assert.*;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+public class MemberUtilsTest {
+    
+    public MemberUtilsTest() {
+    }
+
+    @Test
+    public void testClassModifiers() throws Exception {
+        assertTrue( MemberUtils.isAbstract(ForMemberUtils.ABSTRACT) );
+        assertTrue( MemberUtils.isFinal(ForMemberUtils.FINAL) );
+        assertTrue( MemberUtils.isInterface(ForMemberUtils.INTERFACE) );
+        assertTrue( MemberUtils.isPrivate(ForMemberUtils.PRIVATE) );
+        assertTrue( MemberUtils.isProtected(ForMemberUtils.PROTECTED) );
+        assertTrue( MemberUtils.isPublic(ForMemberUtils.PUBLIC) );
+        assertTrue( MemberUtils.isStatic(ForMemberUtils.STATIC) );
+        
+        assertFalse( MemberUtils.isAbstract(ForMemberUtils.NOTHING) );
+        assertFalse( MemberUtils.isFinal(ForMemberUtils.NOTHING) );
+        assertFalse( MemberUtils.isInterface(ForMemberUtils.NOTHING) );
+        assertFalse( MemberUtils.isPrivate(ForMemberUtils.NOTHING) );
+        assertFalse( MemberUtils.isProtected(ForMemberUtils.NOTHING) );
+        assertFalse( MemberUtils.isPublic(ForMemberUtils.NOTHING) );
+        assertFalse( MemberUtils.isStatic(ForMemberUtils.NOTHING) );
+    }
+    
+    @Test
+    public void testStrict() {
+        assertTrue( MemberUtils.isStrict(ClassInspector.findMethod(Strict1.class, "method")) );
+        assertTrue( MemberUtils.isStrict(ClassInspector.findMethod(Strict2.class, "method")) );
+        assertFalse( MemberUtils.isStrict(ClassInspector.findMethod(Strict3.class, "method")) );
+    }
+    
+}

+ 34 - 0
src/test/java/net/ranides/assira/reflection/mock/Bean1.java

@@ -0,0 +1,34 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.reflection.mock;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+@SuppressWarnings("PMD")
+public class Bean1 {
+    
+    public final int width;
+    public int height;
+    private int hellovalue;
+
+    public Bean1(int width, int height, int hello) {
+        this.width = width;
+        this.height = height;
+        this.hellovalue = hello;
+    }
+
+    public int getHello() {
+        return hellovalue;
+    }
+
+    public void setHello(int v) {
+        hellovalue = v;
+    }
+    
+}

+ 42 - 0
src/test/java/net/ranides/assira/reflection/mock/ForMemberUtils.java

@@ -0,0 +1,42 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.reflection.mock;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+@SuppressWarnings("PMD")
+public class ForMemberUtils {
+    
+    public static final Class<?> ABSTRACT   = CAbstract.class;
+    public static final Class<?> FINAL      = CFinal.class;
+    public static final Class<?> INTERFACE  = CInterface.class;
+    public static final Class<?> PRIVATE    = CPrivate.class;
+    public static final Class<?> PROTECTED  = CProtected.class;
+    public static final Class<?> PUBLIC     = CPublic.class;
+    public static final Class<?> STATIC     = CStatic.class;
+    public static final Class<?> NOTHING    = CNothing.class;
+    
+    
+    public class CPublic { }
+    
+    protected class CProtected { }
+    
+    private class CPrivate { }
+    
+    interface CInterface { }
+    
+    abstract class CAbstract { }
+    
+    final class CFinal { }
+    
+    static class CStatic { }
+    
+    class CNothing { }
+    
+}

+ 34 - 0
src/test/java/net/ranides/assira/reflection/mock/StrictFP.java

@@ -0,0 +1,34 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+package net.ranides.assira.reflection.mock;
+
+/**
+ *
+ * @author Ranides Atterwim <ranides@gmail.com>
+ */
+@SuppressWarnings("PMD")
+public class StrictFP {
+
+    public static strictfp class Strict1 {
+
+        public float method() { return Float.NaN; }
+        
+    }
+
+    public static class Strict2 {
+
+        public strictfp float method() { return Float.NaN; }
+        
+    }
+
+    public static class Strict3 {
+
+        public float method() { return Float.NaN; }
+        
+    }
+
+}

+ 3 - 2
src/test/java/net/ranides/assira/text/LexicalCastBenchmark.java

@@ -6,13 +6,14 @@
  */
 package net.ranides.assira.text;
 
-import com.google.caliper.Runner;
 import com.google.caliper.SimpleBenchmark;
+import net.ranides.assira.BenchmarkRunner;
 
 /**
  *
  * @author Ranides Atterwim <ranides@gmail.com>
  */
+@SuppressWarnings("PMD.AvoidDuplicateLiterals")
 public class LexicalCastBenchmark extends SimpleBenchmark {
     
     
@@ -132,6 +133,6 @@ public class LexicalCastBenchmark extends SimpleBenchmark {
     }
 
     public static void main(String[] args) {
-        Runner.main(LexicalCastBenchmark.class, args);
+        BenchmarkRunner.run32();
     }
 }

+ 99 - 0
src/test/java/net/ranides/assira/text/StringCompilerBenchmark.java

@@ -0,0 +1,99 @@
+/*
+ *  @author Ranides Atterwim <ranides@gmail.com>
+ *  @copyright Ranides Atterwim
+ *  @license WTFPL
+ *  @url http://ranides.net/projects/assira
+ */
+
+package net.ranides.assira.text;
+
+import com.google.caliper.SimpleBenchmark;
+import net.ranides.assira.BenchmarkRunner;
+import net.ranides.assira.math.Randomizer;
+import org.apache.commons.lang3.text.StrBuilder;
+
+/**
+ *
+ * @author ranides
+ */
+@SuppressWarnings("PMD.AvoidDuplicateLiterals")
+@edu.umd.cs.findbugs.annotations.SuppressWarnings("DLS_DEAD_LOCAL_STORE")
+public class StringCompilerBenchmark extends SimpleBenchmark {
+    
+    private final String[] unquoteData;
+    private final String[] quoteData;
+    
+    public StringCompilerBenchmark() {
+        
+        unquoteData = new String[1000];
+        for(int i=0; i<unquoteData.length; i++) {
+            if(Randomizer.number(10)>5) {
+                unquoteData[i] = StringCompiler.quote(Randomizer.text(128, "qwertyuiopasdfghjklzxcvbnm\"\"\""));
+            } else {
+                unquoteData[i] = Randomizer.text(128, "qwertyuiopasdfghjklzxcvbnm");
+            }
+        }
+        
+        quoteData = new String[1000];
+        for(int i=0; i<quoteData.length; i++) {
+            if(Randomizer.number(10)>5) {
+                quoteData[i] = Randomizer.text(128, "qwertyuiopasdfghjklzxcvbnm\"\"\"");
+            } else {
+                quoteData[i] = Randomizer.text(128, "qwertyuiopasdfghjklzxcvbnm");
+            }
+        }
+    }
+    
+    public static String apacheQuote(String value) {
+        if (null == value) {
+            return "\"\"";
+        }
+        return "\"" + new StrBuilder(value).replaceAll("\\", "\\\\").replaceAll("\"", "\\\"") + "\"";
+    }
+    
+    public static String apacheUnquote(String value) {
+        final String test = StringCompiler.unquoteCheck(value);
+        if(null != test) { return test; }
+
+        return new StrBuilder(value.substring(1, value.length()-1) )
+            .replaceAll("\\\\", "\\")
+            .replaceAll("\\\"", "\"")
+            .toString();
+    }
+
+    public void timeUnquoteAssira(int reps) {
+        for(int r=0; r<reps; r++) {
+            for(int i=0, n=unquoteData.length; i<n; i++) {
+                StringCompiler.unquote(unquoteData[i]);
+            }
+        }
+    }
+    
+    public void timeUnquoteApache(int reps) {
+        for(int r=0; r<reps; r++) {
+            for(int i=0, n=unquoteData.length; i<n; i++) {
+                apacheUnquote(unquoteData[i]);
+            }
+        }
+    }
+    
+    public void timeQuoteAssira(int reps) {
+        for(int r=0; r<reps; r++) {
+            for(int i=0, n=quoteData.length; i<n; i++) {
+                StringCompiler.quote(quoteData[i]);
+            }
+        }
+    }
+    
+    public void timeQuoteApache(int reps) {
+        for(int r=0; r<reps; r++) {
+            for(int i=0, n=quoteData.length; i<n; i++) {
+                apacheQuote(quoteData[i]);
+            }
+        }
+    }
+    
+    public static void main(String[] args) throws Exception {
+        BenchmarkRunner.run32();
+    }
+}

+ 1 - 63
src/test/java/net/ranides/assira/text/StringCompilerTest.java

@@ -7,9 +7,7 @@
 
 package net.ranides.assira.text;
 
-import com.google.caliper.Runner;
 import com.google.caliper.SimpleBenchmark;
-import net.ranides.assira.math.Randomizer;
 import org.apache.commons.lang3.text.StrBuilder;
 import org.junit.Test;
 import static org.junit.Assert.*;
@@ -20,31 +18,7 @@ import static org.junit.Assert.*;
  */
 @SuppressWarnings("PMD.AvoidDuplicateLiterals")
 @edu.umd.cs.findbugs.annotations.SuppressWarnings("DLS_DEAD_LOCAL_STORE")
-public class StringCompilerTest extends SimpleBenchmark {
-    
-    private final String[] unquoteData;
-    private final String[] quoteData;
-    
-    public StringCompilerTest() {
-        
-        unquoteData = new String[1000];
-        for(int i=0; i<unquoteData.length; i++) {
-            if(Randomizer.number(10)>5) {
-                unquoteData[i] = StringCompiler.quote(Randomizer.text(128, "qwertyuiopasdfghjklzxcvbnm\"\"\""));
-            } else {
-                unquoteData[i] = Randomizer.text(128, "qwertyuiopasdfghjklzxcvbnm");
-            }
-        }
-        
-        quoteData = new String[1000];
-        for(int i=0; i<quoteData.length; i++) {
-            if(Randomizer.number(10)>5) {
-                quoteData[i] = Randomizer.text(128, "qwertyuiopasdfghjklzxcvbnm\"\"\"");
-            } else {
-                quoteData[i] = Randomizer.text(128, "qwertyuiopasdfghjklzxcvbnm");
-            }
-        }
-    }
+public class StringCompilerTest {
     
     public static String apacheQuote(String value) {
         if (null == value) {
@@ -187,41 +161,5 @@ public class StringCompilerTest extends SimpleBenchmark {
         String[] c = StringCompiler.splitQuoted("  \"a b\" c d e    \"f \\\" g\"    h      ");
         assertArrayEquals(new String[]{"a b", "c", "d", "e", "f \" g", "h"}, c);
     }
-    
-    public void timeUnquoteAssira(int reps) {
-        for(int r=0; r<reps; r++) {
-            for(int i=0, n=unquoteData.length; i<n; i++) {
-                StringCompiler.unquote(unquoteData[i]);
-            }
-        }
-    }
-    
-    public void timeUnquoteApache(int reps) {
-        for(int r=0; r<reps; r++) {
-            for(int i=0, n=unquoteData.length; i<n; i++) {
-                apacheUnquote(unquoteData[i]);
-            }
-        }
-    }
-    
-    public void timeQuoteAssira(int reps) {
-        for(int r=0; r<reps; r++) {
-            for(int i=0, n=quoteData.length; i<n; i++) {
-                StringCompiler.quote(quoteData[i]);
-            }
-        }
-    }
-    
-    public void timeQuoteApache(int reps) {
-        for(int r=0; r<reps; r++) {
-            for(int i=0, n=quoteData.length; i<n; i++) {
-                apacheQuote(quoteData[i]);
-            }
-        }
-    }
 
-    
-    public static void main(String[] args) throws Exception {
-        Runner.main(StringCompilerTest.class, args);
-    }
 }

+ 63 - 0
src/test/java/net/ranides/assira/text/StringUtilsBenchmark.java

@@ -0,0 +1,63 @@
+/*
+ * @author Ranides Atterwim <ranides@gmail.com>
+ * @copyright Ranides Atterwim
+ * @license WTFPL
+ * @url http://ranides.net/projects/assira
+ */
+
+package net.ranides.assira.text;
+
+import com.google.caliper.SimpleBenchmark;
+import net.ranides.assira.BenchmarkRunner;
+import net.ranides.assira.math.Randomizer;
+
+/**
+ *
+ * @author ranides
+ */
+public class StringUtilsBenchmark extends SimpleBenchmark {
+
+    private final String[] randomTexts;
+
+    public StringUtilsBenchmark() {
+        randomTexts = new String[1000];
+        for(int i=0; i<randomTexts.length; i++) {
+            randomTexts[i] = Randomizer.text(128, "qwertyuiopasdfghjklzxcvbnm");
+        }
+    }
+    
+    public int timeReplaceAssira(int reps) {
+        int c = 0;
+        for(int r=0; r<reps; r++) {
+            for (String text : randomTexts) {
+                c += StringUtils.replace(text, 'a', "abc").charAt(0);
+            }
+        }
+        return c;
+    }
+
+    public int timeReplaceJava(int reps) {
+        int c = 0;
+        for(int r=0; r<reps; r++) {
+            for (String text : randomTexts) {
+                c += text.replace(String.valueOf('a'), "abc").charAt(0);
+            }
+        }
+        return c;
+    }
+
+    public int timeReplaceApache(int reps) {
+        int c = 0;
+        for(int r=0; r<reps; r++) {
+            for (String text : randomTexts) {
+                c += org.apache.commons.lang3.StringUtils.replace(text, String.valueOf('a'), "abc").charAt(0);
+            }
+        }
+        return c;
+    }
+
+    public static void main(String[] args) throws Exception {
+        BenchmarkRunner.run32();
+    }
+
+}

+ 1 - 46
src/test/java/net/ranides/assira/text/StringUtilsTest.java

@@ -7,7 +7,6 @@
 
 package net.ranides.assira.text;
 
-import com.google.caliper.Runner;
 import com.google.caliper.SimpleBenchmark;
 import java.util.Arrays;
 import java.util.Iterator;
@@ -15,7 +14,6 @@ import java.util.List;
 import java.util.regex.Matcher;
 import java.util.regex.Pattern;
 import net.ranides.assira.generic.Function;
-import net.ranides.assira.math.Randomizer;
 import org.junit.Test;
 import static org.junit.Assert.*;
 
@@ -27,16 +25,7 @@ import static org.junit.Assert.*;
     "PMD.AvoidDuplicateLiterals",
     "PMD.TooManyDifferentMethods"
 })
-public class StringUtilsTest extends SimpleBenchmark {
-
-    private final String[] randomTexts;
-
-    public StringUtilsTest() {
-        randomTexts = new String[1000];
-        for(int i=0; i<randomTexts.length; i++) {
-            randomTexts[i] = Randomizer.text(128, "qwertyuiopasdfghjklzxcvbnm");
-        }
-    }
+public class StringUtilsTest {
 
     @Test
     public void testRemoveChars() {
@@ -414,39 +403,5 @@ public class StringUtilsTest extends SimpleBenchmark {
         assertEquals("t", StringUtils.removePrefix("Et", "E"));
         assertEquals("ter", StringUtils.removePrefix("Eter", "E"));
     }
-    
-    public int timeReplaceAssira(int reps) {
-        int c = 0;
-        for(int r=0; r<reps; r++) {
-            for (String text : randomTexts) {
-                c += StringUtils.replace(text, 'a', "abc").charAt(0);
-            }
-        }
-        return c;
-    }
-
-    public int timeReplaceJava(int reps) {
-        int c = 0;
-        for(int r=0; r<reps; r++) {
-            for (String text : randomTexts) {
-                c += text.replace(String.valueOf('a'), "abc").charAt(0);
-            }
-        }
-        return c;
-    }
-
-    public int timeReplaceApache(int reps) {
-        int c = 0;
-        for(int r=0; r<reps; r++) {
-            for (String text : randomTexts) {
-                c += org.apache.commons.lang3.StringUtils.replace(text, String.valueOf('a'), "abc").charAt(0);
-            }
-        }
-        return c;
-    }
-
-    public static void main(String[] args) throws Exception {
-        Runner.main(StringUtilsTest.class, args);
-    }
 
 }

+ 62 - 33
src/test/java/net/ranides/assira/text/StringsBenchmark.java

@@ -6,8 +6,10 @@
  */
 package net.ranides.assira.text;
 
-import com.google.caliper.Runner;
+import com.google.caliper.Param;
 import com.google.caliper.SimpleBenchmark;
+import net.ranides.assira.BenchmarkRunner;
+import net.ranides.assira.collection.map.SwitchMapBenchmark;
 import net.ranides.assira.math.Randomizer;
 
 /**
@@ -40,23 +42,66 @@ import net.ranides.assira.math.Randomizer;
  */
 public class StringsBenchmark extends SimpleBenchmark {
     
-    private char[][] dataS;
-    private char[][] dataM;
-    private char[][] dataL;
+    public static final String PARAMS = Strings.raw(/*
+        FOR: CharCopy
+        FOR: CharWrap
+            
+        HEADER: param, count, min, max
+            
+        0,  100,     4,     4
+        1,  100,     8,     8
+        2,  100,     8,    16
+        3,  100,    16,    32
+        4,  100,    32,    64
+        5,  100,    64,   128
+        6,  100,   128,   256
+        7,  100,   512,  1024
+        8,  100,  1024,  1024
+        9,  100,  1024,  2048
+    */);
+    
+    @Param
+    private int param;
+    
+    private char[][] data;
+    
+    private static final GParams[] GPARAMS = {
+        new GParams( 100,     4,     4 ),
+        new GParams( 100,     8,     8 ),
+        new GParams( 100,     8,    16 ),
+        new GParams( 100,    16,    32 ),
+        new GParams( 100,    32,    64 ),
+        new GParams( 100,    64,   128 ),
+        new GParams( 100,   128,   256 ),
+        new GParams( 100,   512,  1024 ),
+        new GParams( 100,  1024,  1024 ),
+        new GParams( 100,  1024,  2048 )
+    };
     
     @Override
     public void setUp() {
-        dataS = makeCharArray(2048, 4, 12);
-        dataM = makeCharArray(1024, 16, 64); 
-        dataL = makeCharArray(256, 128, 1024); 
+        data = GPARAMS[param].array();
     }
     
-    private static char[][] makeCharArray(int count, int min, int max) {
-        char[][] ret = new char[count][];
-        for(int i=0; i<count; i++) {
-            ret[i] = Randomizer.text(Randomizer.number(min,max)).toCharArray();
+    private static final class GParams {
+        private final int count;
+        private final int min;
+        private final int max;
+
+        public GParams(int count, int min, int max) {
+            this.count = count;
+            this.min = min;
+            this.max = max;
         }
-        return ret;
+        
+        public char[][] array() {
+            char[][] ret = new char[count][];
+            for(int i=0; i<count; i++) {
+                ret[i] = Randomizer.text(Randomizer.number(min,max)).toCharArray();
+            }
+            return ret;
+        }
+
     }
     
     private static int itimeCharCopy(int reps, char[][] input) {
@@ -79,32 +124,16 @@ public class StringsBenchmark extends SimpleBenchmark {
         return c;
     }
     
-    public int timeCharCopyS(int reps) {
-        return itimeCharCopy(reps, dataS);
-    }
-    
-    public int timeCharWrapS(int reps) {
-        return itimeCharWrap(reps, dataS);
-    }
-    
-    public int timeCharCopyM(int reps) {
-        return itimeCharCopy(reps, dataM);
-    }
-    
-    public int timeCharWrapM(int reps) {
-        return itimeCharWrap(reps, dataM);
-    }
-    
-    public int timeCharCopyL(int reps) {
-        return itimeCharCopy(reps, dataL);
+    public int timeCharCopy(int reps) {
+        return itimeCharCopy(reps, data);
     }
     
-    public int timeCharWrapL(int reps) {
-        return itimeCharWrap(reps, dataL);
+    public int timeCharWrap(int reps) {
+        return itimeCharWrap(reps, data);
     }
 
     public static void main(String[] args) throws Exception {
-        Runner.main(StringsBenchmark.class, args);
+        BenchmarkRunner.run32();
     }
     
 }