Last active
January 31, 2017 16:51
-
-
Save hageldave/f0caa0eccef0e4e2f50080af39792b2d to your computer and use it in GitHub Desktop.
Code generator for generating extra methods for native types based on generic template
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
package misc; | |
import java.io.File; | |
import java.io.FileNotFoundException; | |
import java.io.PrintStream; | |
import java.util.ArrayList; | |
import java.util.Iterator; | |
import java.util.Scanner; | |
import java.util.regex.Matcher; | |
import java.util.regex.Pattern; | |
public class CodeGen { | |
static PrintStream debug = System.err; | |
static PrintStream out = System.out; | |
static String[] generics = new String[]{"Integer", "Long", "Float", "Double", "Short", "Character", "Byte"}; | |
static String[] natives = new String[]{"int", "long", "float", "double", "short", "char", "byte"}; | |
static String[] natNames = new String[]{"Int", "Long", "Float", "Double", "Short", "Char", "Byte"}; | |
public static void main(String[] args) { | |
generateNativeVersionsForGenerics(); | |
} | |
static void generateNativeVersionsForGenerics() { | |
File f_proto = new File("src/test/java/misc/ProtoSlice.java"); | |
String protoName = "ProtoSlice"; | |
String className = "Slice"; | |
TextFileIterable src = new TextFileIterable(f_proto); | |
// String[] src = { | |
// "////MKNATIVE>>>>\n", | |
// "/*RPLC:Generic*/GenericAccessor/**//*RM*/<T>/**/ clon = new /*RPLC:Generic*/GenericAccessor/**//*RM*/<>/**/(array);\n", | |
// "////<<<<" | |
// }; | |
final int FINDINGPROTO=10; | |
final int SCANNING=0; | |
int status = SCANNING; | |
ArrayList<String> proto = new ArrayList<>(); | |
for(String line: src){ | |
line = line.replaceAll(protoName, className); | |
switch (status) { | |
case FINDINGPROTO: | |
if(line.contains("////<<<<")){ | |
status = SCANNING; | |
processPrototype(proto); | |
proto.clear(); | |
} else { | |
proto.add(line); | |
} | |
break; | |
default: | |
if(line.contains("////MKNATIVE>>>>")){ | |
status = FINDINGPROTO; | |
} else { | |
out.print(line); | |
} | |
break; | |
} | |
} | |
} | |
static void processPrototype(ArrayList<String> proto) { | |
processPrototypeKeepGeneric(proto); | |
out.println(); | |
for(int i = 0; i < 7; i++){ | |
processPrototype(proto, generics[i], natives[i], natNames[i]); | |
out.println(); | |
} | |
} | |
static void processPrototypeKeepGeneric(ArrayList<String> proto){ | |
for(String line: proto){ | |
for(String token: line.split(rg("/**/"))){ | |
token = token.replaceAll(rg("/*RM*/"), ""); | |
token = token.replaceAll(rg("/*G*/"), ""); | |
token = token.replaceAll(rg("/*N*/"), ""); | |
token = token.replaceAll(rg("/*RPLC:.+*/"), ""); | |
out.print(token); | |
} | |
} | |
} | |
static void processPrototype(ArrayList<String> proto, String gen, String nat, String name) { | |
for(String line: proto){ | |
String[] items = line.split(rg("/**/")); | |
for(String item: items){ | |
item = item.replaceAll(rg("/*RM*/.+"), ""); | |
item = item.replaceAll(rg("/*G*/.+"), gen); | |
item = item.replaceAll(rg("/*N*/.+"), nat); | |
item = doReplacement(item, name); | |
out.print(item); | |
} | |
} | |
} | |
static String rg(String regex){ | |
return regex.replaceAll("\\*", "\\\\\\*"); | |
} | |
static String doReplacement(String s, String r){ | |
if(!s.contains("/*RPLC:")) | |
return s; | |
String toReplace = extractRPLC(s); | |
s = s.replaceAll(rg("/*RPLC:.+*/"), ""); | |
s = s.replaceAll(toReplace, r); | |
return s; | |
} | |
static final Pattern rplcGroup = Pattern.compile(rg("/*RPLC:(.+?)*/")); | |
static String extractRPLC(String s){ | |
Matcher m = rplcGroup.matcher(s); | |
m.find(); | |
return m.group(1); | |
} | |
static class TextFileIterable implements Iterable<String> { | |
File f; | |
public TextFileIterable(File file) { | |
f=file; | |
} | |
@Override | |
public Iterator<String> iterator() { | |
try { | |
final Scanner sc = new Scanner(f); | |
return new Iterator<String>() { | |
@Override | |
public boolean hasNext() { | |
boolean hasNext = sc.hasNextLine(); | |
if(!hasNext) | |
sc.close(); | |
return hasNext; | |
} | |
@Override | |
public String next() { | |
return sc.nextLine()+"\n"; | |
} | |
}; | |
} catch (FileNotFoundException e) { | |
throw new RuntimeException(e); | |
} | |
} | |
} | |
} | |
////// | |
///// | |
///// | |
///// | |
//// | |
package misc; | |
import java.util.Arrays; | |
import java.util.Iterator; | |
import java.util.Spliterator; | |
import java.util.function.Consumer; | |
import java.util.stream.Stream; | |
import java.util.stream.StreamSupport; | |
public class ProtoSlice<T> implements Iterable<ProtoSlice.ArrayAccessor<T>>{ | |
final ArrayAccessor<T> aa; | |
final int size; | |
final int beginIdx; | |
private ProtoSlice(ArrayAccessor<T> accessor, int beginIdx, int size) { | |
this.aa = accessor; | |
this.size = size; | |
this.beginIdx = beginIdx; | |
} | |
@Override | |
public Iterator<ArrayAccessor<T>> iterator() { | |
return new AccessorIterator<T>(beginIdx, size, aa); | |
} | |
@Override | |
public Spliterator<ArrayAccessor<T>> spliterator() { | |
return new AccessorSpliterator<T>(beginIdx, size-1, estimateReasonableSplitSize(size), aa); | |
} | |
public Stream<ArrayAccessor<T>> stream(boolean parallel) { | |
return StreamSupport.stream(spliterator(), parallel); | |
} | |
public Stream<ArrayAccessor<T>> stream() { | |
return stream(false); | |
} | |
public Stream<ArrayAccessor<T>> parallelStream() { | |
return stream(true); | |
} | |
@Override | |
public void forEach(Consumer<? super ArrayAccessor<T>> action) { | |
Iterable.super.forEach(action); | |
} | |
public void forEachParallel(Consumer<? super ArrayAccessor<T>> action) { | |
parallelStream().forEach(action); | |
} | |
public ProtoSlice<T> copy() { | |
return new ProtoSlice<T>(aa.copy(),beginIdx,size); | |
} | |
public T getAt(int i){ | |
return aa.get(i); | |
} | |
public void setAt(int i, T e){ | |
aa.set(i, e); | |
} | |
public int length() { | |
return size; | |
} | |
public int size() { | |
return size; | |
} | |
public int getBeginIdx() { | |
return beginIdx; | |
} | |
/////////////////////////////// | |
// Constructors | |
/////////////////////////////// | |
////MKNATIVE>>>> | |
static /*RM*/<T>/**/ ProtoSlice</*G*/T/**/> get(/*N*/T/**/[] array, int beginIdx, int length){ | |
return new ProtoSlice</*G*/T/**/>(new /*RPLC:Generic*/GenericAccessor/**//*RM*/<T>/**/(array), beginIdx, length); | |
} | |
static /*RM*/<T>/**/ ProtoSlice</*G*/T/**/> get(/*N*/T/**/[] array){ | |
return get(array, 0, array.length); | |
} | |
////<<<< | |
/////////////////////////////// | |
// Static Streaming | |
/////////////////////////////// | |
static int estimateReasonableSplitSize(int length) { | |
final int tasksPerProcessor = 16; | |
final int concurrentLimit = Runtime.getRuntime().availableProcessors()*tasksPerProcessor; | |
final int minReasonable = 512; | |
return Math.max(minReasonable, Integer.highestOneBit(length/concurrentLimit)); | |
} | |
////MKNATIVE>>>> | |
public static /*RM*/<T>/**/ Stream<ArrayAccessor</*G*/T/**/>> stream(/*N*/T/**/[] array, boolean parallel, int beginIndex, int length, int minSplitSize){ | |
return StreamSupport.stream(new AccessorSpliterator</*G*/T/**/>(beginIndex, beginIndex+length-1, minSplitSize, new /*RPLC:Generic*/GenericAccessor/**//*RM*/<T>/**/(array)), parallel); | |
} | |
public static /*RM*/<T>/**/ Stream<ArrayAccessor</*G*/T/**/>> stream(/*N*/T/**/[] array, boolean parallel, int beginIndex, int length){ | |
return stream(array, parallel, beginIndex, length, estimateReasonableSplitSize(length)); | |
} | |
public static /*RM*/<T>/**/ Stream<ArrayAccessor</*G*/T/**/>> stream(/*N*/T/**/[] array, boolean parallel){ | |
return stream(array, parallel, 0, array.length); | |
} | |
////<<<< | |
/////////////////////////////// | |
// Accessors | |
/////////////////////////////// | |
public static abstract class ArrayAccessor<T> implements Cloneable { | |
protected int index; | |
public abstract T get(); | |
public abstract void set(T e); | |
protected abstract T get(int i); | |
protected abstract void set(int i, T e); | |
public final int getIndex(){ return index; } | |
public final void setIndex(int i){index = i; } | |
/** only copies reference */ | |
protected abstract ArrayAccessor<T> clone(); | |
/** allocates new array */ | |
protected abstract ArrayAccessor<T> copy(); | |
@Override | |
public String toString() { | |
return String.format("[%s] at index %d", getClass().getSimpleName(), index); | |
} | |
} | |
////MKNATIVE>>>> | |
static class /*RPLC:Generic*/GenericAccessor/**//*RM*/<T>/**/ extends ArrayAccessor</*G*/T/**/> { | |
/*N*/T/**/[] array; | |
public /*RPLC:Generic*/GenericAccessor/**/(/*N*/T/**/[] array) { | |
this.array=array; | |
} | |
@Override | |
public /*G*/T/**/ get() {return array[index];} | |
@Override | |
public void set(/*G*/T/**/ e) {array[index] = e;} | |
@Override | |
protected /*G*/T/**/ get(int i) {return array[i];} | |
@Override | |
protected void set(int i, /*G*/T/**/ e) {array[i] = e;} | |
@Override | |
protected /*RPLC:Generic*/GenericAccessor/**//*RM*/<T>/**/ clone() { | |
/*RPLC:Generic*/GenericAccessor/**//*RM*/<T>/**/ clon = new /*RPLC:Generic*/GenericAccessor/**//*RM*/<>/**/(array); | |
clon.setIndex(index); | |
return clon; | |
} | |
@Override | |
protected /*RPLC:Generic*/GenericAccessor/**//*RM*/<T>/**/ copy() { | |
/*RPLC:Generic*/GenericAccessor/**//*RM*/<T>/**/ cpy = new /*RPLC:Generic*/GenericAccessor/**//*RM*/<T>/**/(Arrays.copyOf(array, array.length)); | |
cpy.setIndex(index); | |
return cpy; | |
} | |
} | |
////<<<< | |
/////////////////////////////// | |
// Iterator & Spliterator | |
/////////////////////////////// | |
static class AccessorIterator<T> implements Iterator<ArrayAccessor<T>> { | |
int i; | |
final int endIndexExcl; | |
final ArrayAccessor<T> acc; | |
public AccessorIterator(int startIndex, int endIndexExcl, ArrayAccessor<T> acc) { | |
this.acc = acc.clone(); | |
this.i = startIndex-1; | |
this.endIndexExcl = endIndexExcl; | |
} | |
@Override | |
public boolean hasNext() { | |
return i+1 < endIndexExcl; | |
} | |
@Override | |
public ArrayAccessor<T> next() { | |
i++; | |
acc.setIndex(i); | |
return acc; | |
} | |
@Override | |
public void forEachRemaining(Consumer<? super ArrayAccessor<T>> action) { | |
i++; | |
for(; i < endIndexExcl; i++){ | |
acc.setIndex(i); | |
} | |
} | |
} | |
static class AccessorSpliterator<T> implements Spliterator<ArrayAccessor<T>> { | |
final ArrayAccessor<T> acc; | |
int endIndex; | |
final int minimumSplitSize; | |
/** | |
* Constructs a new ImgSpliterator for the specified index range | |
* @param startIndex first index of the range (inclusive) | |
* @param endIndex last index of the range (inclusive) | |
* @param minSplitSize minimum split size for this spliterator (minimum number of elements in a split) | |
*/ | |
AccessorSpliterator(int startIndex, int endIndex, int minSplitSize, ArrayAccessor<T> acc) { | |
this.acc = acc.clone(); | |
this.acc.setIndex(startIndex); | |
this.endIndex = endIndex; | |
this.minimumSplitSize = minSplitSize; | |
} | |
private void setEndIndex(int endIndex) { | |
this.endIndex = endIndex; | |
} | |
@Override | |
public boolean tryAdvance(final Consumer<? super ArrayAccessor<T>> action) { | |
if(acc.getIndex() <= endIndex){ | |
int index = acc.getIndex(); | |
action.accept(acc); | |
acc.setIndex(index+1); | |
return true; | |
} else { | |
return false; | |
} | |
} | |
@Override | |
public void forEachRemaining(final Consumer<? super ArrayAccessor<T>> action) { | |
int idx = acc.getIndex(); | |
for(;idx <= endIndex; acc.setIndex(++idx)){ | |
action.accept(acc); | |
} | |
} | |
@Override | |
public Spliterator<ArrayAccessor<T>> trySplit() { | |
int currentIdx = Math.min(acc.getIndex(), endIndex); | |
int midIdx = currentIdx + (endIndex-currentIdx)/2; | |
if(midIdx > currentIdx+minimumSplitSize){ | |
AccessorSpliterator<T> split = new AccessorSpliterator<T>(midIdx, endIndex, minimumSplitSize, acc); | |
setEndIndex(midIdx-1); | |
return split; | |
} else { | |
return null; | |
} | |
} | |
@Override | |
public long estimateSize() { | |
int currentIndex = acc.getIndex(); | |
int lastIndexPlusOne = endIndex+1; | |
return lastIndexPlusOne-currentIndex; | |
} | |
@Override | |
public int characteristics() { | |
return NONNULL | SIZED | CONCURRENT | SUBSIZED | IMMUTABLE; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment