Skip to content

Instantly share code, notes, and snippets.

@hageldave
Last active January 31, 2017 16:51
Show Gist options
  • Save hageldave/f0caa0eccef0e4e2f50080af39792b2d to your computer and use it in GitHub Desktop.
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
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