import virtdata

This commit is contained in:
Jonathan Shook 2020-02-20 15:37:40 -06:00
parent 0b733bfa1d
commit 62d53ecec6
1570 changed files with 370965 additions and 0 deletions

View File

@ -0,0 +1,16 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>virtdata-annotations</artifactId>
<packaging>jar</packaging>
<parent>
<artifactId>virtdata-defaults</artifactId>
<groupId>io.nosqlbench</groupId>
<version>2.12.16-SNAPSHOT</version>
<relativePath>../virtdata-defaults</relativePath>
</parent>
<name>virtdata-annotations</name>
</project>

View File

@ -0,0 +1,16 @@
package io.virtdata.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Direct the user to additional resources
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Categories {
Category[] value();
}

View File

@ -0,0 +1,12 @@
package io.virtdata.annotations;
public enum Category {
datetime,
state,
distributions,
diagnostics,
conversion,
collections,
premade,
nulls, functional, general
}

View File

@ -0,0 +1,28 @@
package io.virtdata.annotations;/*
* Copyright 2016 jshook
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This marks functions as deprecated, with a reason.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface DeprecatedFunction {
String value();
}

View File

@ -0,0 +1,12 @@
package io.virtdata.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Description {
String value();
}

View File

@ -0,0 +1,18 @@
package io.virtdata.annotations;
import java.lang.annotation.Repeatable;
/**
* The example annotation allows for a function developer to attach illustrative
* examples for any given constructor. You can have multiple
* <pre>@Example</pre> annotation per constructor.
*
*
* A few key formats are allowed
*/
@Repeatable(value = Examples.class)
public @interface Example {
String[] value();
}

View File

@ -0,0 +1,109 @@
package io.virtdata.annotations;
import java.util.Arrays;
import java.util.List;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* <H2>Formatting conventions</H2>
* The following example formats are supported:
*
* <ul>
* <li><pre>CtorName(param,...)</pre> - as the constructor would be called.</li>
* <li><pre>[1,2,3]</pre> - a sequence of integer values</li>
* <li><pre>[longs1]</pre> - a name of a pre-defined set of sample inputs</li>
* </ul>
*/
public class ExampleData {
public static Pattern CTOR_PATTERN = Pattern.compile("(?<funcname>[^)]+)\\((?<args>.+)\\)");
public static Pattern VALS_PATTERN = Pattern.compile("\\[(?<values>-?\\d+([,-. ]+-?\\d+)*)]");
private Pattern COMMA_VALS = Pattern.compile("\\[(?<vals>-?\\d+(,-?\\d+)*)]");
private Pattern RANGE_VALS = Pattern.compile("\\[(?<from>-?\\d+)\\.\\.(?<to>-?\\d+)( +(?<step>-?\\d+))?]");
public String[] parts;
public ExampleData(String[] parts) {
this.parts = parts;
}
public static void validateExamples(List<List<String>> examples) {
for (List<String> example : examples) {
for (String examplePart : example) {
if (CTOR_PATTERN.matcher(examplePart).matches()) {
continue;
}
if (VALS_PATTERN.matcher(examplePart).matches()) {
continue;
}
if (!examplePart.startsWith("[")) {
return;
}
throw new RuntimeException("Unable to match a valid pattern for example fragment '"+examplePart +"')" +
". See javadoc for the Example annotation for details.");
}
}
}
public long[] getLongInputs() {
long[] vals = new long[0];
for (String part : parts) {
if (VALS_PATTERN.matcher(part).matches()) {
String[] specs = part.split(";");
long[][] genvals = new long[specs.length][];
int len =0;
for (int i = 0; i < genvals.length; i++) {
String spec = specs[i];
genvals[i] = parseRange(spec);
len+=genvals[i].length;
}
vals = new long[len];
int atlen=0;
for (int i = 0; i < genvals.length; i++) {
System.arraycopy(genvals[i],0,vals,atlen,genvals[i].length);
atlen+=genvals[i].length;
}
}
}
return vals;
}
private long[] parseRange(String spec) {
Matcher comma_matcher = COMMA_VALS.matcher(spec);
if (comma_matcher.matches()) {
String vals = comma_matcher.group("vals");
long[] longvals = Arrays.stream(vals.split(",")).mapToLong(Long::valueOf).toArray();
return longvals;
}
Matcher range_matcher = RANGE_VALS.matcher(spec);
if (range_matcher.matches()) {
long from=Long.parseLong(range_matcher.group("from"));
long to=Long.parseLong(range_matcher.group("to"));
String step_size = range_matcher.group("step");
long step = 1L;
if (step_size!=null) {
step = Long.parseLong(step_size);
}
if (from<to && step<=0) {
throw new RuntimeException("for increasing from-to of (" +from+"-"+to+":, stepsize must be positive.");
}
if (from>to && step>=0) {
throw new RuntimeException("for decreasing from-to of (" +from+"-"+to+":, stepsize must be negative.");
}
long sizeL = (Math.abs(from-to) / Math.abs(step))+1;
if (sizeL>Integer.MAX_VALUE) {
throw new RuntimeException("example size " + sizeL + " is too big.");
}
long[] vals = new long[(int)sizeL];
long sign = (step>0 ? 1L : -1L);
for (int i = 0; i < vals.length; i++) {
vals[i]=from+(step*i);
}
return vals;
}
throw new RuntimeException("Unable to parse spec pattern: '"+spec+"'");
}
}

View File

@ -0,0 +1,12 @@
package io.virtdata.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.CONSTRUCTOR)
public @interface Examples {
Example[] value();
}

View File

@ -0,0 +1,30 @@
package io.virtdata.annotations;/*
* Copyright 2016 jshook
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation is used to mark the input type for a functional interface which
* uses generics, like LongFunction, IntFunction, or Function.
* It is only used when then input type of a function can't be found via reflection.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Input {
Range value();
}

View File

@ -0,0 +1,30 @@
package io.virtdata.annotations;/*
* Copyright 2016 jshook
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* This annotation is used to mark the output type for a functional interface which
* uses generics, like LongFunction, IntFunction, or Function.
* It is only used when then input type of a function can't be found via reflection.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Output {
Range value();
}

View File

@ -0,0 +1,29 @@
package io.virtdata.annotations;/*
* Copyright 2016 jshook
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* A PerThreadMapper will be instantiated once for each thread,
* for each scope in which it is used. Mapper developers should
* endeavor to implement {@link ThreadSafeMapper}s instead.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface PerThreadMapper {
}

View File

@ -0,0 +1,21 @@
package io.virtdata.annotations;
public enum Range {
NonNegativeLongs("All positive long values and zero: 0L.." + Long.MAX_VALUE),
NonNegativeInts("All positive integer values and zero: 0.." + Integer.MAX_VALUE),
Longs("All long values: " + Long.MIN_VALUE + "L.." + Long.MAX_VALUE+"L"),
Integers("All int values: " + Integer.MIN_VALUE + ".." + Integer.MAX_VALUE),
DoubleUnitInterval("The unit interval in double precision: 0.0D..1.0D"),
FloatUnitInterval("The unit interval in single precision: 0.0F..1.0F"),
Doubles("All double values: " + Double.MIN_VALUE + "D.." + Double.MAX_VALUE+"D");
private final String description;
public String getDescription() {
return description;
}
Range(String description) {
this.description = description;
}
}

View File

@ -0,0 +1,29 @@
/*
* Copyright 2016 jshook
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.virtdata.annotations;
import java.lang.annotation.*;
/**
* Direct the user to additional resources
*/
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(SeeList.class)
@Target(ElementType.TYPE)
public @interface See {
String name();
String url();
}

View File

@ -0,0 +1,15 @@
package io.virtdata.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* Direct the user to additional resources
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface SeeList {
See[] value();
}

View File

@ -0,0 +1,33 @@
/*
* Copyright 2016 jshook
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.virtdata.annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* A Service annotation will cause a class to be added to META-INF/services/
* under the specified class name.
*
* At least, this simple thing won't require the use of g u a v a. Yay!
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Service {
Class<?> value();
}

View File

@ -0,0 +1,28 @@
package io.virtdata.annotations;/*
* Copyright 2016 jshook
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* A ThreadSafeMapper will only be instantiated once in a scope, to be
* shared among all threads in that scope.
*/
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ThreadSafeMapper {
}

View File

@ -0,0 +1,27 @@
package io.virtdata.processors;
import java.util.List;
import java.util.Map;
public interface DocCtorData {
/**
* @return the {@link Class#getSimpleName()} of the documented ctor.
*/
String getClassName();
/**
* @return javadoc for the documented ctor, or null if it isn't provided
*/
String getCtorJavaDoc();
/**
* @return an ordered map of the arguments of the documented constructor in name,type form.
*/
Map<String, String> getArgs();
/**
* @return a list of examples, where each is list of (example syntax, comment..)
*/
List<List<String>> getExamples();
}

View File

@ -0,0 +1,92 @@
package io.virtdata.processors;
import io.virtdata.annotations.Category;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
public class DocForFunc implements DocFuncData {
private String packageName;
private String className;
private String classJavadoc;
private String inType;
private String outType;
private ArrayList<DocCtorData> ctors = new ArrayList<>();
private Category[] categories = new Category[] { };
public void setPackageName(String packageName) {
this.packageName = packageName;
}
@Override
public String getPackageName() {
return this.packageName;
}
@Override
public Category[] getCategories() {
return categories;
}
public void setClassName(String className) {
this.className = className;
}
@Override
public String getClassName() {
return className;
}
public void setClassJavadoc(String classJavadoc) {
this.classJavadoc = classJavadoc;
}
@Override
public String getClassJavadoc() {
return classJavadoc;
}
public void setInType(String inType) {
this.inType = inType;
}
@Override
public String getInType() {
return inType;
}
public void setOutType(String outType) {
this.outType = outType;
}
@Override
public String getOutType() {
return outType;
}
public void addCtor(String ctorDoc, LinkedHashMap<String, String> args, List<List<String>> examples) {
if (this.className==null || this.className.isEmpty()) {
throw new RuntimeException("Unable to document ctor without known class name first.");
}
DocForFuncCtor ctor = new DocForFuncCtor(getClassName(), ctorDoc, args, examples);
ctors.add(ctor);
}
@Override
public ArrayList<DocCtorData> getCtors() {
return this.ctors;
}
@Override
public String toString() {
return "DocForFunction{" +
"packageName='" + packageName + '\'' +
", className='" + className + '\'' +
", classJavadoc='" + classJavadoc + '\'' +
", inType='" + inType + '\'' +
", outType='" + outType + '\'' +
", ctors=" + ctors +
'}';
}
public void addCategories(Category[] categories) {
this.categories = categories;
}
}

View File

@ -0,0 +1,55 @@
package io.virtdata.processors;
import io.virtdata.annotations.ExampleData;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
public class DocForFuncCtor implements DocCtorData {
private Map<String, String> args = new LinkedHashMap<>();
private String ctorDoc;
private String className;
private List<List<String>> examples = new ArrayList<>();
public DocForFuncCtor(String className, String ctorDoc, Map<String, String> args, List<List<String>> examples) {
this.className = className;
this.ctorDoc = ctorDoc;
this.args.putAll(args);
ExampleData.validateExamples(examples);
this.examples.addAll(examples);
}
@Override
public String getClassName() {
return this.className;
}
@Override
public String getCtorJavaDoc() {
return ctorDoc;
}
@Override
public String toString() {
return "Ctor{" +
"class=" + className +
", args=" + args +
", ctorDoc='" + ctorDoc + '\'' +
'}';
}
@Override
public Map<String, String> getArgs() {
return args;
}
@Override
public List<List<String>> getExamples() {
return examples;
}
}

View File

@ -0,0 +1,52 @@
package io.virtdata.processors;
import io.virtdata.annotations.Category;
import java.util.List;
/**
* Provide data about a function, suitable for building a documentation site.
*/
public interface DocFuncData {
/**
* @return the package name for the documented type
*/
String getPackageName();
/**
* @return Return the categories for this function.
*/
Category[] getCategories();
/**
* @return the the {@link Class#getSimpleName()} of the class element
*/
String getClassName();
/**
* Javadoc for the class, or null if there is none.
* @return a String of class javadoc data, or null if none
*/
String getClassJavadoc();
/**
* The input type for the apply method in the documented function class.
* Documented function classes must always implement a Java 8 functional interface.
* @return the input type name
*/
String getInType();
/**
* The output type for the apply method in the documented function class.
* Documented function classes must always implement a Java 8 functional interface.
* @return the output type name
*/
String getOutType();
/**
* The list of constructors for this documented type.
* @return a list of constructor models
*/
List<DocCtorData> getCtors();
}

View File

@ -0,0 +1,82 @@
package io.virtdata.processors;
import io.virtdata.annotations.Category;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
public class ExampleDocData implements DocFuncData {
@Override
public String getPackageName() {
return "packagename";
}
@Override
public Category[] getCategories() {
return new Category[] { Category.general };
}
@Override
public String getClassName() {
return "classname";
}
@Override
public String getClassJavadoc() {
return "javadoc";
}
@Override
public String getInType() {
return "intype";
}
@Override
public String getOutType() {
return "outtype";
}
@Override
public List<DocCtorData> getCtors() {
ArrayList<DocCtorData> ctors = new ArrayList<>();
// for each ctor
LinkedHashMap<String, String> args = new LinkedHashMap<>();
args.put("arg1", "val1");
List<List<String>> examples = new ArrayList<>();
examples.add(new ArrayList<String>() {{ add("example"); add("one"); }});
DocForFuncCtor ctordoc = new DocForFuncCtor("name", "ctordoc", args, examples);
ctors.add(ctordoc);
return ctors;
}
public List<DocForFuncCtor> getCtorsAlternate() {
return new ArrayList<DocForFuncCtor>() {{
add(new DocForFuncCtor("name", "ctordoc",
new LinkedHashMap<String, String>() {{
put("aname", "atype");
}},
new ArrayList<List<String>>() {{
add(new ArrayList<String>() {{
add("example");
add("description");
}});
}}
));
add(new DocForFuncCtor("name", "ctordoc",
new LinkedHashMap<String, String>() {{
put("aname", "atype");
}},
new ArrayList<List<String>>() {{
add(new ArrayList<String>() {{
add("example");
}});
}}
));
}};
}
}

View File

@ -0,0 +1,31 @@
package io.virtdata.processors;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
public class ExampleManifest {
public List<DocFuncData> getDocs() {
ArrayList<DocFuncData> docFuncData = new ArrayList<>();
docFuncData.add(new DocForFunc() {{
setClassName("classname");
setPackageName("packagename");
setClassJavadoc("javadoc");
setInType("intype");
setOutType("outtype");
addCtor("ctordoc",
new LinkedHashMap<String, String>() {{
put("vname", "vtype");
}},
new ArrayList<List<String>>() {{
add(new ArrayList<String>() {{
add("syntax");
add("comment)");
}});
}});
}});
return docFuncData;
}
}

View File

@ -0,0 +1,13 @@
@startuml
scale 350 width
[*] --> long
long --> long
long --> int
long --> double
int --> String
double --> String
long --> String
long --> Date
long --> Bytes
long --> T
@enduml

77
virtdata-api/pom.xml Normal file
View File

@ -0,0 +1,77 @@
<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd">
<modelVersion>4.0.0</modelVersion>
<artifactId>virtdata-api</artifactId>
<packaging>jar</packaging>
<parent>
<artifactId>virtdata-defaults</artifactId>
<groupId>io.nosqlbench</groupId>
<version>2.12.16-SNAPSHOT</version>
<relativePath>../virtdata-defaults</relativePath>
</parent>
<name>virtdata-api</name>
<url>http://virtdata.io/</url>
<dependencies>
<dependency>
<groupId>io.nosqlbench</groupId>
<artifactId>virtdata-processors</artifactId>
<version>2.12.16-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.nosqlbench</groupId>
<artifactId>virtdata-annotations</artifactId>
<version>2.12.16-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>io.nosqlbench</groupId>
<artifactId>virtdata-lang</artifactId>
<version>2.12.16-SNAPSHOT</version>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-api</artifactId>
</dependency>
<dependency>
<groupId>org.apache.logging.log4j</groupId>
<artifactId>log4j-core</artifactId>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-lang3</artifactId>
<version>${commons-lang-version}</version>
</dependency>
<dependency>
<groupId>org.assertj</groupId>
<artifactId>assertj-core-java8</artifactId>
<version>1.0.0m1</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>org.junit.jupiter</groupId>
<artifactId>junit-jupiter-api</artifactId>
<version>5.3.2</version>
<scope>test</scope>
</dependency>
<dependency>
<groupId>junit</groupId>
<artifactId>junit</artifactId>
<version>4.12</version>
</dependency>
<dependency>
<groupId>org.apache.commons</groupId>
<artifactId>commons-csv</artifactId>
<version>1.5</version>
</dependency>
</dependencies>
</project>

View File

@ -0,0 +1,15 @@
package io.virtdata.api;
/***
* A Binder is a type that knows how to return a result object given a long value
* to bind mapped values with.
* @param <R> The resulting object type
*/
public interface Binder<R> {
/**
* Bind values derived from a long to some object, returning an object type R
* @param value a long input value
* @return an R
*/
R bind(long value);
}

View File

@ -0,0 +1,5 @@
package io.virtdata.api;
public interface DataMapper<R> {
R get(long input);
}

View File

@ -0,0 +1,133 @@
package io.virtdata.api;
import io.virtdata.core.DataMapperFunctionMapper;
import io.virtdata.core.ResolvedFunction;
import java.util.List;
import java.util.Optional;
/**
* <p>
* A DataMapperLibrary is an independently loadable library of data mapping functions.
* </p>
*/
public interface DataMapperLibrary {
/**
* <p>Return the name for this data mapper implementation, as it can be used in spec strings, etc.</p>
*
* @return Simple lower-case canonical library name
*/
String getLibraryName();
/**
* <p>Find the implementation for and construct an instance of a data mapper function, as described.</p>
*
* @param spec A specifier that describes the type and or parameterization of a data mapping function instance.
* @param <T> The result type produced by the data mapping function.
* @return An optional data mapping function instance
*/
default <T> Optional<DataMapper<T>> getDataMapper(String spec) {
if (canParseSpec(spec)) {
Optional<ResolvedFunction> resolvedFunction = resolveFunction(spec);
return resolvedFunction
.map(ResolvedFunction::getFunctionObject)
.map(DataMapperFunctionMapper::map);
}
return Optional.empty();
}
default <T> Optional<DataMapper<T>> getOptionalDataMapper(String spec, Class<? extends T> clazz) {
return Optional.ofNullable(getDataMapper(spec, clazz));
}
@SuppressWarnings("unchecked")
default <T> DataMapper<T> getDataMapper(String spec, Class<? extends T> clazz) {
if (!canParseSpec(spec)) {
return null;
}
Optional<ResolvedFunction> resolvedFunction = resolveFunction(spec);
if (!resolvedFunction.isPresent()) {
return null;
}
ResolvedFunction rf = resolvedFunction.get();
DataMapper<Object> dm = DataMapperFunctionMapper.map(rf.getFunctionObject());
return (DataMapper<T>) dm;
}
/**
* DataMapper Libraries are required to test specifier strings in order to determine
* whether or not the library could possibly find matching functions.
* This allows varying types of specifiers to be used that are library specific,
* allowing an ad-hoc form of syntax layering.
*
* @param spec a data mapping function spec
* @return a tagged Specifier option if successful
*/
boolean canParseSpec(String spec);
Optional<ResolvedFunction> resolveFunction(String spec);
/**
* @param specifier A specifier that describes the type and parameterization of a data mapping function instance.
* The type of specifier will be specific to your library implementation. You can use SpecData by default.
* @return a list of function instances
*/
List<ResolvedFunction> resolveFunctions(String specifier);
/**
* <p>Get the list of known data mapping function names.</p>
*
* @return list of data mapping function names that can be used in specifiers
*/
List<String> getDataMapperNames();
// default <T> Optional<DataMapper<T>> getDataMapper(String spec) {
default Optional<DataMapper<Long>> getLongDataMapper(String spec) {
if (!canParseSpec(spec)) {
return Optional.empty();
}
Optional<ResolvedFunction> resolvedFunction = resolveFunction(spec);
Optional<DataMapper<Long>> mapper = resolvedFunction
.map(ResolvedFunction::getFunctionObject)
.map(DataMapperFunctionMapper::map);
return mapper;
}
default Optional<DataMapper<Double>> getDoubleDataMapper(String spec) {
if (!canParseSpec(spec)) {
return Optional.empty();
}
Optional<ResolvedFunction> resolvedFunction = resolveFunction(spec);
Optional<DataMapper<Double>> mapper = resolvedFunction
.map(ResolvedFunction::getFunctionObject)
.map(DataMapperFunctionMapper::map);
return mapper;
}
default Optional<DataMapper<Integer>> getIntegerDataMapper(String spec) {
if (!canParseSpec(spec)) {
return Optional.empty();
}
Optional<ResolvedFunction> resolvedFunction = resolveFunction(spec);
Optional<DataMapper<Integer>> mapper = resolvedFunction
.map(ResolvedFunction::getFunctionObject)
.map(DataMapperFunctionMapper::map);
return mapper;
}
default Optional<DataMapper<String>> getStringDataMapper(String spec) {
if (!canParseSpec(spec)) {
return Optional.empty();
}
Optional<ResolvedFunction> resolvedFunction = resolveFunction(spec);
Optional<DataMapper<String>> mapper = resolvedFunction
.map(ResolvedFunction::getFunctionObject)
.map(DataMapperFunctionMapper::map);
return mapper;
}
}

View File

@ -0,0 +1,69 @@
package io.virtdata.api;
import java.util.function.*;
/**
* <p>Captures the list of function object types which may be used
* to implement data mapping functions. Library implementations
* may rely on this for type metadata.</p>
*/
public enum FunctionType {
long_long(LongUnaryOperator.class, long.class, long.class),
long_int(LongToIntFunction.class, long.class, int.class),
long_double(LongToDoubleFunction.class, long.class, double.class),
long_T(LongFunction.class, long.class, Object.class),
int_int(IntUnaryOperator.class, int.class, int.class),
int_long(IntToLongFunction.class, int.class, long.class),
int_double(IntToDoubleFunction.class, int.class, double.class),
int_T(IntFunction.class, int.class, Object.class),
double_T(DoubleFunction.class, double.class, Object.class),
double_double(DoubleUnaryOperator.class, double.class, double.class),
double_int(DoubleToIntFunction.class, double.class, int.class),
double_long(DoubleToLongFunction.class, double.class, long.class),
R_T(Function.class, Object.class, Object.class);
private final Class<?> functionClass;
private Class<?> inputClass;
private Class<?> returnClass;
private ValueType returnValueType;
private ValueType inputValueType;
FunctionType(Class<?> functionClass, Class<?> inputClass, Class<?> returnClass) {
this.functionClass = functionClass;
this.inputClass = inputClass;
this.returnClass = returnClass;
this.returnValueType = ValueType.valueOfAssignableClass(returnClass);
this.inputValueType = ValueType.valueOfAssignableClass(inputClass);
}
public Class<?> getInputClass() {
return inputClass;
}
public Class<?> getReturnClass() {
return returnClass;
}
public Class<?> getFunctionClass() {
return functionClass;
}
public static FunctionType valueOf(Class<?> clazz) {
for(FunctionType functionType: FunctionType.values()) {
if (functionType.functionClass==clazz) {
return functionType;
}
}
throw new RuntimeException("Unable to determine FunctionType for object class:" + clazz);
}
public static FunctionType valueOf(Object g) {
for (FunctionType functionType : FunctionType.values()) {
if (functionType.functionClass.isAssignableFrom(g.getClass())) {
return functionType;
}
}
throw new RuntimeException("Unable to determine FunctionType for object class:" + g.getClass());
}
public ValueType getInputValueType() {
return inputValueType;
}
}

View File

@ -0,0 +1,10 @@
package io.virtdata.api;
public interface Named {
/**
* <p>Return the name for this function library implementation.</p>
*
* @return Simple lower-case canonical library name
*/
String getName();
}

View File

@ -0,0 +1,11 @@
package io.virtdata.api;
/**
* A public class which holds global values. This is used for holding
* an intentional type of unset which is different than null.
* For downstream consumer libraries which need to distinguish between
* unset and null, this is that value.
*/
public enum VALUE {
unset // unset does not mean Null.
}

View File

@ -0,0 +1,91 @@
package io.virtdata.api;/*
* Copyright 2016 jshook
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
import java.util.Comparator;
/**
* Capture preference for types, favoring more efficient types for generation over others.
*/
public enum ValueType implements Comparator<ValueType> {
LONG(long.class, 1),
INT(int.class, 2),
FLOAT(float.class, 3),
DOUBLE(double.class, 4),
BOOLEAN(boolean.class, 5),
BYTE(byte.class, 6),
STRING(String.class, 7),
OBJECT(Object.class, 8);
private final Class<?> clazz;
private int precedence;
ValueType(Class<?> clazz, int precedence) {
this.clazz = clazz;
this.precedence = precedence;
}
public String getSimpleName() {
return this.clazz.getSimpleName();
}
public static ValueType valueOfClassName(String typeName) {
if (typeName==null) { return null; }
for (ValueType valueType : ValueType.values()) {
if (valueType.clazz.getSimpleName().equals(typeName)) {
return valueType;
}
}
return ValueType.OBJECT;
// throw new RuntimeException("Unable to find a matching value type for " + typeName);
}
public static Class<?> classOfType(String inputType) {
if (inputType==null) {
return null;
}
ValueType valueType = ValueType.valueOfClassName(inputType);
if (valueType == null) {
return null;
}
if (valueType == ValueType.OBJECT) {
try {
return Class.forName(inputType);
} catch (ClassNotFoundException e) {
throw new RuntimeException("Unable to determine class for type " + inputType + ". Consider adding the full package to the name.");
}
}
return valueType.getValueClass();
}
public static ValueType valueOfAssignableClass(Class<?> clazz) {
for (ValueType valueType : ValueType.values()) {
if (valueType.clazz.isAssignableFrom(clazz)) {
return valueType;
}
}
throw new RuntimeException("Unable to find a matching value type for " + clazz);
}
@Override
public int compare(ValueType o1, ValueType o2) {
return Integer.compare(o1.precedence, o2.precedence);
}
public Class<?> getValueClass() {
return this.clazz;
}
}

View File

@ -0,0 +1,40 @@
package io.virtdata.api;
import io.virtdata.core.ContextualBindingsArrayTemplate;
import io.virtdata.templates.StringCompositor;
/**
* <p>ValuesArrayBinder provides a way to apply an array of object values to a template
* object of type T to yield a new object instance of type R. The object array is
* a positional argument list. There is no named-argument facility.</p>
*
* <p>Parameter Examples:</p>
* <ul>
* <LI>T: prepared Statement, R: bound statement</LI>
* <LI>T: string template, R: interpolated string value</LI>
* </ul>
*
* <p>ValuesArrayBinders can either be created as helper types, to be passed in as
* mapping functions to other calls, or they can be directly implemented in higher-order
* types which include the ability to produce objects of type R from values provided.
* Both types of use are found in this API. An example of the former type would be
* {@link ContextualBindingsArrayTemplate},
* while and example of the latter would
* be {@link StringCompositor}.
* be {@link StringCompositor}.
* </p>
*
* @param <T> The template type
* @param <R> The result type
*/
public interface ValuesArrayBinder<T, R> {
/**
* Using context instance of type T, AKA the template, create and bind values to
* target object of type R
* @param context A context object that knows how to provide an instance of type R
* @param values An array of values which should be bound to the new R instance
* @return The new result instance of R
*/
R bindValues(T context, Object[] values);
}

View File

@ -0,0 +1,30 @@
package io.virtdata.api;
import io.virtdata.core.Bindings;
/**
* <p>ValuesBinder provides a way to apply an map of named object values to a template
* object of type T to yield a new object instance of type R. Get the values you need
* from the bindings in any appropriate way and apply them to your template object.
*
* <p>Parameter Examples:</p>
* <ul>
* <LI>T: prepared Statement, R: bound statement</LI>
* <LI>T: string template, R: interpolated string value</LI>
* </ul>
*
* @param <T> The template type
* @param <R> The result type
*/
public interface ValuesBinder<T, R> {
/**
* Using context instance of type S, AKA the template, create and bind values to
* target object of type R
* @param context A context object that knows how to provide an instance of type R
* @param bindings A Bindings instance from which to draw the values
* @param cycle The cycle for which to generate the values
* @return The new result instance of R
*/
R bindValues(T context, Bindings bindings, long cycle);
}

View File

@ -0,0 +1,29 @@
package io.virtdata.api;
import java.util.Map;
/**
* <p>ValuesMapBinder provides a way to apply an map of named object values to a template
* object of type T to yield a new object instance of type R. The object array is
* a positional argument list. There is no named-argument facility.</p>
*
* <p>Parameter Examples:</p>
* <ul>
* <LI>T: prepared Statement, R: bound statement</LI>
* <LI>T: string template, R: interpolated string value</LI>
* </ul>
*
* @param <T> The template type
* @param <R> The result type
*/
public interface ValuesMapBinder<T, R> {
/**
* Using context instance of type S, AKA the template, create and bind values to
* target object of type R
* @param context A context object that knows how to provide an instance of type R
* @param values An array of values which should be bound to the new R instance
* @return The new result instance of R
*/
R bindValues(T context, Map<String,Object> values);
}

View File

@ -0,0 +1,122 @@
package io.virtdata.api;
import io.virtdata.ast.Expression;
import io.virtdata.ast.FunctionCall;
import io.virtdata.core.DataMapperFunctionMapper;
import io.virtdata.core.ResolvedFunction;
import io.virtdata.parser.VirtDataDSL;
import java.util.*;
import java.util.stream.Collectors;
/**
* A VirtDataFunctionLibrary is simply a way to ask for a set
* of named function objects in a generic way.
*/
public interface VirtDataFunctionLibrary extends Named {
/**
* Given a signature for a unary function which takes an input
* and output type, a function name, and constructor arguments,
* return a list of instances from all implementations that have
* the same name as the function name,
* which have a matching constructor signature, and which also
* have a functional method which can be used with the provided
* input and output types.
*
* The input and output types are optionally specified. If either
* is provided, the returned functions should be constrained to match,
* but otherwise all possibly matching functions are included.
*
* Further, the argument should not be strict type checks, but should
* allow any matching constructor for which a compatible assignment
* can be made.
*
* The specified function name does not have to map to a
*
* @param returnType The class which the apply method should return,
* or null if unspecified
* @param inputType The class which the unary apply method should take as an
* argument, or null if unspecified
* @param functionName The name of the implementation to match
* @param parameters A list of arguments which will be used to instantiate
* any matching implementations
* @return A list, possibly empty, of matching functions
*/
List<ResolvedFunction> resolveFunctions(
Class<?> returnType,
Class<?> inputType,
String functionName,
Map<String,?> customConfigs,
Object... parameters
);
default List<ResolvedFunction> resolveFunction(String spec) {
return this.resolveFunctions(spec, new HashMap<>());
}
default List<ResolvedFunction> resolveFunctions(String spec, Map<String,Object> customConfigs) {
List<ResolvedFunction> resolvedFunctions = new ArrayList<>();
VirtDataDSL.ParseResult parseResult = VirtDataDSL.parse(spec);
if (parseResult.throwable!=null) {
throw new RuntimeException(parseResult.throwable);
}
List<Expression> expressions = parseResult.flow.getExpressions();
if (expressions.size() > 1) {
throw new RuntimeException("Unable to promote a lambda flow to a data mapper here.");
}
FunctionCall call = expressions.get(0).getCall();
List<ResolvedFunction> found = resolveFunctions(
Optional.ofNullable(call.getOutputType()).map(ValueType::valueOfClassName).map(ValueType::getValueClass).orElse(null),
Optional.ofNullable(call.getInputType()).map(ValueType::valueOfClassName).map(ValueType::getValueClass).orElse(null),
call.getFunctionName(),
customConfigs,
call.getArguments());
resolvedFunctions.addAll(found);
return resolvedFunctions;
}
default <T> List<DataMapper<T>> getDataMappers(String spec) {
return this.getDataMappers(spec,new HashMap<>());
}
default <T> List<DataMapper<T>> getDataMappers(String spec, Map<String,Object> customConfigs) {
List<ResolvedFunction> resolvedFunctions1 = this.resolveFunctions(spec, customConfigs);
return resolvedFunctions1.stream().map(
r -> DataMapperFunctionMapper.<T>map(r.getFunctionObject())).collect(Collectors.toList());
}
/**
* Provide a way to promote a long function into a data mapper.
*
* @param spec a binding spec
* @param <T> The type of data mapper to return
* @return An optional data mapper
*/
default <T> Optional<DataMapper<T>> getDataMapper(String spec) {
return this.getDataMapper(spec, new HashMap<>());
}
default <T> Optional<DataMapper<T>> getDataMapper(String spec, Map<String,Object> customConfigs) {
List<ResolvedFunction> resolvedFunctions = this.resolveFunctions(spec, customConfigs);
switch (resolvedFunctions.size()) {
case 0:
return Optional.empty();
case 1:
return Optional.of(DataMapperFunctionMapper.<T>map(resolvedFunctions.get(0).getFunctionObject()));
default:
throw new RuntimeException(
"Found " + resolvedFunctions.size() +
" data mapping functions, expected exactly one for library-level function lookups." +
" This may require both an input and an output type qualifier like 'int -> f() -> int'." +
" \nFound: [<library name>::] input->class->output [initializer type->parameter type,...]: \n" +
resolvedFunctions.stream().map(String::valueOf).collect(Collectors.joining("\n")));
}
}
}

View File

@ -0,0 +1,222 @@
package io.virtdata.api.composers;
import io.virtdata.api.FunctionType;
import io.virtdata.api.ValueType;
import java.util.function.*;
public class ComposerForDoubleFunction implements FunctionComposer<DoubleFunction<?>> {
private final DoubleFunction<?> inner;
public ComposerForDoubleFunction(DoubleFunction<?> inner) {
this.inner = inner;
}
@Override
public Object getFunctionObject() {
return inner;
}
@Override
@SuppressWarnings("unchecked")
public FunctionComposer andThen(Object outer) {
FunctionType outerFunctionType = FunctionType.valueOf(outer);
Object outv = this.inner.apply(1);
ValueType itype = ValueType.valueOfAssignableClass(outv.getClass());
switch (outerFunctionType) {
case long_long:
switch (itype) {
case LONG:
final DoubleToLongFunction f11 = (double d) ->
((LongUnaryOperator) outer).applyAsLong(((DoubleToLongFunction) inner).applyAsLong(d));
return new ComposerForDoubleToLongFunction(f11);
case DOUBLE:
final DoubleToLongFunction f12 = (double d) ->
((LongUnaryOperator) outer).applyAsLong((long) ((DoubleUnaryOperator) inner).applyAsDouble(d));
return new ComposerForDoubleToLongFunction(f12);
case INT:
final DoubleToLongFunction f13 = (double d) ->
((LongUnaryOperator) outer).applyAsLong(((DoubleToIntFunction) inner).applyAsInt(d));
return new ComposerForDoubleToLongFunction(f13);
default:
final DoubleToLongFunction f14 = (double d) ->
((LongUnaryOperator) outer).applyAsLong(Long.valueOf(((DoubleFunction<Object>) inner).apply(d).toString()));
return new ComposerForDoubleToLongFunction(f14);
}
case long_T:
final DoubleFunction<?> f2 =
(double d) -> ((LongFunction<?>) outer).apply(((DoubleFunction<Long>) inner).apply(d));
return new ComposerForDoubleFunction(f2);
case long_int:
final DoubleToIntFunction f3 =
(double d) -> ((LongToIntFunction) outer).applyAsInt(((DoubleFunction<Long>) inner).apply(d));
return new ComposerForDoubleToIntFunction(f3);
case long_double:
final DoubleUnaryOperator f4 =
(double d) -> ((LongToDoubleFunction) outer).applyAsDouble(((DoubleFunction<Long>) inner).apply(d));
return new ComposerForDoubleUnaryOperator(f4);
case int_int:
switch (itype) {
case LONG:
final DoubleToIntFunction f51 = (double d) ->
((IntUnaryOperator) outer).applyAsInt(((DoubleFunction<Long>) inner).apply(d).intValue());
return new ComposerForDoubleToIntFunction(f51);
case DOUBLE:
final DoubleToIntFunction f52 = (double d) ->
((IntUnaryOperator) outer).applyAsInt(((DoubleFunction<Double>) inner).apply(d).intValue());
return new ComposerForDoubleToIntFunction(f52);
case INT:
final DoubleToIntFunction f53 = (double d) ->
((IntUnaryOperator) outer).applyAsInt(((DoubleFunction<Integer>) inner).apply(d));
return new ComposerForDoubleToIntFunction(f53);
default:
final DoubleToIntFunction f54 = (double d) ->
((IntUnaryOperator) outer).applyAsInt(Integer.valueOf(((DoubleFunction<Object>) inner).apply(d).toString()));
return new ComposerForDoubleToIntFunction(f54);
}
case int_long:
switch (itype) {
case LONG:
final DoubleToLongFunction f61 =
(double d) -> ((IntToLongFunction) outer).applyAsLong(((DoubleFunction<Long>) inner).apply(d).intValue());
return new ComposerForDoubleToLongFunction(f61);
case DOUBLE:
final DoubleToLongFunction f62 =
(double d) -> ((IntToLongFunction) outer).applyAsLong(((DoubleFunction<Double>) inner).apply(d).intValue());
return new ComposerForDoubleToLongFunction(f62);
case INT:
final DoubleToLongFunction f63 =
(double d) -> ((IntToLongFunction) outer).applyAsLong(((DoubleFunction<Integer>) inner).apply(d));
return new ComposerForDoubleToLongFunction(f63);
default:
final DoubleToLongFunction f64 =
(double d) -> ((IntToLongFunction) outer).applyAsLong(Integer.valueOf(((DoubleFunction<Object>) inner).apply(d).toString()));
return new ComposerForDoubleToLongFunction(f64);
}
case int_double:
switch (itype) {
case LONG:
final DoubleUnaryOperator f71 =
(double d) -> ((IntToDoubleFunction) outer).applyAsDouble(((DoubleFunction<Long>) inner).apply(d).intValue());
return new ComposerForDoubleUnaryOperator(f71);
case DOUBLE:
final DoubleUnaryOperator f72 =
(double d) -> ((IntToDoubleFunction) outer).applyAsDouble(((DoubleFunction<Double>) inner).apply(d).intValue());
return new ComposerForDoubleUnaryOperator(f72);
case INT:
final DoubleUnaryOperator f73 =
(double d) -> ((IntToDoubleFunction) outer).applyAsDouble(((DoubleFunction<Integer>) inner).apply(d));
return new ComposerForDoubleUnaryOperator(f73);
default:
final DoubleUnaryOperator f74 =
(double d) -> ((IntToDoubleFunction) outer).applyAsDouble(Integer.valueOf(((DoubleFunction<Object>) inner).apply(d).toString()));
return new ComposerForDoubleUnaryOperator(f74);
}
case int_T:
switch (itype) {
case LONG:
final DoubleFunction<?> f81 =
(double d) -> ((IntFunction<?>) outer).apply(((DoubleFunction<Long>) inner).apply(d).intValue());
return new ComposerForDoubleFunction(f81);
case DOUBLE:
final DoubleFunction<?> f82 =
(double d) -> ((IntFunction<?>) outer).apply(((DoubleFunction<Double>) inner).apply(d).intValue());
return new ComposerForDoubleFunction(f82);
case INT:
final DoubleFunction<?> f83 =
(double d) -> ((IntFunction<?>) outer).apply(((DoubleFunction<Integer>) inner).apply(d));
return new ComposerForDoubleFunction(f83);
default:
final DoubleFunction<?> f84 =
(double d) -> ((IntFunction<?>) outer).apply(Integer.valueOf(((DoubleFunction<Object>) inner).apply(d).toString()));
return new ComposerForDoubleFunction(f84);
}
case double_double:
switch (itype) {
case LONG:
final DoubleUnaryOperator f91 =
(double d) -> ((DoubleUnaryOperator) outer).applyAsDouble(((DoubleFunction<Long>) inner).apply(d));
return new ComposerForDoubleUnaryOperator(f91);
case DOUBLE:
final DoubleUnaryOperator f92 =
(double d) -> ((DoubleUnaryOperator) outer).applyAsDouble(((DoubleFunction<Double>) inner).apply(d));
return new ComposerForDoubleUnaryOperator(f92);
case INT:
final DoubleUnaryOperator f93 =
(double d) -> ((DoubleUnaryOperator) outer).applyAsDouble(((DoubleFunction<Integer>) inner).apply(d));
return new ComposerForDoubleUnaryOperator(f93);
default:
final DoubleUnaryOperator f94 =
(double d) -> ((DoubleUnaryOperator) outer).applyAsDouble(Double.valueOf(((DoubleFunction<Object>) inner).apply(d).toString()));
return new ComposerForDoubleUnaryOperator(f94);
}
case double_long:
final DoubleToLongFunction f10 =
(double d) -> ((DoubleToLongFunction) outer).applyAsLong(((DoubleFunction<Long>) inner).apply(d));
return new ComposerForDoubleToLongFunction(f10);
case double_int:
switch (itype) {
case LONG:
final DoubleToIntFunction f111 =
(double d) -> ((DoubleToIntFunction) outer).applyAsInt(((DoubleFunction<Long>) inner).apply(d));
return new ComposerForDoubleToIntFunction(f111);
case DOUBLE:
final DoubleToIntFunction f112 =
(double d) -> ((DoubleToIntFunction) outer).applyAsInt(((DoubleFunction<Double>) inner).apply(d));
return new ComposerForDoubleToIntFunction(f112);
case INT:
final DoubleToIntFunction f113 =
(double d) -> ((DoubleToIntFunction) outer).applyAsInt(((DoubleFunction<Integer>) inner).apply(d));
return new ComposerForDoubleToIntFunction(f113);
default:
final DoubleToIntFunction f114 =
(double d) -> ((DoubleToIntFunction) outer).applyAsInt(Double.valueOf(((DoubleFunction<Object>) inner).apply(d).toString()));
return new ComposerForDoubleToIntFunction(f114);
}
case double_T:
switch (itype) {
case LONG:
final DoubleFunction<?> f121 =
(double d) -> ((DoubleFunction<?>) outer).apply(((DoubleFunction<Long>) inner).apply(d));
return new ComposerForDoubleFunction(f121);
case DOUBLE:
final DoubleFunction<?> f122 =
(double d) -> ((DoubleFunction<?>) outer).apply(((DoubleFunction<Double>) inner).apply(d));
return new ComposerForDoubleFunction(f122);
case INT:
final DoubleFunction<?> f123 =
(double d) -> ((DoubleFunction<?>) outer).apply(((DoubleFunction<Integer>) inner).apply(d));
return new ComposerForDoubleFunction(f123);
default:
final DoubleFunction<?> f124 =
(double d) -> ((DoubleFunction<?>) outer).apply(Double.valueOf(((DoubleFunction<Object>) inner).apply(d).toString()));
return new ComposerForDoubleFunction(f124);
}
case R_T:
switch (itype) {
case LONG:
final DoubleFunction<?> f131 =
(double d) -> ((Function<Object,Object>)outer).apply(((DoubleToLongFunction)inner).applyAsLong(d));
return new ComposerForDoubleFunction(f131);
case DOUBLE:
final DoubleFunction<?> f132 =
(double d) -> ((Function<Object,Object>)outer).apply(((DoubleUnaryOperator)inner).applyAsDouble(d));
return new ComposerForDoubleFunction(f132);
case INT:
final DoubleFunction<?> f133 =
(double d) -> ((Function<Object,Object>)outer).apply(((DoubleToIntFunction)inner).applyAsInt(d));
return new ComposerForDoubleFunction(f133);
default:
final DoubleFunction<?> f134 =
(double d) -> ((Function<Object,Object>)outer).apply(((DoubleFunction<Object>)inner).apply(d));
return new ComposerForDoubleFunction(f134);
}
default:
throw new RuntimeException(outerFunctionType + " is not recognized");
}
}
}

View File

@ -0,0 +1,81 @@
package io.virtdata.api.composers;
import io.virtdata.api.FunctionType;
import java.util.function.*;
public class ComposerForDoubleToIntFunction implements FunctionComposer<DoubleToIntFunction> {
private final DoubleToIntFunction inner;
public ComposerForDoubleToIntFunction(DoubleToIntFunction inner) {
this.inner = inner;
}
@Override
public Object getFunctionObject() {
return inner;
}
@Override
@SuppressWarnings("unchecked")
public FunctionComposer andThen(Object outer) {
FunctionType functionType = FunctionType.valueOf(outer);
switch (functionType) {
case long_long:
final DoubleToLongFunction f1 =
(double d) -> ((LongUnaryOperator) outer).applyAsLong((inner).applyAsInt(d));
return new ComposerForDoubleToLongFunction(f1);
case long_int:
final DoubleToIntFunction f2 =
(double d) -> ((LongToIntFunction) outer).applyAsInt(( inner).applyAsInt(d));
return new ComposerForDoubleToIntFunction(f2);
case long_double:
final DoubleUnaryOperator f3 =
(double d) -> ((LongToDoubleFunction)outer).applyAsDouble((inner).applyAsInt(d));
return new ComposerForDoubleUnaryOperator(f3);
case long_T:
final DoubleFunction<?> f4 =
(double d) -> ((LongFunction<?>)outer).apply((inner).applyAsInt(d));
return new ComposerForDoubleFunction(f4);
case int_int:
final DoubleToIntFunction f5 =
(double d) -> ((IntUnaryOperator)outer).applyAsInt((inner).applyAsInt(d));
return new ComposerForDoubleToIntFunction(f5);
case int_long:
final DoubleToLongFunction f6 =
(double d) -> ((IntToLongFunction)outer).applyAsLong((inner).applyAsInt(d));
return new ComposerForDoubleToLongFunction(f6);
case int_double:
final DoubleUnaryOperator f7 =
(double d) -> ((IntToDoubleFunction)outer).applyAsDouble((inner).applyAsInt(d));
return new ComposerForDoubleUnaryOperator(f7);
case int_T:
final DoubleFunction<?> f8 =
(double d) -> ((IntFunction<?>)outer).apply((inner).applyAsInt(d));
return new ComposerForDoubleFunction(f8);
case double_double:
final DoubleUnaryOperator f9 =
(double d) -> ((DoubleUnaryOperator) outer).applyAsDouble((inner).applyAsInt(d));
return new ComposerForDoubleUnaryOperator(f9);
case double_long:
final DoubleToLongFunction f10 =
(double d) -> ((DoubleToLongFunction)outer).applyAsLong((inner).applyAsInt(d));
return new ComposerForDoubleToLongFunction(f10);
case double_int:
final DoubleToIntFunction f11 =
(double d) -> ((DoubleToIntFunction)outer).applyAsInt((inner).applyAsInt(d));
return new ComposerForDoubleToIntFunction(f11);
case double_T:
final DoubleFunction<?> f12 =
(double d) -> ((DoubleFunction<?>)outer).apply((inner).applyAsInt(d));
return new ComposerForDoubleFunction(f12);
case R_T:
final DoubleFunction<?> f13 =
(double d) -> ((Function<Integer,?>)outer).apply((inner).applyAsInt(d));
return new ComposerForDoubleFunction(f13);
default:
throw new RuntimeException("Unrecognized function type:" + functionType);
}
}
}

View File

@ -0,0 +1,94 @@
package io.virtdata.api.composers;
import io.virtdata.api.FunctionType;
import java.util.function.*;
public class ComposerForDoubleToLongFunction implements FunctionComposer<DoubleToLongFunction> {
private final DoubleToLongFunction inner;
public ComposerForDoubleToLongFunction(DoubleToLongFunction inner) {
this.inner = inner;
}
@Override
public Object getFunctionObject() {
return inner;
}
@Override
@SuppressWarnings("unchecked")
public FunctionComposer andThen(Object outer) {
FunctionType functionType = FunctionType.valueOf(outer);
switch (functionType) {
case long_long:
final DoubleToLongFunction f1 =
(double d) -> ((LongUnaryOperator)outer).applyAsLong(inner.applyAsLong(d));
return new ComposerForDoubleToLongFunction(f1);
case long_int:
final DoubleToIntFunction f2 =
(double d) -> ((LongToIntFunction)outer).applyAsInt(inner.applyAsLong(d));
return new ComposerForDoubleToIntFunction(f2);
case long_double:
final DoubleUnaryOperator f3 =
(double d) -> ((LongToDoubleFunction)outer).applyAsDouble(inner.applyAsLong(d));
return new ComposerForDoubleUnaryOperator(f3);
case long_T:
final DoubleFunction<?> f4 =
(double d) -> ((LongFunction<?>)outer).apply(inner.applyAsLong(d));
return new ComposerForDoubleFunction(f4);
case int_int:
final DoubleToIntFunction f5 =
(double d) -> ((IntUnaryOperator)outer).applyAsInt((int) inner.applyAsLong(d));
return new ComposerForDoubleToIntFunction(f5);
case int_long:
final DoubleToLongFunction f6 =
(double d) -> ((IntToLongFunction)outer).applyAsLong((int) inner.applyAsLong(d));
return new ComposerForDoubleToLongFunction(f6);
case int_double:
final DoubleUnaryOperator f7 =
(double d) -> ((IntToDoubleFunction)outer).applyAsDouble((int) inner.applyAsLong(d));
return new ComposerForDoubleUnaryOperator(f7);
case int_T:
final DoubleFunction<?> f8 =
(double d) -> ((IntFunction<?>)outer).apply((int) inner.applyAsLong(d));
return new ComposerForDoubleFunction(f8);
case double_double:
final DoubleUnaryOperator f9 =
(double d) -> ((DoubleUnaryOperator)outer).applyAsDouble(inner.applyAsLong(d));
return new ComposerForDoubleUnaryOperator(f9);
case double_int:
final DoubleToIntFunction f10 =
(double d) -> ((DoubleToIntFunction)outer).applyAsInt(inner.applyAsLong(d));
return new ComposerForDoubleToIntFunction(f10);
case double_long:
final DoubleToLongFunction f11 =
(double d) -> ((DoubleToLongFunction)outer).applyAsLong(inner.applyAsLong(d));
return new ComposerForDoubleToLongFunction(f11);
case double_T:
final DoubleFunction<?> f12 =
(double d) -> ((DoubleFunction<?>)outer).apply(inner.applyAsLong(d));
return new ComposerForDoubleFunction(f12);
case R_T:
final DoubleFunction<?> f13 =
(double d) -> ((Function<Long,?>)outer).apply(inner.applyAsLong(d));
return new ComposerForDoubleFunction(f13);
default:
throw new RuntimeException(functionType + " is not recognized");
}
}
}

View File

@ -0,0 +1,81 @@
package io.virtdata.api.composers;
import io.virtdata.api.FunctionType;
import java.util.function.*;
public class ComposerForDoubleUnaryOperator implements FunctionComposer<DoubleUnaryOperator> {
private final DoubleUnaryOperator inner;
public ComposerForDoubleUnaryOperator(DoubleUnaryOperator inner) {
this.inner = inner;
}
@Override
public Object getFunctionObject() {
return inner;
}
@Override
@SuppressWarnings("unchecked")
public FunctionComposer andThen(Object outer) {
FunctionType functionType = FunctionType.valueOf(outer);
switch (functionType) {
case long_long:
final DoubleToLongFunction f1 =
(double d) -> ((LongUnaryOperator)outer).applyAsLong((long)(inner).applyAsDouble(d));
return new ComposerForDoubleToLongFunction(f1);
case long_int:
final DoubleToIntFunction f2 =
(double d) -> ((LongToIntFunction)outer).applyAsInt((int)(inner).applyAsDouble(d));
return new ComposerForDoubleToIntFunction(f2);
case long_double:
final DoubleUnaryOperator f3 =
(double d) -> ((LongToDoubleFunction)outer).applyAsDouble((long)(inner).applyAsDouble(d));
return new ComposerForDoubleUnaryOperator(f3);
case long_T:
final DoubleFunction<?> f4 =
(double d) -> ((LongFunction<?>)outer).apply((long)(inner).applyAsDouble(d));
return new ComposerForDoubleFunction(f4);
case int_int:
final DoubleToIntFunction f5 =
(double d) -> ((IntUnaryOperator)outer).applyAsInt((int)(inner).applyAsDouble(d));
return new ComposerForDoubleToIntFunction(f5);
case int_long:
final DoubleToLongFunction f6 =
(double d) -> ((IntToLongFunction)outer).applyAsLong((int)(inner).applyAsDouble(d));
return new ComposerForDoubleToLongFunction(f6);
case int_double:
final DoubleUnaryOperator f7 =
(double d) -> ((IntToDoubleFunction)outer).applyAsDouble((int)inner.applyAsDouble(d));
return new ComposerForDoubleUnaryOperator(f7);
case int_T:
final DoubleFunction<?> f8 =
(double d) -> ((IntFunction<?>)outer).apply((int)(inner).applyAsDouble(d));
return new ComposerForDoubleFunction(f8);
case double_double:
final DoubleUnaryOperator f9 =
(double d) -> ((DoubleUnaryOperator)outer).applyAsDouble(inner.applyAsDouble(d));
return new ComposerForDoubleUnaryOperator(f9);
case double_long:
final DoubleToLongFunction f10 =
(double d) -> ((DoubleToLongFunction)outer).applyAsLong(inner.applyAsDouble(d));
return new ComposerForDoubleToLongFunction(f10);
case double_int:
final DoubleToIntFunction f11 =
(double d) -> ((DoubleToIntFunction)outer).applyAsInt(inner.applyAsDouble(d));
return new ComposerForDoubleToIntFunction(f11);
case double_T:
final DoubleFunction<?> f12 =
(double d) -> ((DoubleFunction<?>)outer).apply(inner.applyAsDouble(d));
return new ComposerForDoubleFunction(f12);
case R_T:
final DoubleFunction<?> f13 =
(double d) -> ((Function<Double,?>)outer).apply(inner.applyAsDouble(d));
return new ComposerForDoubleFunction(f13);
default:
throw new RuntimeException(functionType + " is not recognized");
}
}
}

View File

@ -0,0 +1,268 @@
package io.virtdata.api.composers;
import io.virtdata.api.FunctionType;
import io.virtdata.api.ValueType;
import java.util.function.*;
public class ComposerForFunction implements FunctionComposer<Function<?,?>> {
private final Function<?,?> inner;
public ComposerForFunction(Function<?, ?> inner) {
this.inner = inner;
}
@Override
public Object getFunctionObject() {
return inner;
}
@Override
@SuppressWarnings("unchecked")
public FunctionComposer andThen(Object outer) {
FunctionType functionType = FunctionType.valueOf(outer);
Object outv = ((Function<Object,Object>)this.inner).apply(1);
ValueType itype = ValueType.valueOfAssignableClass(outv.getClass());
switch (functionType) {
case long_long:
switch (itype) {
case LONG:
final Function<Object, Object> f11 = (Object o) ->
((LongUnaryOperator) outer).applyAsLong(((Function<Object, Long>) inner).apply(o));
return new ComposerForFunction(f11);
case DOUBLE:
final Function<Object, Object> f12 = (Object o) ->
((LongUnaryOperator) outer).applyAsLong(((Function<Object, Double>) inner).apply(o).longValue());
return new ComposerForFunction(f12);
case INT:
final Function<Object, Object> f13 = (Object o) ->
((LongUnaryOperator) outer).applyAsLong(((Function<Object, Integer>) inner).apply(o));
return new ComposerForFunction(f13);
default:
final Function<Object, Object> f14 = (Object o) ->
((LongUnaryOperator) outer).applyAsLong(Double.valueOf(((Function<Object, Object>) inner).apply(o).toString()).longValue());
return new ComposerForFunction(f14);
}
case long_int:
switch (itype) {
case LONG:
final Function<Object, Object> f11 = (Object o) ->
((LongToIntFunction) outer).applyAsInt(((Function<Object, Long>) inner).apply(o));
return new ComposerForFunction(f11);
case DOUBLE:
final Function<Object, Object> f12 = (Object o) ->
((LongToIntFunction) outer).applyAsInt(((Function<Object, Double>) inner).apply(o).longValue());
return new ComposerForFunction(f12);
case INT:
final Function<Object, Object> f13 = (Object o) ->
((LongToIntFunction) outer).applyAsInt(((Function<Object, Integer>) inner).apply(o));
return new ComposerForFunction(f13);
default:
final Function<Object, Object> f14 = (Object o) ->
((LongToIntFunction) outer).applyAsInt(Double.valueOf(((Function<Object, Object>) inner).apply(o).toString()).longValue());
return new ComposerForFunction(f14);
}
case long_double:
switch (itype) {
case LONG:
final Function<Object, Object> f11 = (Object o) ->
((LongToDoubleFunction) outer).applyAsDouble(((Function<Object, Long>) inner).apply(o));
return new ComposerForFunction(f11);
case DOUBLE:
final Function<Object, Object> f12 = (Object o) ->
((LongToDoubleFunction) outer).applyAsDouble(((Function<Object, Double>) inner).apply(o).longValue());
return new ComposerForFunction(f12);
case INT:
final Function<Object, Object> f13 = (Object o) ->
((LongToDoubleFunction) outer).applyAsDouble(((Function<Object, Integer>) inner).apply(o));
return new ComposerForFunction(f13);
default:
final Function<Object, Object> f14 = (Object o) ->
((LongToDoubleFunction) outer).applyAsDouble(Double.valueOf(((Function<Object, Object>) inner).apply(o).toString()).longValue());
return new ComposerForFunction(f14);
}
case long_T:
switch (itype) {
case LONG:
final Function<Object, Object> f11 = (Object o) ->
((LongFunction<Object>) outer).apply(((Function<Object, Long>) inner).apply(o));
return new ComposerForFunction(f11);
case DOUBLE:
final Function<Object, Object> f12 = (Object o) ->
((LongFunction<Object>) outer).apply(((Function<Object, Double>) inner).apply(o).longValue());
return new ComposerForFunction(f12);
case INT:
final Function<Object, Object> f13 = (Object o) ->
((LongFunction<Object>) outer).apply(((Function<Object, Integer>) inner).apply(o));
return new ComposerForFunction(f13);
default:
final Function<Object, Object> f14 = (Object o) ->
((LongFunction<Object>) outer).apply(Double.valueOf(((Function<Object, Object>) inner).apply(o).toString()).longValue());
return new ComposerForFunction(f14);
}
case R_T:
final Function<Object,Object> f5=
(Object o) ->
((Function<Object,Object>)outer).apply(((Function<Object,Object>)inner).apply(o));
return new ComposerForFunction(f5);
case int_int:
switch (itype) {
case LONG:
final Function<Object, Object> f11 = (Object o) ->
((IntUnaryOperator) outer).applyAsInt(((Function<Object, Long>) inner).apply(o).intValue());
return new ComposerForFunction(f11);
case DOUBLE:
final Function<Object, Object> f12 = (Object o) ->
((IntUnaryOperator) outer).applyAsInt(((Function<Object, Double>) inner).apply(o).intValue());
return new ComposerForFunction(f12);
case INT:
final Function<Object, Object> f13 = (Object o) ->
((IntUnaryOperator) outer).applyAsInt(((Function<Object, Integer>) inner).apply(o));
return new ComposerForFunction(f13);
default:
final Function<Object, Object> f14 = (Object o) ->
((IntUnaryOperator) outer).applyAsInt(Double.valueOf(((Function<Object, Object>) inner).apply(o).toString()).intValue());
return new ComposerForFunction(f14);
}
case int_long:
switch (itype) {
case LONG:
final Function<Object, Object> f11 = (Object o) ->
((IntToLongFunction) outer).applyAsLong(((Function<Object, Long>) inner).apply(o).intValue());
return new ComposerForFunction(f11);
case DOUBLE:
final Function<Object, Object> f12 = (Object o) ->
((IntToLongFunction) outer).applyAsLong(((Function<Object, Double>) inner).apply(o).intValue());
return new ComposerForFunction(f12);
case INT:
final Function<Object, Object> f13 = (Object o) ->
((IntToLongFunction) outer).applyAsLong(((Function<Object, Integer>) inner).apply(o));
return new ComposerForFunction(f13);
default:
final Function<Object, Object> f14 = (Object o) ->
((IntToLongFunction) outer).applyAsLong(Double.valueOf(((Function<Object, Object>) inner).apply(o).toString()).intValue());
return new ComposerForFunction(f14);
}
case int_double:
switch (itype) {
case LONG:
final Function<Object, Object> f11 = (Object o) ->
((IntToDoubleFunction) outer).applyAsDouble(((Function<Object, Long>) inner).apply(o).intValue());
return new ComposerForFunction(f11);
case DOUBLE:
final Function<Object, Object> f12 = (Object o) ->
((IntToDoubleFunction) outer).applyAsDouble(((Function<Object, Double>) inner).apply(o).intValue());
return new ComposerForFunction(f12);
case INT:
final Function<Object, Object> f13 = (Object o) ->
((IntToDoubleFunction) outer).applyAsDouble(((Function<Object, Integer>) inner).apply(o));
return new ComposerForFunction(f13);
default:
final Function<Object, Object> f14 = (Object o) ->
((IntToDoubleFunction) outer).applyAsDouble(Double.valueOf(((Function<Object, Object>) inner).apply(o).toString()).intValue());
return new ComposerForFunction(f14);
}
case int_T:
switch (itype) {
case LONG:
final Function<Object, Object> f11 = (Object o) ->
((IntFunction<Object>) outer).apply(((Function<Object, Long>) inner).apply(o).intValue());
return new ComposerForFunction(f11);
case DOUBLE:
final Function<Object, Object> f12 = (Object o) ->
((IntFunction<Object>) outer).apply(((Function<Object, Double>) inner).apply(o).intValue());
return new ComposerForFunction(f12);
case INT:
final Function<Object, Object> f13 = (Object o) ->
((IntFunction<Object>) outer).apply(((Function<Object, Integer>) inner).apply(o));
return new ComposerForFunction(f13);
default:
final Function<Object, Object> f14 = (Object o) ->
((IntFunction<Object>) outer).apply(Double.valueOf(((Function<Object, Object>) inner).apply(o).toString()).intValue());
return new ComposerForFunction(f14);
}
case double_double:
switch (itype) {
case LONG:
final Function<Object, Object> f11 = (Object o) ->
((DoubleUnaryOperator) outer).applyAsDouble(((Function<Object, Long>) inner).apply(o));
return new ComposerForFunction(f11);
case DOUBLE:
final Function<Object, Object> f12 = (Object o) ->
((DoubleUnaryOperator) outer).applyAsDouble(((Function<Object, Double>) inner).apply(o));
return new ComposerForFunction(f12);
case INT:
final Function<Object, Object> f13 = (Object o) ->
((DoubleUnaryOperator) outer).applyAsDouble(((Function<Object, Integer>) inner).apply(o));
return new ComposerForFunction(f13);
default:
final Function<Object, Object> f14 = (Object o) ->
((DoubleUnaryOperator) outer).applyAsDouble(Double.valueOf(((Function<Object, Object>) inner).apply(o).toString()));
return new ComposerForFunction(f14);
}
case double_int:
switch (itype) {
case LONG:
final Function<Object, Object> f11 = (Object o) ->
((DoubleToIntFunction) outer).applyAsInt(((Function<Object, Long>) inner).apply(o));
return new ComposerForFunction(f11);
case DOUBLE:
final Function<Object, Object> f12 = (Object o) ->
((DoubleToIntFunction) outer).applyAsInt(((Function<Object, Double>) inner).apply(o));
return new ComposerForFunction(f12);
case INT:
final Function<Object, Object> f13 = (Object o) ->
((DoubleToIntFunction) outer).applyAsInt(((Function<Object, Integer>) inner).apply(o));
return new ComposerForFunction(f13);
default:
final Function<Object, Object> f14 = (Object o) ->
((DoubleToIntFunction) outer).applyAsInt(Double.valueOf(((Function<Object, Object>) inner).apply(o).toString()));
return new ComposerForFunction(f14);
}
case double_long:
switch (itype) {
case LONG:
final Function<Object, Object> f11 = (Object o) ->
((DoubleToLongFunction) outer).applyAsLong(((Function<Object, Long>) inner).apply(o));
return new ComposerForFunction(f11);
case DOUBLE:
final Function<Object, Object> f12 = (Object o) ->
((DoubleToLongFunction) outer).applyAsLong(((Function<Object, Double>) inner).apply(o));
return new ComposerForFunction(f12);
case INT:
final Function<Object, Object> f13 = (Object o) ->
((DoubleToLongFunction) outer).applyAsLong(((Function<Object, Integer>) inner).apply(o));
return new ComposerForFunction(f13);
default:
final Function<Object, Object> f14 = (Object o) ->
((DoubleToLongFunction) outer).applyAsLong(Double.valueOf(((Function<Object, Object>) inner).apply(o).toString()));
return new ComposerForFunction(f14);
}
case double_T:
switch (itype) {
case LONG:
final Function<Object, Object> f11 = (Object o) ->
((DoubleFunction<Object>) outer).apply(((Function<Object, Long>) inner).apply(o));
return new ComposerForFunction(f11);
case DOUBLE:
final Function<Object, Object> f12 = (Object o) ->
((DoubleFunction<Object>) outer).apply(((Function<Object, Double>) inner).apply(o));
return new ComposerForFunction(f12);
case INT:
final Function<Object, Object> f13 = (Object o) ->
((DoubleFunction<Object>) outer).apply(((Function<Object, Integer>) inner).apply(o));
return new ComposerForFunction(f13);
default:
final Function<Object, Object> f14 = (Object o) ->
((DoubleFunction<Object>) outer).apply(Double.valueOf(((Function<Object, Object>) inner).apply(o).toString()));
return new ComposerForFunction(f14);
}
default:
throw new RuntimeException(functionType + " is not recognized");
}
}
}

View File

@ -0,0 +1,284 @@
package io.virtdata.api.composers;
import io.virtdata.api.FunctionType;
import io.virtdata.api.ValueType;
import java.util.function.*;
public class ComposerForIntFunction implements FunctionComposer<IntFunction<?>> {
private final IntFunction<?> inner;
public ComposerForIntFunction(IntFunction<?> inner) {
this.inner = inner;
}
@Override
@SuppressWarnings("unchecked")
public FunctionComposer<?> andThen(Object outer) {
FunctionType functionType = FunctionType.valueOf(outer);
Object outv = this.inner.apply(1);
ValueType itype = ValueType.valueOfAssignableClass(outv.getClass());
switch (functionType) {
case long_long:
switch (itype) {
case LONG:
final IntToLongFunction f11 = (int i) ->
((LongUnaryOperator) outer).applyAsLong((((IntFunction<Long>) inner).apply(i)).intValue());
return new ComposerForIntToLongFunction(f11);
case DOUBLE:
final IntToLongFunction f12 = (int i) ->
((LongUnaryOperator) outer).applyAsLong((((IntFunction<Double>) inner).apply(i)).intValue());
return new ComposerForIntToLongFunction(f12);
case INT:
final IntToLongFunction f13 = (int i) ->
((LongUnaryOperator) outer).applyAsLong((((IntFunction<Integer>) inner).apply(i)));
return new ComposerForIntToLongFunction(f13);
default:
final IntToLongFunction f14 = (int i) ->
((LongUnaryOperator) outer).applyAsLong(Double.valueOf((((IntFunction<Object>) inner).apply(i)).toString()).longValue());
return new ComposerForIntToLongFunction(f14);
}
case long_T:
switch (itype) {
case LONG:
final IntFunction<?> f21 = (int i) ->
((LongFunction<?>) outer).apply(((IntFunction<Long>) inner).apply(i));
return new ComposerForIntFunction(f21);
case DOUBLE:
final IntFunction<?> f22 = (int i) ->
((LongFunction<?>) outer).apply(((IntFunction<Double>) inner).apply(i).longValue());
return new ComposerForIntFunction(f22);
case INT:
final IntFunction<?> f23 = (int i) ->
((LongFunction<?>) outer).apply(((IntFunction<Integer>) inner).apply(i));
return new ComposerForIntFunction(f23);
default:
final IntFunction<?> f24 = (int i) ->
((LongFunction<?>) outer).apply(Double.valueOf(((IntFunction<Object>) inner).apply(i).toString()).longValue());
return new ComposerForIntFunction(f24);
}
case long_int:
switch (itype) {
case LONG:
final IntUnaryOperator f31 = (int i) ->
((LongToIntFunction) outer).applyAsInt(((IntFunction<Long>) inner).apply(i));
return new ComposerForIntUnaryOperator(f31);
case DOUBLE:
final IntUnaryOperator f32 = (int i) ->
((LongToIntFunction) outer).applyAsInt(((IntFunction<Double>) inner).apply(i).longValue());
return new ComposerForIntUnaryOperator(f32);
case INT:
final IntUnaryOperator f33 = (int i) ->
((LongToIntFunction) outer).applyAsInt(((IntFunction<Integer>) inner).apply(i));
return new ComposerForIntUnaryOperator(f33);
default:
final IntUnaryOperator f34 = (int i) ->
((LongToIntFunction) outer).applyAsInt(Double.valueOf(((IntFunction<Object>) inner).apply(i).toString()).longValue());
return new ComposerForIntUnaryOperator(f34);
}
case long_double:
switch (itype) {
case LONG:
final IntToDoubleFunction f41 = (int i) ->
((LongToDoubleFunction) outer).applyAsDouble(((IntFunction<Long>) inner).apply(i));
return new ComposerForIntToDoubleFunction(f41);
case DOUBLE:
final IntToDoubleFunction f42 = (int i) ->
((LongToDoubleFunction) outer).applyAsDouble(((IntFunction<Double>) inner).apply(i).longValue());
return new ComposerForIntToDoubleFunction(f42);
case INT:
final IntToDoubleFunction f43 = (int i) ->
((LongToDoubleFunction) outer).applyAsDouble(((IntFunction<Integer>) inner).apply(i));
return new ComposerForIntToDoubleFunction(f43);
default:
final IntToDoubleFunction f44 = (int i) ->
((LongToDoubleFunction) outer).applyAsDouble(Double.valueOf(((IntFunction<Object>) inner).apply(i).toString()).longValue());
return new ComposerForIntToDoubleFunction(f44);
}
case int_int:
switch (itype) {
case LONG:
final IntUnaryOperator f23 = (int i) ->
((IntUnaryOperator) outer).applyAsInt(((IntFunction<Long>) inner).apply(i).intValue());
return new ComposerForIntUnaryOperator(f23);
case DOUBLE:
final IntUnaryOperator f21 = (int i) ->
((IntUnaryOperator) outer).applyAsInt(((IntFunction<Double>) inner).apply(i).intValue());
return new ComposerForIntUnaryOperator(f21);
case INT:
final IntUnaryOperator f22 = (int i) ->
((IntUnaryOperator) outer).applyAsInt(((IntFunction<Integer>) inner).apply(i));
return new ComposerForIntUnaryOperator(f22);
default:
final IntUnaryOperator f24 = (int i) ->
((IntUnaryOperator) outer).applyAsInt(Double.valueOf(((IntFunction<Object>) inner).apply(i).toString()).intValue());
return new ComposerForIntUnaryOperator(f24);
}
case R_T:
switch (itype) {
case LONG:
final IntFunction<?> f61 = (int i) ->
((Function<Object,Object>) outer).apply(((IntFunction<Long>) inner).apply(i));
return new ComposerForIntFunction(f61);
case INT:
final IntFunction<?> f62 = (int i) ->
((IntFunction<?>) outer).apply(((IntFunction<Integer>) inner).apply(i));
return new ComposerForIntFunction(f62);
case DOUBLE:
final IntFunction<?> f63 = (int i) ->
((Function<Object,Object>) outer).apply(((IntFunction<Double>) inner).apply(i));
return new ComposerForIntFunction(f63);
default:
final IntFunction<?> f64 = (int i) ->
((Function<Object,Object>) outer).apply(((IntFunction<Object>) inner).apply(i));
return new ComposerForIntFunction(f64);
}
case int_long:
switch (itype) {
case LONG:
final IntToLongFunction f71 = (int i) ->
((IntToLongFunction) outer).applyAsLong(((IntFunction<Long>) inner).apply(i).intValue());
return new ComposerForIntToLongFunction(f71);
case INT:
final IntToLongFunction f72 = (int i) ->
((IntToLongFunction) outer).applyAsLong(((IntFunction<Integer>) inner).apply(i));
return new ComposerForIntToLongFunction(f72);
case DOUBLE:
final IntToLongFunction f73 = (int i) ->
((IntToLongFunction) outer).applyAsLong(((IntFunction<Long>) inner).apply(i).intValue());
return new ComposerForIntToLongFunction(f73);
default:
final IntToLongFunction f74 = (int i) ->
((IntToLongFunction) outer).applyAsLong(Double.valueOf(((IntFunction<Object>) inner).apply(i).toString()).intValue());
return new ComposerForIntToLongFunction(f74);
}
case int_double:
switch (itype) {
case LONG:
final IntToDoubleFunction f81 =
(int i) -> ((IntToDoubleFunction) outer).applyAsDouble(((IntFunction<Long>) inner).apply(i).intValue());
return new ComposerForIntToDoubleFunction(f81);
case INT:
final IntToDoubleFunction f82 =
(int i) -> ((IntToDoubleFunction) outer).applyAsDouble(((IntFunction<Integer>) inner).apply(i));
return new ComposerForIntToDoubleFunction(f82);
case DOUBLE:
final IntToDoubleFunction f83 =
(int i) -> ((IntToDoubleFunction) outer).applyAsDouble(((IntFunction<Long>) inner).apply(i).intValue());
return new ComposerForIntToDoubleFunction(f83);
default:
final IntToDoubleFunction f84 =
(int i) -> ((IntToDoubleFunction) outer).applyAsDouble(Double.valueOf(((IntFunction<Object>) inner).apply(i).toString()).intValue());
return new ComposerForIntToDoubleFunction(f84);
}
case int_T:
switch (itype) {
case LONG:
final IntFunction<?> f91 =
(int i) -> ((IntFunction<?>) outer).apply(((IntFunction<Long>) inner).apply(i).intValue());
return new ComposerForIntFunction(f91);
case INT:
final IntFunction<?> f92 =
(int i) -> ((IntFunction<?>) outer).apply(((IntFunction<Integer>) inner).apply(i));
return new ComposerForIntFunction(f92);
case DOUBLE:
final IntFunction<?> f93 =
(int i) -> ((IntFunction<?>) outer).apply(((IntFunction<Double>) inner).apply(i).intValue());
return new ComposerForIntFunction(f93);
default:
final IntFunction<?> f94 =
(int i) -> ((IntFunction<?>) outer).apply(Double.valueOf(((IntFunction<Object>) inner).apply(i).toString()).intValue());
return new ComposerForIntFunction(f94);
}
case double_double:
switch (itype) {
case LONG:
final IntToDoubleFunction f101 =
(int i) -> ((DoubleUnaryOperator) outer).applyAsDouble(((IntFunction<Long>) inner).apply(i));
return new ComposerForIntToDoubleFunction(f101);
case DOUBLE:
final IntToDoubleFunction f102 =
(int i) -> ((DoubleUnaryOperator) outer).applyAsDouble(((IntFunction<Double>) inner).apply(i));
return new ComposerForIntToDoubleFunction(f102);
case INT:
final IntToDoubleFunction f103 =
(int i) -> ((DoubleUnaryOperator) outer).applyAsDouble(((IntFunction<Integer>) inner).apply(i));
return new ComposerForIntToDoubleFunction(f103);
default:
final IntToDoubleFunction f104 =
(int i) -> ((DoubleUnaryOperator) outer).applyAsDouble(Double.valueOf(((IntFunction<Object>) inner).apply(i).toString()));
return new ComposerForIntToDoubleFunction(f104);
}
case double_long:
switch (itype) {
case LONG:
final IntToLongFunction f111 =
(int i) -> ((DoubleToLongFunction) outer).applyAsLong(((IntFunction<Long>) inner).apply(i));
return new ComposerForIntToLongFunction(f111);
case DOUBLE:
final IntToLongFunction f112 =
(int i) -> ((DoubleToLongFunction) outer).applyAsLong(((IntFunction<Double>) inner).apply(i));
return new ComposerForIntToLongFunction(f112);
case INT:
final IntToLongFunction f113 =
(int i) -> ((DoubleToLongFunction) outer).applyAsLong(((IntFunction<Integer>) inner).apply(i));
return new ComposerForIntToLongFunction(f113);
default:
final IntToLongFunction f114 =
(int i) -> ((DoubleToLongFunction) outer).applyAsLong(Double.valueOf(((IntFunction<Object>) inner).apply(i).toString()));
return new ComposerForIntToLongFunction(f114);
}
case double_int:
switch (itype) {
case LONG:
final IntUnaryOperator f121 =
(int i) -> ((DoubleToIntFunction) outer).applyAsInt(((IntFunction<Long>) inner).apply(i));
return new ComposerForIntUnaryOperator(f121);
case DOUBLE:
final IntUnaryOperator f122 =
(int i) -> ((DoubleToIntFunction) outer).applyAsInt(((IntFunction<Double>) inner).apply(i));
return new ComposerForIntUnaryOperator(f122);
case INT:
final IntUnaryOperator f123 =
(int i) -> ((DoubleToIntFunction) outer).applyAsInt(((IntFunction<Integer>) inner).apply(i));
return new ComposerForIntUnaryOperator(f123);
default:
final IntUnaryOperator f124 =
(int i) -> ((DoubleToIntFunction) outer).applyAsInt(Double.valueOf(((IntFunction<Object>) inner).apply(i).toString()));
return new ComposerForIntUnaryOperator(f124);
}
case double_T:
switch (itype) {
case LONG:
final IntFunction<?> f131 =
(int i) -> ((DoubleFunction<?>) outer).apply(((IntFunction<Long>) inner).apply(i));
return new ComposerForIntFunction(f131);
case DOUBLE:
final IntFunction<?> f132 =
(int i) -> ((DoubleFunction<?>) outer).apply(((IntFunction<Double>) inner).apply(i));
return new ComposerForIntFunction(f132);
case INT:
final IntFunction<?> f133 =
(int i) -> ((DoubleFunction<?>) outer).apply(((IntFunction<Integer>) inner).apply(i));
return new ComposerForIntFunction(f133);
default:
final IntFunction<?> f134 =
(int i) -> ((DoubleFunction<?>) outer).apply(Double.valueOf(((IntFunction<Object>) inner).apply(i).toString()));
return new ComposerForIntFunction(f134);
}
default:
throw new RuntimeException(functionType + " is not recognized");
}
}
@Override
public Object getFunctionObject() {
return inner;
}
}

View File

@ -0,0 +1,91 @@
package io.virtdata.api.composers;
import io.virtdata.api.FunctionType;
import java.util.function.*;
public class ComposerForIntToDoubleFunction implements FunctionComposer<IntToDoubleFunction> {
private final IntToDoubleFunction inner;
public ComposerForIntToDoubleFunction(IntToDoubleFunction inner) {
this.inner = inner;
}
@Override
public Object getFunctionObject() {
return inner;
}
@Override
@SuppressWarnings("unchecked")
public FunctionComposer<?> andThen(Object outer) {
FunctionType functionType = FunctionType.valueOf(outer);
switch(functionType) {
case long_long:
final IntToLongFunction f1 =
(int i) ->
((LongUnaryOperator)outer).applyAsLong((int) inner.applyAsDouble(i));
return new ComposerForIntToLongFunction(f1);
case long_T:
final IntFunction<?> f2 =
(int i) ->
((LongFunction<?>)outer).apply((int) inner.applyAsDouble(i));
return new ComposerForIntFunction(f2);
case long_int:
final IntUnaryOperator f3 =
(int i) ->
((LongToIntFunction)outer).applyAsInt((int) inner.applyAsDouble(i));
return new ComposerForIntUnaryOperator(f3);
case long_double:
final IntToDoubleFunction f4 =
(int i) ->
((LongToDoubleFunction)outer).applyAsDouble((int) inner.applyAsDouble(i));
return new ComposerForIntToDoubleFunction(f4);
case int_int:
final IntUnaryOperator f5 =
(int i) ->
((IntUnaryOperator)outer).applyAsInt((int) inner.applyAsDouble(i));
return new ComposerForIntUnaryOperator(f5);
case R_T:
final IntFunction f6 =
(int i) ->
((Function<Double,?>)outer).apply(inner.applyAsDouble(i));
return new ComposerForIntFunction(f6);
case int_long:
final IntToLongFunction f7 =
(int i) ->
((IntToLongFunction)outer).applyAsLong((int) inner.applyAsDouble(i));
return new ComposerForIntToLongFunction(f7);
case int_double:
final IntToDoubleFunction f8 =
(int i) ->
((IntToDoubleFunction)outer).applyAsDouble((int) inner.applyAsDouble(i));
return new ComposerForIntToDoubleFunction(f8);
case int_T:
final IntFunction<?> f9 =
(int i) ->
((IntFunction<?>)outer).apply((int) inner.applyAsDouble(i));
return new ComposerForIntFunction(f9);
case double_double:
final IntToDoubleFunction f10 =
(int i) -> ((DoubleUnaryOperator)outer).applyAsDouble(inner.applyAsDouble(i));
return new ComposerForIntToDoubleFunction(f10);
case double_long:
final IntToLongFunction f11 =
(int i) -> ((DoubleToLongFunction)outer).applyAsLong(inner.applyAsDouble(i));
return new ComposerForIntToLongFunction(f11);
case double_int:
final IntUnaryOperator f12 =
(int i) -> ((DoubleToIntFunction)outer).applyAsInt(inner.applyAsDouble(i));
return new ComposerForIntUnaryOperator(f12);
case double_T:
final IntFunction<?> f13 =
(int i) -> ((DoubleFunction<?>)outer).apply(inner.applyAsDouble(i));
return new ComposerForIntFunction(f13);
default:
throw new RuntimeException(functionType + " is not recognized");
}
}
}

View File

@ -0,0 +1,90 @@
package io.virtdata.api.composers;
import io.virtdata.api.FunctionType;
import java.util.function.*;
public class ComposerForIntToLongFunction implements FunctionComposer<IntToLongFunction> {
private IntToLongFunction inner;
public ComposerForIntToLongFunction(IntToLongFunction inner) {
this.inner = inner;
}
@Override
public Object getFunctionObject() {
return inner;
}
@Override
@SuppressWarnings("unchecked")
public FunctionComposer andThen(Object outer) {
FunctionType functionType = FunctionType.valueOf(outer);
switch(functionType) {
case long_long:
final IntToLongFunction f1 =
((LongUnaryOperator) outer)::applyAsLong;
return new ComposerForIntToLongFunction(f1);
case long_T:
final IntFunction<?> f2 =
(int i) ->
((LongFunction<?>)outer).apply(inner.applyAsLong(i));
return new ComposerForIntFunction(f2);
case long_int:
final IntUnaryOperator f3 =
(int i) ->
((LongToIntFunction)outer).applyAsInt(inner.applyAsLong(i));
return new ComposerForIntUnaryOperator(f3);
case long_double:
final IntToDoubleFunction f4 =
(int i) -> ((LongToDoubleFunction)outer).applyAsDouble(inner.applyAsLong(i));
return new ComposerForIntToDoubleFunction(f4);
case int_int:
final IntUnaryOperator f5 =
(int i) ->
((IntUnaryOperator)outer).applyAsInt((int) inner.applyAsLong(i));
return new ComposerForIntUnaryOperator(f5);
case R_T:
final IntFunction<?> f6 =
(int i) ->
((Function<Long,?>)outer).apply(inner.applyAsLong(i));
return new ComposerForIntFunction(f6);
case int_long:
final IntToLongFunction f7 =
(int i) ->
((IntToLongFunction)outer).applyAsLong((int) inner.applyAsLong(i));
return new ComposerForIntToLongFunction(f7);
case int_double:
final IntToDoubleFunction f8 =
(int i) ->
((IntToDoubleFunction)outer).applyAsDouble((int) inner.applyAsLong(i));
return new ComposerForIntToDoubleFunction(f8);
case int_T:
final IntFunction<?> f9 =
(int i) ->
((IntFunction<?>)outer).apply((int) inner.applyAsLong(i));
return new ComposerForIntFunction(f9);
case double_double:
final IntToDoubleFunction f10 =
(int i) -> ((DoubleUnaryOperator)outer).applyAsDouble(inner.applyAsLong(i));
return new ComposerForIntToDoubleFunction(f10);
case double_long:
final IntToLongFunction f11 =
(int i) -> ((DoubleToLongFunction)outer).applyAsLong(inner.applyAsLong(i));
return new ComposerForIntToLongFunction(f11);
case double_int:
final IntUnaryOperator f12 =
(int i) -> ((DoubleToIntFunction)outer).applyAsInt(inner.applyAsLong(i));
return new ComposerForIntUnaryOperator(f12);
case double_T:
final IntFunction<?> f13 =
(int i) -> ((DoubleFunction<?>)outer).apply(inner.applyAsLong(i));
return new ComposerForIntFunction(f13);
default:
throw new RuntimeException(functionType + " is not recognized");
}
}
}

View File

@ -0,0 +1,95 @@
package io.virtdata.api.composers;
import io.virtdata.api.FunctionType;
import java.util.function.*;
public class ComposerForIntUnaryOperator implements FunctionComposer<IntUnaryOperator> {
private IntUnaryOperator inner;
public ComposerForIntUnaryOperator(IntUnaryOperator inner) {
this.inner = inner;
}
@Override
public Object getFunctionObject() {
return inner;
}
@Override
@SuppressWarnings("unchecked")
public FunctionComposer<?> andThen(Object outer) {
FunctionType functionType = FunctionType.valueOf(outer);
switch (functionType) {
case long_long:
final IntToLongFunction f1 =
(int i) ->
((LongUnaryOperator) outer).applyAsLong(inner.applyAsInt(i));
return new ComposerForIntToLongFunction(f1);
case long_T:
final IntFunction<?> f2 =
(int i) ->
((LongFunction<?>) outer).apply(inner.applyAsInt(i));
return new ComposerForIntFunction(f2);
case long_int:
final IntUnaryOperator f3 =
(int i) ->
((LongToIntFunction) outer).applyAsInt(inner.applyAsInt(i));
return new ComposerForIntUnaryOperator(f3);
case long_double:
final IntToDoubleFunction f4 =
(int i) ->
((LongToDoubleFunction) outer).applyAsDouble(inner.applyAsInt(i));
return new ComposerForIntToDoubleFunction(f4);
case R_T:
final IntFunction<?> f5 =
(int i) ->
((Function<Integer, ?>) outer).apply(inner.applyAsInt(i));
return new ComposerForIntFunction(f5);
case int_int:
final IntUnaryOperator f6 =
(int i) ->
((IntUnaryOperator) outer).applyAsInt(inner.applyAsInt(i));
return new ComposerForIntUnaryOperator(f6);
case int_long:
final IntToLongFunction f7 =
(int i) ->
((IntToLongFunction) outer).applyAsLong(inner.applyAsInt(i));
return new ComposerForIntToLongFunction(f7);
case int_double:
final IntToDoubleFunction f8 =
(int i) ->
((IntToDoubleFunction) outer).applyAsDouble(inner.applyAsInt(i));
return new ComposerForIntToDoubleFunction(f8);
case int_T:
final IntFunction<?> f9 =
(int i) ->
((IntFunction<?>)outer).apply(inner.applyAsInt(i));
return new ComposerForIntFunction(f9);
case double_double:
final IntToDoubleFunction f10 =
(int i) -> ((DoubleUnaryOperator)outer).applyAsDouble(inner.applyAsInt(i));
return new ComposerForIntToDoubleFunction(f10);
case double_long:
final IntToLongFunction f11 =
(int i) -> ((DoubleToLongFunction)outer).applyAsLong(inner.applyAsInt(i));
return new ComposerForIntToLongFunction(f11);
case double_int:
final IntUnaryOperator f12 =
(int i) -> ((DoubleToIntFunction)outer).applyAsInt(inner.applyAsInt(i));
return new ComposerForIntUnaryOperator(f12);
case double_T:
final IntFunction<?> f13 =
(int i) -> ((DoubleFunction<?>)outer).apply(inner.applyAsInt(i));
return new ComposerForIntFunction(f13);
default:
throw new RuntimeException(functionType + " is not recognized");
}
}
}

View File

@ -0,0 +1,268 @@
package io.virtdata.api.composers;
import io.virtdata.api.FunctionType;
import io.virtdata.api.ValueType;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.util.function.*;
public class ComposerForLongFunction implements FunctionComposer<LongFunction<?>> {
private final static Logger logger = LogManager.getLogger(ComposerForLongFunction.class);private final LongFunction<?> inner;
public ComposerForLongFunction(LongFunction<?> inner) {
this.inner = inner;
}
@Override
public Object getFunctionObject() {
return inner;
}
@Override
@SuppressWarnings("unchecked")
public FunctionComposer andThen(Object outer) {
FunctionType functionType = FunctionType.valueOf(outer);
Object outv = this.inner.apply(1L);
ValueType itype = ValueType.valueOfAssignableClass(outv.getClass());
switch (functionType) {
case long_long:
switch (itype) {
case LONG:
final LongUnaryOperator f11 =
(long l) -> ((LongUnaryOperator) outer).applyAsLong(((LongFunction<Long>) inner).apply(l));
return new ComposerForLongUnaryOperator(f11);
case DOUBLE:
final LongUnaryOperator f12 =
(long l) -> ((LongUnaryOperator) outer).applyAsLong(((LongFunction<Double>) inner).apply(l).longValue());
return new ComposerForLongUnaryOperator(f12);
case INT:
final LongUnaryOperator f13 =
(long l) -> ((LongUnaryOperator) outer).applyAsLong(((LongFunction<Integer>) inner).apply(l));
return new ComposerForLongUnaryOperator(f13);
default:
final LongUnaryOperator f14 =
(long l) -> ((LongUnaryOperator) outer).applyAsLong(Double.valueOf(((LongFunction<Object>) inner).apply(l).toString()).longValue());
return new ComposerForLongUnaryOperator(f14);
}
case long_T:
switch (itype) {
case LONG:
final LongFunction<?> f21 =
(long l) -> ((LongFunction<?>) outer).apply(((LongFunction<Long>) inner).apply(l));
return new ComposerForLongFunction(f21);
case DOUBLE:
final LongFunction<?> f22 =
(long l) -> ((LongFunction<?>) outer).apply(((LongFunction<Double>) inner).apply(l).longValue());
return new ComposerForLongFunction(f22);
case INT:
final LongFunction<?> f23 =
(long l) -> ((LongFunction<?>) outer).apply(((LongFunction<Integer>) inner).apply(l));
return new ComposerForLongFunction(f23);
default:
final LongFunction<?> f24 =
(long l) -> ((LongFunction<?>) outer).apply(Double.valueOf(((LongFunction<Object>) inner).apply(l).toString()).longValue());
return new ComposerForLongFunction(f24);
}
case long_int:
switch (itype) {
case LONG:
final LongToIntFunction f31 =
(long l) -> ((LongToIntFunction) outer).applyAsInt(((LongFunction<Long>) inner).apply(l));
return new ComposerForLongToIntFunction(f31);
case DOUBLE:
final LongToIntFunction f32 =
(long l) -> ((LongToIntFunction) outer).applyAsInt(((LongFunction<Double>) inner).apply(l).longValue());
return new ComposerForLongToIntFunction(f32);
case INT:
final LongToIntFunction f33 =
(long l) -> ((LongToIntFunction) outer).applyAsInt(((LongFunction<Integer>) inner).apply(l));
return new ComposerForLongToIntFunction(f33);
default:
final LongToIntFunction f34 =
(long l) -> ((LongToIntFunction) outer).applyAsInt(Double.valueOf(((LongFunction<Object>) inner).apply(l).toString()).longValue());
return new ComposerForLongToIntFunction(f34);
}
case long_double:
switch (itype) {
case LONG:
final LongToDoubleFunction f41 =
(long l) -> ((LongToDoubleFunction) outer).applyAsDouble(((LongFunction<Long>) inner).apply(l));
return new ComposerForLongToDoubleFunction(f41);
case DOUBLE:
final LongToDoubleFunction f42 =
(long l) -> ((LongToDoubleFunction) outer).applyAsDouble(((LongFunction<Double>) inner).apply(l).longValue());
return new ComposerForLongToDoubleFunction(f42);
case INT:
final LongToDoubleFunction f43 =
(long l) -> ((LongToDoubleFunction) outer).applyAsDouble(((LongFunction<Integer>) inner).apply(l));
return new ComposerForLongToDoubleFunction(f43);
default:
final LongToDoubleFunction f44 =
(long l) -> ((LongToDoubleFunction) outer).applyAsDouble(Double.valueOf(((LongFunction<Object>) inner).apply(l).toString()).longValue());
return new ComposerForLongToDoubleFunction(f44);
}
case R_T:
final LongFunction<?> f5 =
(long l) -> ((Function<Object, Object>) outer).apply(((LongFunction<Object>) inner).apply(l));
return new ComposerForLongFunction(f5);
case int_int:
switch (itype) {
case LONG:
final LongToIntFunction f61 = (long l) ->
((IntUnaryOperator) outer).applyAsInt(((LongFunction<Long>) inner).apply(l).intValue());
return new ComposerForLongToIntFunction(f61);
case INT:
final LongToIntFunction f62 = (long l) ->
((IntUnaryOperator) outer).applyAsInt(((LongFunction<Integer>) inner).apply(l));
return new ComposerForLongToIntFunction(f62);
case DOUBLE:
final LongToIntFunction f64 = (long l) ->
((IntUnaryOperator) outer).applyAsInt(((LongFunction<Double>) inner).apply(l).intValue());
return new ComposerForLongToIntFunction(f64);
default:
final LongToIntFunction f63 = (long l) ->
((IntUnaryOperator) outer).applyAsInt(Double.valueOf(((LongFunction<Object>) inner).apply(l).toString()).intValue());
return new ComposerForLongToIntFunction(f63);
}
case int_long:
switch (itype) {
case LONG:
final LongUnaryOperator f71 = (long l) ->
((IntToLongFunction) outer).applyAsLong(((LongFunction<Long>) inner).apply(l).intValue());
return new ComposerForLongUnaryOperator(f71);
case INT:
final LongUnaryOperator f72 = (long l) ->
((IntToLongFunction) outer).applyAsLong(((LongFunction<Integer>) inner).apply(l));
return new ComposerForLongUnaryOperator(f72);
case DOUBLE:
final LongUnaryOperator f73 = (long l) ->
((IntToLongFunction) outer).applyAsLong(((LongFunction<Double>) inner).apply(l).intValue());
return new ComposerForLongUnaryOperator(f73);
default:
final LongUnaryOperator f74 = (long l) ->
((IntToLongFunction) outer).applyAsLong(Double.valueOf(((LongFunction<Object>) inner).apply(l).toString()).intValue());
return new ComposerForLongUnaryOperator(f74);
}
case int_double:
switch (itype) {
case LONG:
final LongToDoubleFunction f81 =
(long l) -> ((IntToDoubleFunction) outer).applyAsDouble(((LongFunction<Long>) inner).apply(l).intValue());
return new ComposerForLongToDoubleFunction(f81);
case DOUBLE:
final LongToDoubleFunction f83 =
(long l) -> ((IntToDoubleFunction) outer).applyAsDouble(((LongFunction<Double>) inner).apply(l).intValue());
return new ComposerForLongToDoubleFunction(f83);
case INT:
final LongToDoubleFunction f82 =
(long l) -> ((IntToDoubleFunction) outer).applyAsDouble(((LongFunction<Integer>) inner).apply(l));
return new ComposerForLongToDoubleFunction(f82);
default:
final LongToDoubleFunction f84 =
(long l) -> ((IntToDoubleFunction) outer).applyAsDouble(Double.valueOf(((LongFunction<Object>) inner).apply(l).toString()).intValue());
return new ComposerForLongToDoubleFunction(f84);
}
case int_T:
switch (itype) {
case LONG:
final LongFunction<?> f91 =
(long l) -> ((IntFunction<Object>) outer).apply(((LongFunction<Long>) inner).apply(l).intValue());
return new ComposerForLongFunction(f91);
case DOUBLE:
final LongFunction<?> f92 =
(long l) -> ((IntFunction<Object>) outer).apply(((LongFunction<Double>) inner).apply(l).intValue());
return new ComposerForLongFunction(f92);
case INT:
final LongFunction<?> f93 =
(long l) -> ((IntFunction<Object>) outer).apply(((LongFunction<Integer>) inner).apply(l));
return new ComposerForLongFunction(f93);
default:
final LongFunction<?> f94 =
(long l) -> ((IntFunction<Object>) outer).apply(Double.valueOf(((LongFunction<Object>) inner).apply(l).toString()).intValue());
return new ComposerForLongFunction(f94);
}
case double_double:
switch (itype) {
case LONG:
final LongToDoubleFunction f101 =
(long l) -> ((DoubleUnaryOperator) outer).applyAsDouble(((LongFunction<Long>) inner).apply(l));
return new ComposerForLongToDoubleFunction(f101);
case DOUBLE:
final LongToDoubleFunction f102 =
(long l) -> ((DoubleUnaryOperator) outer).applyAsDouble(((LongFunction<Double>) inner).apply(l));
return new ComposerForLongToDoubleFunction(f102);
case INT:
final LongToDoubleFunction f103 =
(long l) -> ((DoubleUnaryOperator) outer).applyAsDouble(((LongFunction<Integer>) inner).apply(l));
return new ComposerForLongToDoubleFunction(f103);
default:
final LongToDoubleFunction f104 =
(long l) -> ((DoubleUnaryOperator) outer).applyAsDouble(Double.valueOf(((LongFunction<Object>) inner).apply(l).toString()));
return new ComposerForLongToDoubleFunction(f104);
}
case double_long:
switch (itype) {
case LONG:
final LongUnaryOperator f111 =
(long l) -> ((DoubleToLongFunction) outer).applyAsLong(((LongFunction<Long>) inner).apply(l));
return new ComposerForLongUnaryOperator(f111);
case INT:
final LongUnaryOperator f112 =
(long l) -> ((DoubleToLongFunction) outer).applyAsLong(((LongFunction<Integer>) inner).apply(l));
return new ComposerForLongUnaryOperator(f112);
case DOUBLE:
final LongUnaryOperator f113 =
(long l) -> ((DoubleToLongFunction) outer).applyAsLong(((LongFunction<Double>) inner).apply(l));
return new ComposerForLongUnaryOperator(f113);
default:
final LongUnaryOperator f114 =
(long l) -> ((DoubleToLongFunction) outer).applyAsLong(Double.valueOf(((LongFunction<Object>) inner).apply(l).toString()));
return new ComposerForLongUnaryOperator(f114);
}
case double_int:
switch (itype) {
case LONG:
final LongToIntFunction f121 =
(long l) -> ((DoubleToIntFunction) outer).applyAsInt(((LongFunction<Long>) inner).apply(l));
return new ComposerForLongToIntFunction(f121);
case INT:
final LongToIntFunction f122 =
(long l) -> ((DoubleToIntFunction) outer).applyAsInt(((LongFunction<Integer>) inner).apply(l));
return new ComposerForLongToIntFunction(f122);
case DOUBLE:
final LongToIntFunction f123 =
(long l) -> ((DoubleToIntFunction) outer).applyAsInt(((LongFunction<Double>) inner).apply(l));
return new ComposerForLongToIntFunction(f123);
default:
final LongToIntFunction f124 =
(long l) -> ((DoubleToIntFunction) outer).applyAsInt(Double.valueOf(((LongFunction<Object>) inner).apply(l).toString()));
return new ComposerForLongToIntFunction(f124);
}
case double_T:
switch (itype) {
case LONG:
final LongFunction<Object> f131 =
(long l) -> ((DoubleFunction<Object>) outer).apply(((LongFunction<Long>) inner).apply(l));
return new ComposerForLongFunction(f131);
case DOUBLE:
final LongFunction<Object> f133 =
(long l) -> ((DoubleFunction<Object>) outer).apply(((LongFunction<Double>) inner).apply(l));
return new ComposerForLongFunction(f133);
case INT:
final LongFunction<Object> f132 =
(long l) -> ((DoubleFunction<Object>) outer).apply(((LongFunction<Integer>) inner).apply(l));
return new ComposerForLongFunction(f132);
default:
final LongFunction<Object> f134 =
(long l) -> ((DoubleFunction<Object>) outer).apply(Double.valueOf(((LongFunction<Object>) inner).apply(l).toString()));
return new ComposerForLongFunction(f134);
}
default:
throw new RuntimeException(functionType + " is not recognized");
}
}
}

View File

@ -0,0 +1,86 @@
package io.virtdata.api.composers;
import io.virtdata.api.FunctionType;
import java.util.function.*;
public class ComposerForLongToDoubleFunction implements FunctionComposer<LongToDoubleFunction> {
private final LongToDoubleFunction inner;
public ComposerForLongToDoubleFunction(LongToDoubleFunction inner) {
this.inner = inner;
}
@Override
public Object getFunctionObject() {
return inner;
}
@Override
@SuppressWarnings("unchecked")
public FunctionComposer andThen(Object outer) {
FunctionType functionType = FunctionType.valueOf(outer);
switch (functionType) {
case long_long:
final LongUnaryOperator f1 =
(long l) -> ((LongUnaryOperator) outer).applyAsLong((long) inner.applyAsDouble(l));
return new ComposerForLongUnaryOperator(f1);
case long_T:
final LongFunction<?> f2 =
(long l) -> ((LongFunction<?>) outer).apply((long) inner.applyAsDouble(l));
return new ComposerForLongFunction(f2);
case long_int:
final LongToIntFunction f3 =
(long l) -> ((LongToIntFunction) outer).applyAsInt((int) inner.applyAsDouble(l));
return new ComposerForLongToIntFunction(f3);
case long_double:
final LongToDoubleFunction f4 =
(long l) -> ((LongToDoubleFunction) outer).applyAsDouble((long) inner.applyAsDouble(l));
return new ComposerForLongToDoubleFunction(f4);
case R_T:
final LongFunction<?> f5 =
(long l) -> ((Function<Double,?>) outer).apply(inner.applyAsDouble(l));
return new ComposerForLongFunction(f5);
case int_int:
final LongToIntFunction f6 =
(long l) ->
((IntUnaryOperator) outer).applyAsInt((int) inner.applyAsDouble(l));
return new ComposerForLongToIntFunction(f6);
case int_long:
final LongUnaryOperator f7 =
(long l) -> ((IntToLongFunction) outer).applyAsLong((int) inner.applyAsDouble(l));
return new ComposerForLongUnaryOperator(f7);
case int_double:
final LongToDoubleFunction f8 =
(long l) ->
((IntToDoubleFunction) outer).applyAsDouble((int) inner.applyAsDouble(l));
return new ComposerForLongToDoubleFunction(f8);
case int_T:
final LongFunction<?> f9 =
(long l) ->
((IntFunction<?>) outer).apply((int) inner.applyAsDouble(l));
return new ComposerForLongFunction(f9);
case double_double:
final LongToDoubleFunction f10 =
(long l) -> ((DoubleUnaryOperator)outer).applyAsDouble(inner.applyAsDouble(l));
return new ComposerForLongToDoubleFunction(f10);
case double_long:
final LongUnaryOperator f11 =
(long l) -> ((DoubleToLongFunction)outer).applyAsLong(inner.applyAsDouble(l));
return new ComposerForLongUnaryOperator(f11);
case double_int:
final LongToIntFunction f12 =
(long l) -> ((DoubleToIntFunction)outer).applyAsInt(inner.applyAsDouble(l));
return new ComposerForLongToIntFunction(f12);
case double_T:
final LongFunction<?> f13 =
(long l) -> ((DoubleFunction<?>)outer).apply(inner.applyAsDouble(l));
return new ComposerForLongFunction(f13);
default:
throw new RuntimeException(functionType + " is not recognized");
}
}
}

View File

@ -0,0 +1,92 @@
package io.virtdata.api.composers;
import io.virtdata.api.FunctionType;
import java.util.function.*;
public class ComposerForLongToIntFunction implements FunctionComposer<LongToIntFunction> {
private final LongToIntFunction inner;
public ComposerForLongToIntFunction(LongToIntFunction inner) {
this.inner = inner;
}
@Override
public Object getFunctionObject() {
return inner;
}
@Override
public FunctionComposer andThen(Object outer) {
FunctionType outerFunctionType = FunctionType.valueOf(outer);
switch (outerFunctionType) {
case long_long:
final LongUnaryOperator f1 =
(long l) ->
((LongUnaryOperator) outer).applyAsLong(inner.applyAsInt(l));
return new ComposerForLongUnaryOperator(f1);
case long_T:
final LongFunction<?> f2 =
(long l) ->
((LongFunction<?>) outer).apply(inner.applyAsInt(l));
return new ComposerForLongFunction(f2);
case long_int:
final LongToIntFunction f3 =
(long l) ->
((LongToIntFunction) outer).applyAsInt((inner.applyAsInt(l)));
return new ComposerForLongToIntFunction(f3);
case long_double:
final LongToDoubleFunction f4 =
(long l) ->
((LongToDoubleFunction) outer).applyAsDouble(inner.applyAsInt(l));
return new ComposerForLongToDoubleFunction(f4);
case R_T:
final LongFunction<?> f5 =
(long l) ->
((Function<Integer,?>) outer).apply((int) inner.applyAsInt(l));
return new ComposerForLongFunction(f5);
case int_int:
final LongToIntFunction f6 =
(long l) ->
((IntUnaryOperator) outer).applyAsInt(inner.applyAsInt(l));
return new ComposerForLongToIntFunction(f6);
case int_long:
final LongUnaryOperator f7 =
(long l) ->
((IntToLongFunction) outer).applyAsLong(inner.applyAsInt(l));
return new ComposerForLongUnaryOperator(f7);
case int_double:
final LongToDoubleFunction f8 =
(long l) ->
((IntToDoubleFunction) outer).applyAsDouble(inner.applyAsInt(l));
return new ComposerForLongToDoubleFunction(f8);
case int_T:
final LongFunction<?> f9 =
(long l) ->
((IntFunction<?>)outer).apply(inner.applyAsInt(l));
return new ComposerForLongFunction(f9);
case double_double:
final LongToDoubleFunction f10 =
(long l) -> ((DoubleUnaryOperator)outer).applyAsDouble(inner.applyAsInt(l));
return new ComposerForLongToDoubleFunction(f10);
case double_long:
final LongUnaryOperator f11 =
(long l) -> ((DoubleToLongFunction)outer).applyAsLong(inner.applyAsInt(l));
return new ComposerForLongUnaryOperator(f11);
case double_int:
final LongToIntFunction f12 =
(long l) -> ((DoubleToIntFunction)outer).applyAsInt(inner.applyAsInt(l));
return new ComposerForLongToIntFunction(f12);
case double_T:
final LongFunction<?> f13 =
(long l) -> ((DoubleFunction<?>)outer).apply(inner.applyAsInt(l));
return new ComposerForLongFunction(f13);
default:
throw new RuntimeException(outerFunctionType + " is not recognized");
}
}
}

View File

@ -0,0 +1,88 @@
package io.virtdata.api.composers;
import io.virtdata.api.FunctionType;
import java.util.function.*;
public class ComposerForLongUnaryOperator implements FunctionComposer<LongUnaryOperator> {
private LongUnaryOperator inner;
public ComposerForLongUnaryOperator(LongUnaryOperator inner) {
this.inner = inner;
}
@Override
public Object getFunctionObject() {
return inner;
}
@Override
@SuppressWarnings("unchecked")
public FunctionComposer<?> andThen(Object outer) {
FunctionType functionType = FunctionType.valueOf(outer);
switch (functionType) {
case long_long:
final LongUnaryOperator f1 =
(long l) -> ((LongUnaryOperator) outer).applyAsLong(inner.applyAsLong(l));
return new ComposerForLongUnaryOperator(f1);
case long_T:
final LongFunction<?> f2 =
(long l) -> ((LongFunction<?>)outer).apply(inner.applyAsLong(l));
return new ComposerForLongFunction(f2);
case long_int:
final LongToIntFunction f3 =
(long l) -> ((LongToIntFunction)outer).applyAsInt(inner.applyAsLong(l));
return new ComposerForLongToIntFunction(f3);
case long_double:
final LongToDoubleFunction f4 =
(long l) -> ((LongToDoubleFunction)outer).applyAsDouble(inner.applyAsLong(l));
return new ComposerForLongToDoubleFunction(f4);
case R_T:
final LongFunction<?> f5 =
(long l) -> ((Function<Long,?>)outer).apply(inner.applyAsLong(l));
return new ComposerForLongFunction(f5);
case int_int:
final LongToIntFunction f6 =
(long l) -> ((IntUnaryOperator)outer).applyAsInt((int) inner.applyAsLong(l));
return new ComposerForLongToIntFunction(f6);
case int_long:
final LongUnaryOperator f7 =
(long l) -> ((IntToLongFunction)outer).applyAsLong((int) inner.applyAsLong(l));
return new ComposerForLongUnaryOperator(f7);
case int_double:
final LongToDoubleFunction f8 =
(long l) -> ((IntToDoubleFunction)outer).applyAsDouble((int) inner.applyAsLong(l));
return new ComposerForLongToDoubleFunction(f8);
case int_T:
final LongFunction<?> f9 =
(long l) ->
((IntFunction<?>)outer).apply((int) inner.applyAsLong(l));
return new ComposerForLongFunction(f9);
case double_double:
final LongToDoubleFunction f10 =
(long l) -> ((DoubleUnaryOperator)outer).applyAsDouble(inner.applyAsLong(l));
return new ComposerForLongToDoubleFunction(f10);
case double_long:
final LongUnaryOperator f11 =
(long l) -> ((DoubleToLongFunction)outer).applyAsLong(inner.applyAsLong(l));
return new ComposerForLongUnaryOperator(f11);
case double_int:
final LongToIntFunction f12 =
(long l) -> ((DoubleToIntFunction)outer).applyAsInt(inner.applyAsLong(l));
return new ComposerForLongToIntFunction(f12);
case double_T:
final LongFunction<?> f13 =
(long l) -> ((DoubleFunction<?>)outer).apply(inner.applyAsLong(l));
return new ComposerForLongFunction(f13);
default:
throw new RuntimeException(functionType + " is not recognized");
}
}
}

View File

@ -0,0 +1,84 @@
package io.virtdata.api.composers;
import io.virtdata.api.FunctionType;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.util.function.*;
public class FunctionAssembly implements FunctionComposer {
private final static Logger logger = LogManager.getLogger(FunctionAssembly.class);private FunctionComposer<?> composer = null;
@Override
public Object getFunctionObject() {
if (composer != null) {
return composer.getFunctionObject();
} else {
throw new RuntimeException("No function have been passed for assembly.");
}
}
@Override
public FunctionComposer andThen(Object outer) {
try {
if (composer != null) {
composer = composer.andThen(outer);
} else {
composer = andThenInitial(outer);
}
return composer;
} catch (Exception e) {
logger.error("Error while composing functions:\n");
if (composer != null) {
logger.error("composer: class:" + composer.getClass().getSimpleName() + ", toString:" + composer.toString());
}
logger.error("outer: class:" + outer.getClass() + ", toString:" + outer.toString());
throw e;
}
}
private FunctionComposer<?> andThenInitial(Object o) {
try {
FunctionType functionType = FunctionType.valueOf(o);
switch (functionType) {
case long_long:
return new ComposerForLongUnaryOperator((LongUnaryOperator) o);
case long_int:
return new ComposerForLongToIntFunction((LongToIntFunction) o);
case long_double:
return new ComposerForLongToDoubleFunction((LongToDoubleFunction) o);
case long_T:
return new ComposerForLongFunction((LongFunction<?>) o);
case int_int:
return new ComposerForIntUnaryOperator((IntUnaryOperator) o);
case int_long:
return new ComposerForIntToLongFunction((IntToLongFunction) o);
case int_double:
return new ComposerForIntToDoubleFunction((IntToDoubleFunction) o);
case int_T:
return new ComposerForIntFunction((IntFunction<?>) o);
case double_double:
return new ComposerForDoubleUnaryOperator((DoubleUnaryOperator) o);
case double_long:
return new ComposerForDoubleToLongFunction((DoubleToLongFunction) o);
case double_int:
return new ComposerForDoubleToIntFunction((DoubleToIntFunction) o);
case double_T:
return new ComposerForDoubleFunction((DoubleFunction<?>) o);
case R_T:
return new ComposerForFunction((Function<?, ?>) o);
default:
throw new RuntimeException("Unrecognized function type:" + functionType);
}
} catch (Exception e) {
logger.error("Error while setting up initial composer state for function class:" +
o.getClass().getSimpleName() + ", toString:" + o.toString());
throw e;
}
}
@Override
public String toString() {
return "composer:" + this.composer;
}
}

View File

@ -0,0 +1,36 @@
package io.virtdata.api.composers;
import io.virtdata.annotations.ThreadSafeMapper;
import io.virtdata.api.DataMapper;
import io.virtdata.core.DataMapperFunctionMapper;
import io.virtdata.core.ResolvedFunction;
public interface FunctionComposer<T> {
Object getFunctionObject();
FunctionComposer andThen(Object outer);
default ResolvedFunction getResolvedFunction() {
return new ResolvedFunction(
getFunctionObject(),
getFunctionObject().getClass().getAnnotation(ThreadSafeMapper.class) != null,
null, null,
null, null
);
}
default ResolvedFunction getResolvedFunction(boolean isThreadSafe) {
return new ResolvedFunction(
getFunctionObject(),
isThreadSafe,
null, null,
null, null
);
}
default <R> DataMapper<R> getDataMapper() {
return DataMapperFunctionMapper.map(getFunctionObject());
}
}

View File

@ -0,0 +1,8 @@
package io.virtdata.api.config;
import java.util.Map;
public interface ConfigAware {
void applyConfig(Map<String,?> element);
ConfigModel getConfigModel();
}

View File

@ -0,0 +1,17 @@
package io.virtdata.api.config;
import java.util.List;
public interface ConfigModel {
List<Element> getElements();
public static class Element {
public final String name;
public final Class<?> type;
public Element(String name, Class<?> type) {
this.name = name;
this.type =type;
}
}
}

View File

@ -0,0 +1,30 @@
package io.virtdata.api.config;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
public class MutableConfigModel implements ConfigModel {
private final List<ConfigModel.Element> elements = new ArrayList<>();
public MutableConfigModel() {}
public MutableConfigModel add(String name, Class<?> clazz) {
add(new ConfigModel.Element(name, clazz));
return this;
}
private void add(ConfigModel.Element element) {
this.elements.add(element);
}
public ConfigModel asReadOnly() {
return this;
}
@Override
public List<Element> getElements() {
return Collections.unmodifiableList(elements);
}
}

View File

@ -0,0 +1,354 @@
/*
*
* Copyright 2015 Jonathan Shook
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package io.virtdata.core;
//
import io.virtdata.api.DataMapper;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.util.*;
/**
* Maps a template with named bind points and specifiers onto a set of data
* mapping function instances. Allows for streamlined calling of mapper functions
* as a set.
* <p>There are several ways to get generated data via this class. You must always
* provide a base input value. Fields can be accessed by parameter position or name.
* In some cases, you can provide an iterator stride
* in order to get data in bulk. In other cases, you can have setters called
* directly on your provided objects. See the detailed method docs for more information.</p>
*/
public class Bindings {
private final static Logger logger = LogManager.getLogger(Bindings.class);private BindingsTemplate template;
private List<DataMapper<?>> dataMappers = new ArrayList<DataMapper<?>>();
private ThreadLocal<Map<String, DataMapper<?>>> nameCache;
public Bindings(BindingsTemplate template, List<DataMapper<?>> dataMappers) {
this.template = template;
this.dataMappers = dataMappers;
nameCache = ThreadLocal.withInitial(() ->
new HashMap<String, DataMapper<?>>() {{
for (int i = 0; i < template.getBindPointNames().size(); i++) {
put(template.getBindPointNames().get(i), dataMappers.get(i));
}
}});
}
public String toString() {
return template.toString() + dataMappers;
}
/**
* Get a value from each data mapper in the bindings list
*
* @param input The long value which the bound data mappers will use as in input
* @return An array of objects, the values yielded from each data mapper in the bindings list
*/
public Object[] getAll(long input) {
Object[] values = new Object[dataMappers.size()];
int offset = 0;
for (DataMapper dataMapper : dataMappers) {
values[offset++] = dataMapper.get(input);
}
return values;
}
/**
* @return {@link BindingsTemplate} associated with this set of bindings
*/
public BindingsTemplate getTemplate() {
return this.template;
}
/**
* @param input The input value for which the values should be generated.
* @return {@link Map} of {@link String} to {@link Object}
*/
public Map<String, Object> getAllMap(long input) {
Map<String, Object> values = new HashMap<>();
setMap(values, input);
return values;
}
/**
* Generate a list of maps over a range of inputs.
* <p>For example, calling getIteratedMaps(5,3) with bindings named
* alpha and gamma might produce something like:
* <ol start="0">
* <li>
* <ul>
* <li>alpha -&gt; val1</li>
* <li>gamma -&gt; val2</li>
* </ul>
* </li>
* <li>
* <ul>
* <li>alpha -&gt; val3</li>
* <li>gamma -&gt; val4</li>
* </ul>
* </li>
* <li>
* <ul>
* <li>alpha -&gt; val5</li>
* <li>gamma -&gt; val6</li>
* </ul>
* </li>
* </ol>
*
* @param input The base value for which the values should be generated.
* @param count The number of iterations, starting at input, to be generated
* @return {@link List} of {@link Map} of {@link String} to {@link Object}
*/
public List<Map<String, Object>> getIteratedMaps(long input, int count) {
List<Map<String, Object>> listOfMaps = new ArrayList<>(count);
for (int i = 0; i < count; i++) {
Map<String, Object> suffixedMap = new HashMap<>();
setMap(suffixedMap, input + i);
listOfMaps.add(suffixedMap);
}
return listOfMaps;
}
/**
* Generate a map containing the results from multiple iterations, suffixing
* the keys in the map with the iterations from 0 to count-1.
* <p>For example, calling getIteratedSuffixMap(5, 3) with generators named
* alpha and gamma might yield results like
* <ul>
* <li>alpha0 -&gt; val1</li>
* <li>gamma0 -&gt; val2</li>
* <li>alpha1 -&gt; val3</li>
* <li>gamma1 -&gt; val4</li>
* <li>alpha2 -&gt; val5</li>
* <li>gamma2 -&gt; val6</li>
* </ul>
*
* @param input The base input value for which the values should be generated
* @param count The count of maps that should be added to the final map
* @return {@link Map} of {@link String} to {@link Object}
*/
public Map<String, Object> getIteratedSuffixMap(long input, int count) {
Map<String, Object> suffixedMap = new LinkedHashMap<>(count * this.dataMappers.size());
setIteratedSuffixMap(suffixedMap, input, count);
return suffixedMap;
}
/**
* This is a version of the {@link #setIteratedSuffixMap(Map, long, int, String[])} which creates
* a new map for each call.
* @param input The base input value for which the values should be generated
* @param count The count of maps that should be added to the final map
* @param fieldNames The field names which are used to look up the functions in the binding
* @return A newly created map with the generated names and values.
*/
public Map<String,Object> getIteratedSuffixMap(long input, int count, String... fieldNames) {
Map<String, Object> suffixedMap = new LinkedHashMap<>(count * fieldNames.length);
setIteratedSuffixMap(suffixedMap, input, count, fieldNames);
return suffixedMap;
}
/**
* Populate a map of values with a two-dimensional set of generated key and value names. This is a basic
* traversal over all the provided field names and a range of input values from input to input+count.
* The key names for the map are created by adding a numeric suffix to the field name.
*
* For example, with field names aleph and gamma, with input 53 and count 2, the key names will
* be created as aleph0, gamma0, aleph1, gamma1, and the input values which will be used to
* create the generated values for these keys will be 53, 53, and 54, 54, respectively.
*
* Symbolically, this does the same as the sketch below:
*
* <ol>
* <li>map{aleph0}=funcFor("aleph")(53)</li>
* <li>map{gamma0}=funcFor("gamma")(53)</li>
* <li>map{aleph1}=funcFor("aleph")(54)</li>
* <li>map{gamma1}=funcFor("gamma")(54)</li>
* </ol>
*
* @param suffixedMap A donor map which is to be populated. The values do not clear the map, but merely overwrite
* values of the same name.
* @param input The base input value for which the values should be generated
* @param count The count of maps that should be added to the final map
* @param fieldNames The field names which are used to look up the functions in the binding
*/
private void setIteratedSuffixMap(Map<String, Object> suffixedMap, long input, int count, String[] fieldNames) {
for (int i = 0; i < count; i++) {
for (String f : fieldNames) {
suffixedMap.put(f+i,get(f,input+i));
}
}
}
/**
* Get a value for the data mapper in slot i
*
* @param i the data mapper slot, 0-indexed
* @param input the long input value which the bound data mapper will use as input
* @return a single object, the value yielded from the indexed data mapper in the bindings list
*/
public Object get(int i, long input) {
return dataMappers.get(i).get(input);
}
/**
* Get a value for the cached mapper name, using the name to mapper index cache.
* @param name The field name in the data mapper
* @param input the long input value which the bound data mapper will use as an input
* @return a single object, the value yielded from the named and indexed data mapper in the bindings list.
*/
public Object get(String name, long input) {
DataMapper<?> dataMapper = nameCache.get().get(name);
return dataMapper.get(input);
}
/**
* Generate all values in the bindings template, and set each of them in
* the map according to their bind point name.
*
* @param donorMap - a user-provided Map&lt;String,Object&gt;
* @param cycle - the cycle for which to generate the values
*/
public void setMap(Map<String, Object> donorMap, long cycle) {
Object[] all = getAll(cycle);
for (int i = 0; i < all.length; i++) {
donorMap.put(template.getBindPointNames().get(i), all[i]);
}
}
/**
* Set the values in a provided map, with bound names suffixed with
* some value. No non-overlapping keys in the map will be affected.
*
* @param donorMap an existing {@link Map} of {@link String} to {@link Object}
* @param cycle the cycle for which values should be generated
* @param suffix a string suffix to be appended to any map keys
*/
public void setSuffixedMap(Map<String, Object> donorMap, long cycle, String suffix) {
Object[] all = getAll(cycle);
for (int i = 0; i < all.length; i++) {
donorMap.put(template.getBindPointNames().get(i) + suffix, all[i]);
}
}
/**
* Set the values in a provided map, with the bound names suffixed with
* an internal iteration value.
*
* @param donorMap an existing {@link Map} of {@link String} to {@link Object}
* @param input the base cycle for which values should be generated
* @param count the number of iterations to to generate values and keynames for
*/
public void setIteratedSuffixMap(Map<String, Object> donorMap, long input, long count) {
for (int i = 0; i < count; i++) {
setSuffixedMap(donorMap, input + i, String.valueOf(i));
}
}
/**
* Generate only the values which have matching keys in the provided
* map according to their bind point names, and assign them to the
* map under that name. It is an error for a key name to be defined
* in the map for which there is no mapper.
*
* @param donorMap - a user-provided Map&lt;String,Object&gt;
* @param input - the input for which to generate the values
*/
public void updateMap(Map<String, Object> donorMap, long input) {
for (String s : donorMap.keySet()) {
donorMap.put(s, get(s, input));
}
}
/**
* Generate only the values named in fieldNames, and then call the user-provided
* field setter for each name and object generated.
*
* @param fieldSetter user-provided object that implements {@link FieldSetter}.
* @param input the input for which to generate values
* @param fieldName A varargs list of field names, or a String[] of names to set
*/
public void setNamedFields(FieldSetter fieldSetter, long input, String... fieldName) {
for (String s : fieldName) {
fieldSetter.setField(s, get(s, input));
}
}
/**
* Generate all the values named in the bindings for a number of iterations, calling
* a user-provided field setter for each name and object generated, with the
* iteration number appended to the fieldName, but only for the named bindings.
*
* @param fieldSetter user-provided object that implements {@link FieldSetter}
* @param input the base input value for which the objects should be generated
* @param count the number of iterations to generate values and names for
* @param fieldName the field names for which to generate values and names
*/
public void setNamedFieldsIterated(FieldSetter fieldSetter, long input, int count, String... fieldName) {
for (int i = 0; i < count; i++) {
for (String s : fieldName) {
fieldSetter.setField(s + i, get(s, input + i));
}
}
}
/**
* Generate all the values named in the bind point names, then call the user-provided
* field setter for each name and object generated.
*
* @param fieldSetter user-provided object that implements {@link FieldSetter}
* @param input the input for which to generate values
*/
public void setAllFields(FieldSetter fieldSetter, long input) {
Object[] all = getAll(input);
for (int i = 0; i < all.length; i++) {
fieldSetter.setField(template.getBindPointNames().get(i), all[i]);
}
}
/**
* Generate all the values named in the bindings for a number of iterations, calling
* a user-provided field setter for each name and object generated, with the
* iteration number appended to the fieldName.
*
* @param fieldSetter user-provided object that implements {@link FieldSetter}
* @param input the base input value for which the objects should be generated
* @param count the number of iterations to generate values and names for
*/
public void setAllFieldsIterated(FieldSetter fieldSetter, long input, int count) {
for (int i = 0; i < count; i++) {
Object[] all = getAll(input+i);
for (int j = 0; j < all.length; j++) {
fieldSetter.setField(template.getBindPointNames().get(i) + i, all[i]);
}
}
}
public LazyValuesMap getLazyMap(long input) {
return new LazyValuesMap(this, input);
}
public static interface FieldSetter {
void setField(String name, Object value);
}
}

View File

@ -0,0 +1,46 @@
/*
* Copyright 2017 jshook
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.virtdata.core;
import java.util.HashMap;
import java.util.Map;
public class BindingsCache {
private final Bindings bindings;
private Map<String,Object> valuesCache = new HashMap<>();
public BindingsCache(Bindings bindings) {
this.bindings = bindings;
}
public Object getField(String fieldName, long input) {
Object value = valuesCache.computeIfAbsent(fieldName, k -> getFieldValue(fieldName, input));
return value;
}
private Object getFieldValue(String fieldName, long coordinate) {
int i = bindings.getTemplate().getBindPointNames().indexOf(fieldName);
if (i<0) {
throw new RuntimeException("field name '" + fieldName + "' does not exist in bindings:" + bindings);
}
Object o = bindings.get(i, coordinate);
return o;
}
public Map<String,Object> getCachedMap() {
return this.valuesCache;
}
}

View File

@ -0,0 +1,159 @@
/*
*
* Copyright 2015 Jonathan Shook
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*
*/
package io.virtdata.core;
//
import io.virtdata.api.DataMapper;
import io.virtdata.templates.BindPoint;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.security.InvalidParameterException;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;
import java.util.Optional;
/**
* Maps a set of parameters on an associated object of type T to specifiers for data mappers.
* Allows for easy construction of DataMapperBindings when in the proper thread scope.
* <p>
* The user is required to call @{link resolveBindings} when in the scope that the resulting
* bindings will be used in.
*/
public class BindingsTemplate {
private final static Logger logger = LogManager.getLogger(BindingsTemplate.class);private List<String> bindPointNames = new ArrayList<>();
private List<String> specifiers = new ArrayList<>();
// public BindingsTemplate(Map<String,String> specs) {
// specs.forEach(this::addFieldBinding);
// }
public BindingsTemplate(List<String> anchors, List<String> specs) {
if (anchors.size()!=specs.size()) {
throw new InvalidParameterException("Anchors and Specifiers must be matched pair-wise.");
}
for (int i = 0; i < anchors.size(); i++) {
addFieldBinding(anchors.get(i),specs.get(i));
}
}
public BindingsTemplate(List<BindPoint> bindpoints) {
addFieldBindings(bindpoints);
}
public BindingsTemplate() {
}
public void addFieldBindings(List<BindPoint> bindPoints) {
for (BindPoint bindPoint : bindPoints) {
addFieldBinding(bindPoint.getAnchor(),bindPoint.getBindspec());
}
}
/**
* Add a named binding specifier to the template
* @param bindPointName the name associated with the binding specifier
* @param genSpec the binding specifier
*/
public void addFieldBinding(String bindPointName, String genSpec) {
this.bindPointNames.add(bindPointName);
this.specifiers.add(genSpec);
}
/**
* Add multiple named bindings to the template
* @param bindPairs A map of named binding specifiers
*/
public void addFieldBindings(Map<String,String> bindPairs) {
for (Map.Entry<String, String> e : bindPairs.entrySet()) {
this.bindPointNames.add(e.getKey());
this.specifiers.add(e.getValue());
}
}
/**
* Use the data mapping library and the specifier to create instances of data mapping functions.
* If you need thread-aware mapping, be sure to call this in the proper thread. Each time this method
* is called, it creates a new instance.
* @return A set of bindings that can be used to yield mapped data values later.
*/
public Bindings resolveBindings() {
List<DataMapper<?>> dataMappers = new ArrayList<>();
for (String specifier : specifiers) {
Optional<DataMapper<Object>> optionalDataMapper = VirtData.getOptionalMapper(specifier);
if (optionalDataMapper.isPresent()) {
dataMappers.add(optionalDataMapper.get());
} else {
logAvailableDataMappers();
throw new RuntimeException(
"data mapper binding was unsuccessful for "
+ ", spec:" + specifier
+ ", see log for known data mapper names.");
}
}
return new Bindings(this, dataMappers);
}
private void logAvailableDataMappers() {
VirtDataDocs.getAllNames().forEach(gn -> logger.info("DATAMAPPER " + gn));
}
public List<String> getBindPointNames() {
return this.bindPointNames;
}
public List<String> getDataMapperSpecs() {
return this.specifiers;
}
@Override
public String toString() {
String delim = "";
StringBuilder sb = new StringBuilder(BindingsTemplate.class.getSimpleName()).append(":");
for (int i = 0; i < bindPointNames.size(); i++) {
sb.append(delim);
sb.append("'").append(bindPointNames.get(i)).append("'");
sb.append("=>");
sb.append("\"").append(specifiers.get(i)).append("\"");
delim = ", ";
}
return sb.toString();
}
public String toString(Object[] values) {
String delim = "";
StringBuilder sb = new StringBuilder(BindingsTemplate.class.getSimpleName()).append(":");
for (int i = 0; i < bindPointNames.size(); i++) {
sb.append(delim);
sb.append("'").append(bindPointNames.get(i)).append("'");
sb.append("=>");
sb.append("\"").append(specifiers.get(i)).append("\"");
sb.append("=>[");
sb.append(values[i]);
sb.append("](");
sb.append((null!=values[i]) ? values[i].getClass().getSimpleName() : "NULL");
sb.append(")");
delim = ", ";
}
return sb.toString();
}
}

View File

@ -0,0 +1,106 @@
package io.virtdata.core;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
public class CompatibilityFixups {
private final static Logger logger = LogManager.getLogger(CompatibilityFixups.class);// Not all of these are simple upper-case changes
private final static Map<String,String> funcs = new HashMap<String,String>() {{
put("log_normal","LogNormal");
put("normal", "Normal");
put("levy", "Levy");
put("nakagami","Nakagami");
put("exponential","Exponential");
put("logistic","Logistic");
put("laplace","Laplace");
put("cauchy","Cauchy");
put("f","F");
put("t","T");
put("weibull","Weibull");
put("chi_squared","ChiSquared");
put("gumbel","Gumbel");
put("beta","Beta");
put("pareto","Pareto");
put("gamma","Gamma");
put("uniform_real","Uniform");
put("uniform_integer","Uniform");
put("hypergeometric","Hypergeometric");
put("geometric","Geometric");
put("poisson","Poisson");
put("zipf","Zipf");
put("binomial","Binomial");
put("pascal","Pascal");
}};
private static final String MAPTO = "mapto_";
private static final String HASHTO = "hashto_";
private static final String COMPUTE = "compute_";
private static final String INTERPOLATE = "interpolate_";
private final static Pattern oldcurve = Pattern.compile("(?<name>\\b[\\w_]+)(?<lparen>\\()(?<args>.*?)(?<rparen>\\))");
private final static CompatibilityFixups instance = new CompatibilityFixups();
public static String fixup(String spec) {
String fixed = instance.fix(spec);
if (!fixed.equals(spec)) {
logger.warn(spec + "' was preprocessed to '" + fixed + "'. Please change to the new one to avoid this warning.");
}
return fixed;
}
public String fix(String spec) {
// Fixup curve ctors. These are not HOF, so local matching will work fine. However, they could occur multiple
// times within an HOF, so multiple replace is necessary.
Matcher matcher = oldcurve.matcher(spec);
StringBuilder out = new StringBuilder(spec.length());
int start = 0;
while (matcher.find()) {
out.append(spec.substring(start, matcher.start()));
String replacement = fixCurveCall(matcher.group("name"), matcher.group("args"));
out.append(replacement);
start = matcher.end();
}
out.append(spec.substring(start));
return out.toString();
}
private String fixCurveCall(String name, String args) {
boolean map = false;
boolean compute = false;
if (name.contains(MAPTO)) {
name = name.replaceAll(MAPTO,"");
map=true;
}
if (name.contains(HASHTO)) {
name = name.replaceAll(HASHTO,"");
map=false;
}
if (name.contains(COMPUTE)) {
name = name.replaceAll(COMPUTE,"");
compute=true;
}
if (name.contains(INTERPOLATE)) {
name = name.replaceAll(INTERPOLATE,"");
compute=false;
}
String nameReplacement = funcs.get(name);
if (nameReplacement!=null) {
name=nameReplacement;
args=map?args+",'map'":args+",'hash'";
args=compute?args+",'compute'":args+",'interpolate'";
}
return name+"("+args+")";
}
}

View File

@ -0,0 +1,48 @@
package io.virtdata.core;
import io.virtdata.api.ValuesArrayBinder;
import io.virtdata.api.Binder;
/**
* <p>A thread-local template that describes a set of data mappers, a context object,
* and a method for applying mapped values to the context object via an object array.
* This type is used in thread-local scope to map thread-specific
* data mapper instances to a contextual template object and a method for
* applying mapped values to it.</p>
*
* <p>This type is generally constructed by a ContextualBindingsTemplate.</p>
*
* @param <C> The type of the contextual template object.
* @param <R> The resulting type from binding mapped values with the contextual template C
*/
public class ContextualArrayBindings<C, R> implements Binder<R> {
private final C context;
private Bindings bindings;
private ValuesArrayBinder<C, R> valuesArrayBinder;
public ContextualArrayBindings(Bindings bindings, C context, ValuesArrayBinder<C, R> valuesArrayBinder) {
this.bindings = bindings;
this.context = context;
this.valuesArrayBinder = valuesArrayBinder;
}
public Bindings getBindings() {
return bindings;
}
public C getContext() {
return context;
}
@Override
public R bind(long value) {
Object[] allGeneratedValues = bindings.getAll(value);
try { // Provide bindings context data where it may be useful
return valuesArrayBinder.bindValues(context, allGeneratedValues);
} catch (Exception e) {
throw new RuntimeException("Binding error:" + bindings.getTemplate().toString(allGeneratedValues), e);
}
}
}

View File

@ -0,0 +1,46 @@
package io.virtdata.core;
import io.virtdata.api.Binder;
import io.virtdata.api.ValuesBinder;
/**
* <p>A thread-local template that describes a set of data mappers, a context object, and a method for applying
* mapped values to the context object directly from the bindings. This type is used in thread-local scope
* to map thread-specific data mapper instances to a contextual template object and a method for applying mapped values to it.</p>
*
* <p>This type is generally constructed by a ContextualDirectBindingsTemplate.</p>
*
* @param <C> The type of the contextual template object.
* @param <R> The resulting type from binding mapped values with the contextual template C
*/
public class ContextualBindings<C, R> implements Binder<R> {
private final C context;
private Bindings bindings;
private ValuesBinder<C, R> valuesBinder;
public ContextualBindings(Bindings bindings, C context, ValuesBinder<C, R> valuesBinder) {
this.bindings = bindings;
this.context = context;
this.valuesBinder = valuesBinder;
}
public Bindings getBindings() {
return bindings;
}
public C getContext() {
return context;
}
@Override
public R bind(long value) {
Object[] allGeneratedValues = bindings.getAll(value);
try { // Provide bindings context data where it may be useful
return valuesBinder.bindValues(context, bindings, value);
} catch (Exception e) {
throw new RuntimeException("Binding error:" + bindings.getTemplate().toString(allGeneratedValues), e);
}
}
}

View File

@ -0,0 +1,44 @@
package io.virtdata.core;
import io.virtdata.api.ValuesArrayBinder;
/**
* A template that maps a set of specifiers, a context object, and a method for applying
* mapped values to the context object. This can be used in the configuration phase, in global
* scope without triggering mapper bindings resolution from specifiers.
*
* @param <C> The type of the contextual template object.
* @param <R> The type which will be produced when mapped values are applied to a type C
*/
public class ContextualBindingsArrayTemplate<C, R> {
private C context;
private BindingsTemplate bindingsTemplate;
private ValuesArrayBinder<C, R> valuesArrayBinder;
public ContextualBindingsArrayTemplate(C context,
BindingsTemplate bindingsTemplate,
ValuesArrayBinder<C, R> valuesArrayBinder) {
this.context = context;
this.bindingsTemplate = bindingsTemplate;
this.valuesArrayBinder = valuesArrayBinder;
}
public C getContext() {
return context;
}
public BindingsTemplate getBindingsTemplate() {
return bindingsTemplate;
}
public ValuesArrayBinder<C, R> getValuesArrayBinder() {
return valuesArrayBinder;
}
public ContextualArrayBindings<C, R> resolveBindings() {
Bindings bindings = bindingsTemplate.resolveBindings();
return new ContextualArrayBindings<C, R>(bindings, context, valuesArrayBinder);
}
}

View File

@ -0,0 +1,44 @@
package io.virtdata.core;
import io.virtdata.api.ValuesBinder;
/**
* A template that maps a set of specifiers, a context object, and a method for applying
* mapped values to the context object. This can be used in the configuration phase, in global
* scope without triggering mapper bindings resolution from specifiers.
*
* @param <C> The type of the contextual template object.
* @param <R> The type which will be produced when mapped values are applied to a type C
*/
public class ContextualBindingsTemplate<C, R> {
private C context;
private BindingsTemplate bindingsTemplate;
private ValuesBinder<C, R> valuesBinder;
public ContextualBindingsTemplate(C context,
BindingsTemplate bindingsTemplate,
ValuesBinder<C, R> valuesMapBinder) {
this.context = context;
this.bindingsTemplate = bindingsTemplate;
this.valuesBinder = valuesMapBinder;
}
public C getContext() {
return context;
}
public BindingsTemplate getBindingsTemplate() {
return bindingsTemplate;
}
public ValuesBinder<C, R> getValuesBinder() {
return valuesBinder;
}
public ContextualBindings<C, R> resolveBindings() {
Bindings bindings = bindingsTemplate.resolveBindings();
return new ContextualBindings<C, R>(bindings, context, valuesBinder);
}
}

View File

@ -0,0 +1,50 @@
package io.virtdata.core;
import io.virtdata.api.Binder;
import io.virtdata.api.ValuesMapBinder;
import java.util.HashMap;
import java.util.Map;
/**
* <p>A thread-local template that describes a set of data mappers, a context object, and a method for applying
* mapped values to the context object via a String-Object map. This type is used in thread-local scope to map thread-specific
* data mapper instances to a contextual template object and a method for applying mapped values to it.</p>
*
* <p>This type is generally constructed by a ContextualBindingsTemplate.</p>
*
* @param <C> The type of the contextual template object.
* @param <R> The resulting type from binding mapped values with the contextual template C
*/
public class ContextualMapBindings<C, R> implements Binder<R> {
private final C context;
private Bindings bindings;
private ValuesMapBinder<C, R> valuesMapBinder;
public ContextualMapBindings(Bindings bindings, C context, ValuesMapBinder<C, R> valuesMapBinder) {
this.bindings = bindings;
this.context = context;
this.valuesMapBinder = valuesMapBinder;
}
public Bindings getBindings() {
return bindings;
}
public C getContext() {
return context;
}
@Override
public R bind(long value) {
Map<String,Object> generatedValues = new HashMap<String,Object>();
bindings.setMap(generatedValues, value);
try { // Provide bindings context data where it may be useful
return valuesMapBinder.bindValues(context, generatedValues);
} catch (Exception e) {
throw new RuntimeException("Binding error:" + bindings.getTemplate().toString() + ": " + generatedValues, e);
}
}
}

View File

@ -0,0 +1,116 @@
package io.virtdata.core;
import io.virtdata.api.FunctionType;
import io.virtdata.api.DataMapper;
import java.util.function.*;
/**
* <p>This class implements an obtuse way of avoiding autoboxing and M:N type
* mapping complexity by way of doublish dispatch. It was preferred over a more
* generalized reflection and annotation-based approach. If it gets too verbose,
* (for some definition of "too"), then it may be refactored.</p>
* <p>The primary goal of this approach is to allow for primitive-level
* lambdas when function are composed together. This will allow for significant
* performance gains when there are only a few steps in a composed function
* which are non-primitive, which is the general case.</p>
* <p>Composition should be supported between all primitive functions
* for types listed in TypeMap, as well as generic functions, with generic
* functions as the last resort.</p>
*/
@SuppressWarnings("unchecked")
public class DataMapperFunctionMapper {
public static <T> DataMapper<T> map(Object function) {
FunctionType functionType = FunctionType.valueOf(function);
switch (functionType) {
case long_double:
return (DataMapper<T>) map((LongToDoubleFunction) function);
case long_int:
return (DataMapper<T>) map((LongToIntFunction) function);
case long_long:
return (DataMapper<T>) map((LongUnaryOperator) function);
case long_T:
return (DataMapper<T>) map((LongFunction) function);
case R_T:
return (DataMapper<T>) map((Function) function);
case int_int:
return (DataMapper<T>) map((IntUnaryOperator) function);
case int_long:
return (DataMapper<T>) map((IntToLongFunction) function);
case int_double:
return (DataMapper<T>) map((IntToDoubleFunction) function);
case int_T:
return (DataMapper<T>) map((IntFunction) function);
case double_double:
return (DataMapper<T>) map((DoubleUnaryOperator) function);
case double_long:
return (DataMapper<T>) map((DoubleToLongFunction) function);
case double_int:
return (DataMapper<T>) map((DoubleToIntFunction) function);
case double_T:
return (DataMapper<T>) map((DoubleFunction) function);
default:
throw new RuntimeException(
"Function object was not a recognized type for mapping to a data mapping lambda: "
+ function.toString());
}
}
public static <R> DataMapper<R> map(DoubleFunction<R> f) {
return (long l) -> f.apply((double) l);
}
public static DataMapper<Integer> map(DoubleToIntFunction f) {
return f::applyAsInt;
}
public static DataMapper<Long> map(DoubleToLongFunction f) {
return f::applyAsLong;
}
public static DataMapper<Double> map(DoubleUnaryOperator f) {
return f::applyAsDouble;
}
public static <R> DataMapper<R> map(IntFunction<R> f) {
return (long l) -> f.apply((int) l);
}
public static DataMapper<Long> map(IntToDoubleFunction f) {
return (long l) -> (long) f.applyAsDouble((int) l);
}
public static DataMapper<Long> map(IntToLongFunction f) {
return (long l) -> f.applyAsLong((int) l);
}
public static DataMapper<Integer> map(IntUnaryOperator f) {
return (long l) -> f.applyAsInt((int) l);
}
public static DataMapper<Double> map(LongToDoubleFunction f) {
return f::applyAsDouble;
}
public static DataMapper<Integer> map(LongToIntFunction f) {
return f::applyAsInt;
}
public static DataMapper<Long> map(LongUnaryOperator f) {
return f::applyAsLong;
}
public static <R> DataMapper<R> map(LongFunction<R> f) {
return f::apply;
}
public static <R> DataMapper<R> map(Function<Long, R> f) {
return f::apply;
}
}

View File

@ -0,0 +1,83 @@
/*
* Copyright 2015 jshook
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.virtdata.core;
import io.virtdata.api.DataMapperLibrary;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;
import java.util.stream.Collectors;
/**
* Convenient singleton for accessing all loadable DataMapper Library instances.
*/
public class DataMapperLibraryFinder {
private static final Logger logger =
LogManager.getLogger(DataMapperLibrary.class);
private static final Map<String, DataMapperLibrary> libraries = new ConcurrentHashMap<>();
private DataMapperLibraryFinder() {
}
public synchronized static DataMapperLibrary get(String libraryName) {
Optional<DataMapperLibrary> at = Optional.ofNullable(getLibraries().get(libraryName));
return at.orElseThrow(
() -> new RuntimeException("DataMapperLibrary '" + libraryName + "' not found.")
);
}
private synchronized static Map<String, DataMapperLibrary> getLibraries() {
if (libraries.size()==0) {
ClassLoader cl = Thread.currentThread().getContextClassLoader();
logger.debug("loading DataMapper Libraries");
ServiceLoader<DataMapperLibrary> sl = ServiceLoader.load(DataMapperLibrary.class);
Map<String,Integer> dups = new HashMap<>();
for (DataMapperLibrary dataMapperLibrary : sl) {
logger.debug("Found data mapper library:" +
dataMapperLibrary.getClass().getCanonicalName() + ":" +
dataMapperLibrary.getLibraryName());
if (libraries.get(dataMapperLibrary.getLibraryName()) != null) {
String name = dataMapperLibrary.getLibraryName();
dups.put(name,dups.getOrDefault(name,0));
}
libraries.put(dataMapperLibrary.getLibraryName(),dataMapperLibrary);
}
if (dups.size() > 0) {
logger.trace("Java runtime provided duplicates for " +
dups.entrySet().stream().map(e -> e.getKey()+":"+e.getValue()).collect(Collectors.joining(",")));
}
}
logger.info("Loaded DataMapper Libraries:" + libraries.keySet());
return libraries;
}
/**
* Return list of libraries that have been found by this runtime,
* in alphabetical order of their type names.
* @return a list of DataMapperLibrary instances.
*/
public synchronized static List<DataMapperLibrary> getAll() {
List<DataMapperLibrary> libraries = new ArrayList<>(getLibraries().values());
libraries.sort((o1, o2) -> o1.getLibraryName().compareTo(o2.getLibraryName()));
return Collections.unmodifiableList(libraries);
}
}

View File

@ -0,0 +1,54 @@
package io.virtdata.core;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Optional;
public class FunctionTyper {
public static Class<?> getResultClass(Class<?> functionalType) {
assertFunctionalInterface(functionalType);
Method applyMethod = getMethod(functionalType);
return applyMethod.getReturnType();
}
public static Class<?> getInputClass(Class<?> functionalType) {
assertFunctionalInterface(functionalType);
Method applyMethod = getMethod(functionalType);
return applyMethod.getParameterTypes()[0];
}
public static Class<?> getArgType(Method applyMethod) {
if (applyMethod.getParameterCount() != 1) {
throw new RuntimeException(
"The parameter found is supposed to be 1, but it was" + applyMethod.getParameterCount()
);
}
return applyMethod.getParameterTypes()[0];
}
private static Method getMethod(Class<?> functionalType) {
assertFunctionalInterface(functionalType);
Optional<Method> foundMethod = Arrays.stream(functionalType.getMethods())
.filter(m -> !m.isSynthetic() && !m.isBridge() && !m.isDefault())
.filter(m -> m.getName().startsWith("apply"))
.findFirst();
return foundMethod.orElseThrow(
() -> new RuntimeException(
"Unable to find the function method on " + functionalType.getCanonicalName()
)
);
}
private static void assertFunctionalInterface(Class<?> functionalType) {
if (functionalType.getAnnotation(FunctionalInterface.class)==null) {
throw new RuntimeException("type " + functionalType.getCanonicalName() + " is not a functional type");
}
if (!functionalType.isInterface()) {
throw new RuntimeException("type " + functionalType.getCanonicalName() + " is not an interface.");
}
}
}

View File

@ -0,0 +1,98 @@
/*
* Copyright 2017 jshook
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.virtdata.core;
import java.util.*;
public class LazyValuesMap implements Map<String,Object> {
private final Bindings bindings;
private final BindingsCache bindingsCache;
private final long input;
public LazyValuesMap(Bindings bindings, long input) {
this.bindings = bindings;
this.bindingsCache = new BindingsCache(bindings);
this.input = input;
}
@Override
public int size() {
return bindings.getTemplate().getBindPointNames().size();
}
@Override
public boolean isEmpty() {
return bindings.getTemplate().getBindPointNames().isEmpty();
}
@Override
public boolean containsKey(Object key) {
return bindings.getTemplate().getBindPointNames().contains((String) key);
}
/**
* TODO: Doc how this is different, and semantically useful
* @param value the spec value, not the generated data value
* @return true if the spec exists in the bindings
*/
@Override
public boolean containsValue(Object value) {
return bindings.getTemplate().getDataMapperSpecs().contains((String) value);
}
@Override
public Object get(Object key) {
return bindingsCache.getField((String) key,input);
}
@Override
public Object put(String key, Object value) {
return bindingsCache.getCachedMap().put(key,value);
}
@Override
public Object remove(Object key) {
return bindingsCache.getCachedMap().remove(key);
}
@Override
public void putAll(Map<? extends String, ?> m) {
bindingsCache.getCachedMap().putAll(m);
}
@Override
public void clear() {
bindingsCache.getCachedMap().clear();
}
@Override
public Set<String> keySet() {
return Collections.unmodifiableSet(new HashSet<String>()
{{
addAll(bindings.getTemplate().getBindPointNames());
}});
}
@Override
public Collection<Object> values() {
return bindingsCache.getCachedMap().values();
}
@Override
public Set<Entry<String, Object>> entrySet() {
return bindingsCache.getCachedMap().entrySet();
}
}

View File

@ -0,0 +1,160 @@
package io.virtdata.core;
import io.virtdata.api.FunctionType;
import io.virtdata.api.ValueType;
import java.lang.invoke.MethodHandles;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.Comparator;
import java.util.Optional;
/**
* A function that has been resolved by a libraryName for use in data mapping.
* Some API calls require this type, as it can only be constructed successfully
* if the object type is valid for mapping to a data mapper function.
*/
public class ResolvedFunction {
public static Comparator<ResolvedFunction> PREFERRED_TYPE_COMPARATOR = new PreferredTypeComparator();
private final Class<?> inputType;
private final Class<?> outputType;
private Class<?>[] initializerSignature;
private Object[] initializerValues;
private FunctionType functionType;
private Object functionObject;
private String libraryName;
private boolean isThreadSafe;
private static MethodHandles.Lookup methodLookup = MethodHandles.publicLookup();
public ResolvedFunction(Object g, boolean isThreadSafe, Class<?>[] initializerSignature, Object[] initValues, Class<?> inputType, Class<?> outputType, String libraryName) {
this(g, isThreadSafe, initializerSignature, initValues, inputType, outputType);
this.libraryName = libraryName;
}
public ResolvedFunction(Object g, boolean isThreadSafe, Class<?>[] initializerSignature, Object[] initValues, Class<?> inputType, Class<?> outputType) {
this.functionObject = g;
this.isThreadSafe = isThreadSafe;
functionType = FunctionType.valueOf(g); // sanity check the type of g
this.initializerSignature = initializerSignature;
this.initializerValues = initValues;
this.inputType = inputType;
this.outputType = outputType;
}
public static String getStringLegend() {
return "[<library name>::] input->class->output [initializer type->parameter type,...]";
}
public FunctionType getFunctionType() {
return functionType;
}
public void setFunctionType(FunctionType functionType) {
this.functionType = functionType;
}
public Object getFunctionObject() {
return functionObject;
}
public void setFunctionObject(Object functionObject) {
this.functionObject = functionObject;
}
public Class<?> getResultClass() {
Method applyMethod = getMethod();
return applyMethod.getReturnType();
}
public Class<?> getInputClass() {
Method applyMethod = getMethod();
return applyMethod.getParameterTypes()[0];
}
public Class<?> getArgType() {
Method applyMethod = getMethod();
if (applyMethod.getParameterCount() != 1) {
throw new RuntimeException(
"The parameter found is supposed to be 1, but it was" + applyMethod.getParameterCount()
);
}
return applyMethod.getParameterTypes()[0];
}
private Method getMethod() {
Optional<Method> foundMethod = Arrays.stream(functionObject.getClass().getMethods())
.filter(m -> !m.isSynthetic() && !m.isBridge() && !m.isDefault())
.filter(m -> m.getName().startsWith("apply"))
.findFirst();
return foundMethod.orElseThrow(
() -> new RuntimeException(
"Unable to find the function method on " + functionObject.getClass().getCanonicalName()
)
);
}
public boolean isThreadSafe() {
return isThreadSafe;
}
public String toString() {
StringBuilder sb = new StringBuilder();
if (libraryName != null) {
sb.append(libraryName).append("::");
}
sb.append(getArgType().getSimpleName()).append("->");
sb.append(getMethod().getDeclaringClass().getName());
// sb.append(getFunctionObject().getClass().getPackage().getLibname()).append(".").append(getMethod().getLibname());
sb.append("->").append(getResultClass().getName());
if (initializerValues != null && initializerValues.length > 0) {
sb.append(" [");
for (int i = 0; i < initializerSignature.length; i++) {
Class<?> isig = initializerSignature[i];
String assignToType = isig.isPrimitive() ? isig.getName() : isig.getSimpleName();
String assignFromType = "[]";
if (i < initializerValues.length) {
Class<?> init = initializerValues[i].getClass();
assignFromType = init.isPrimitive() ? init.getName() : init.getSimpleName();
}
if (initializerSignature.length != initializerValues.length && i == initializerSignature.length - 1) {
assignToType = assignToType.replaceAll("\\[]", "") + "...";
assignFromType = assignFromType.replaceAll("\\[]", "") + "...";
}
sb.append(assignFromType).append("=>").append(assignToType);
sb.append(",");
}
sb.setLength(sb.length() - 1);
sb.append("]");
}
return sb.toString();
}
/**
* Compare two ResolvedFunctions by preferred input type and then by preferred output type.
*/
private static class PreferredTypeComparator implements Comparator<ResolvedFunction> {
@Override
public int compare(ResolvedFunction o1, ResolvedFunction o2) {
ValueType iv1 = ValueType.valueOfAssignableClass(o1.getArgType());
ValueType iv2 = ValueType.valueOfAssignableClass(o2.getArgType());
int inputComparison = iv1.compareTo(iv2);
if (inputComparison != 0) {
return inputComparison;
}
iv1 = ValueType.valueOfAssignableClass(o1.getResultClass());
iv2 = ValueType.valueOfAssignableClass(o2.getResultClass());
return iv1.compareTo(iv2);
}
}
}

View File

@ -0,0 +1,65 @@
package io.virtdata.core;
import io.virtdata.api.DataMapper;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.io.PrintWriter;
import java.io.StringWriter;
import java.util.Optional;
public class ResolverDiagnostics {
private final static Logger logger = LogManager.getLogger(ResolverDiagnostics.class);private ResolvedFunction resolvedFunction;
private final StringBuilder log = new StringBuilder();
private Throwable error;
public ResolverDiagnostics() {
}
public <T> Optional<DataMapper<T>> getOptionalMapper() {
return Optional.ofNullable(resolvedFunction).map(ResolvedFunction::getFunctionObject).map(DataMapperFunctionMapper::map);
}
public Optional<ResolvedFunction> getResolvedFunction() {
return Optional.ofNullable(getResolvedFunctionOrThrow());
}
public ResolvedFunction getResolvedFunctionOrThrow() {
if (error!=null) {
throw new RuntimeException(error.getMessage(),error);
}
return resolvedFunction;
}
public ResolverDiagnostics error(Exception e) {
this.error = e;
log.append("ERROR encountered while resolving function:\n");
log.append(e.toString()).append("\n");
StringWriter writer = new StringWriter();
PrintWriter pw = new PrintWriter(writer);
e.printStackTrace(pw);
String stacktrace = writer.toString();
log.append("stack trace:\n");
log.append(stacktrace);
return this;
}
public ResolverDiagnostics setResolvedFunction(ResolvedFunction resolvedFunction) {
this.resolvedFunction = resolvedFunction;
return this;
}
public ResolverDiagnostics trace(String s) {
logger.trace(s);
log.append(s).append("\n");
return this;
}
public String toString() {
return log.toString();
}
}

View File

@ -0,0 +1,276 @@
package io.virtdata.core;
import io.virtdata.api.DataMapper;
import io.virtdata.api.ValueType;
import io.virtdata.ast.VirtDataFlow;
import io.virtdata.parser.VirtDataDSL;
import io.virtdata.templates.BindPoint;
import org.apache.commons.lang3.ClassUtils;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.util.*;
public class VirtData {
private final static Logger logger = LogManager.getLogger(VirtData.class);/**
* Create a bindings template from the pair-wise names and specifiers.
* Each even-numbered (starting with zero) argument is a binding name,
* and each odd-numbered (starting with one) argument is a binding spec.
*
* @param namesAndSpecs names and specs in "name", "spec", ... form
* @return A bindings template that can be used to resolve a bindings instance
*/
public static BindingsTemplate getTemplate(String... namesAndSpecs) {
if ((namesAndSpecs.length % 2) != 0) {
throw new RuntimeException(
"args must be in 'name','spec', pairs. " +
"This can't be true for " + namesAndSpecs.length + "elements.");
}
List<BindPoint> bindPoints = new ArrayList<>();
for (int i = 0; i < namesAndSpecs.length; i += 2) {
bindPoints.add(new BindPoint(namesAndSpecs[i],namesAndSpecs[i+1]));
}
return getTemplate(bindPoints);
}
// /**
// * Create a bindings template from the provided map, ensuring that
// * the syntax of the bindings specs is parsable first.
// *
// * @param namedBindings The named bindings map
// * @return a bindings template
// */
// public static BindingsTemplate getTemplate(Map<String, String> namedBindings) {
//
// for (String bindingSpec : namedBindings.values()) {
// VirtDataDSL.ParseResult parseResult = VirtDataDSL.parse(bindingSpec);
// if (parseResult.throwable != null) {
// throw new RuntimeException(parseResult.throwable);
// }
// }
// return new BindingsTemplate(namedBindings);
// }
/**
* Create a bindings template from a provided list of {@link BindPoint}s,
* ensuring that the syntax of the bindings specs is parsable first.
*
* @param bindPoints A list of {@link BindPoint}s
* @return A BindingsTemplate
*/
public static BindingsTemplate getTemplate(List<BindPoint> bindPoints) {
for (BindPoint bindPoint : bindPoints) {
String bindspec = bindPoint.getBindspec();
VirtDataDSL.ParseResult parseResult = VirtDataDSL.parse(bindspec);
if (parseResult.throwable!=null) {
throw new RuntimeException(parseResult.throwable);
}
}
return new BindingsTemplate(bindPoints);
}
/**
* Instantiate an optional data mapping function if possible.
*
* @param flowSpec The VirtData specifier for the mapping function
* @param <T> The parameterized return type of the function
* @return An optional function which will be empty if the function could not be resolved.
*/
public static <T> Optional<DataMapper<T>> getOptionalMapper(String flowSpec, Map<String,?> cfg) {
flowSpec = CompatibilityFixups.fixup(flowSpec);
VirtDataDSL.ParseResult parseResult = VirtDataDSL.parse(flowSpec);
if (parseResult.throwable != null) {
throw new RuntimeException(parseResult.throwable);
}
VirtDataFlow flow = parseResult.flow;
VirtDataComposer composer = new VirtDataComposer();
composer.addCustomElements(cfg);
Optional<ResolvedFunction> resolvedFunction = composer.resolveFunctionFlow(flow);
return resolvedFunction.map(ResolvedFunction::getFunctionObject).map(DataMapperFunctionMapper::map);
}
public static <T> Optional<DataMapper<T>> getOptionalMapper(String flowSpec) {
return getOptionalMapper(flowSpec,Collections.emptyMap());
}
public static ResolverDiagnostics getMapperDiagnostics(String flowSpec) {
return getMapperDiagnostics(flowSpec, Collections.emptyMap());
}
public static ResolverDiagnostics getMapperDiagnostics(String flowSpec, Map<String,Object> config) {
try {
flowSpec = CompatibilityFixups.fixup(flowSpec);
VirtDataDSL.ParseResult parseResult = VirtDataDSL.parse(flowSpec);
if (parseResult.throwable != null) {
throw new RuntimeException(parseResult.throwable);
}
VirtDataFlow flow = parseResult.flow;
VirtDataComposer composer = new VirtDataComposer();
composer.addCustomElements(config);
ResolverDiagnostics resolverDiagnostics = composer.resolveDiagnosticFunctionFlow(flow);
return resolverDiagnostics;
} catch (Exception e) {
return new ResolverDiagnostics().error(e);
}
}
/**
* Instantiate an optional data mapping function if possible, with type awareness. This version
* of {@link #getOptionalMapper(String)} will use the additional type information in the clazz
* parameter to automatically parameterize the flow specifier.
*
* If the flow specifier does contain
* an output type qualifier already, then a check is made to ensure that the output type qualifier is
* assignable to the specified class in the clazz parameter. This ensures that type parameter awareness
* at compile time is honored and verified when this call is made.
*
* @param flowSpec The VirtData specifier for the mapping function
* @param <T> The parameterized return type of the function.
* @param clazz The explicit class which must be of type T or assignable to type T
* @return An optional function which will be empty if the function could not be resolved.
*/
public static <T> Optional<DataMapper<T>> getOptionalMapper(String flowSpec, Class<? extends T> clazz) {
return getOptionalMapper(flowSpec,clazz,Collections.emptyMap());
}
public static <T> Optional<DataMapper<T>> getOptionalMapper(
String flowSpec,
Class<?> clazz,
Map<String,Object> config) {
flowSpec = CompatibilityFixups.fixup(flowSpec);
VirtDataDSL.ParseResult parseResult = VirtDataDSL.parse(flowSpec);
if (parseResult.throwable != null) {
throw new RuntimeException(parseResult.throwable);
}
VirtDataFlow flow = parseResult.flow;
String outputType = flow.getLastExpression().getCall().getOutputType();
Class<?> outputClass = ValueType.classOfType(outputType);
if (outputClass != null) {
if (!ClassUtils.isAssignable(outputClass,clazz,true)) {
throw new RuntimeException("The flow specifier '" + flowSpec + "' wants an output type of '" + outputType +"', but this" +
" type is not assignable to the explicit class '" + clazz.getCanonicalName() + "' that was enforced at the API level." +
" Either remove the output type qualifier at the last function in the flow spec, or change it to something that can" +
" reliably be cast to type '" + clazz.getCanonicalName() +"'");
}
} else {
logger.debug("Auto-assigning output type qualifier '->" + clazz.getCanonicalName() + "' to specifier '" + flowSpec + "'");
flow.getLastExpression().getCall().setOutputType(clazz.getCanonicalName());
}
VirtDataComposer composer = new VirtDataComposer();
composer.addCustomElements(config);
Optional<ResolvedFunction> resolvedFunction = composer.resolveFunctionFlow(flow);
Optional<DataMapper<T>> mapper = resolvedFunction.map(ResolvedFunction::getFunctionObject).map(DataMapperFunctionMapper::map);
if (mapper.isPresent()) {
T actualTestValue = mapper.get().get(1L);
if (!ClassUtils.isAssignable(actualTestValue.getClass(),clazz,true)) {
throw new RuntimeException("The flow specifier '" + flowSpec + "' successfully created a function, but the test value" +
"(" + String.valueOf(actualTestValue) + ") of type [" + actualTestValue.getClass() + "] produced by it was not " +
"assignable to the type '" + clazz.getCanonicalName() + "' which was explicitly set" +
" at the API level.");
}
}
return mapper;
}
public static <T> T getFunction(String flowSpec, Class<? extends T> functionType) {
return getFunction(flowSpec, functionType, Collections.emptyMap());
}
public static <T> T getFunction(String flowSpec, Class<? extends T> functionType, Map<String,Object> config) {
Optional<? extends T> optionalFunction = getOptionalFunction(flowSpec, functionType, config);
return optionalFunction.orElseThrow();
}
public static <T> Optional<T> getOptionalFunction(String flowSpec, Class<? extends T> functionType) {
return getOptionalFunction(flowSpec,functionType,Collections.emptyMap());
}
public static <T> Optional<T> getOptionalFunction(String flowSpec, Class<? extends T> functionType, Map<String,Object> config) {
flowSpec = CompatibilityFixups.fixup(flowSpec);
Class<?> requiredInputType = FunctionTyper.getInputClass(functionType);
Class<?> requiredOutputType = FunctionTyper.getResultClass(functionType);
FunctionalInterface annotation = functionType.getAnnotation(FunctionalInterface.class);
if (annotation==null) {
throw new RuntimeException("You can only use function types that are tagged as @FunctionInterface");
}
VirtDataDSL.ParseResult parseResult = VirtDataDSL.parse(flowSpec);
if (parseResult.throwable != null) {
throw new RuntimeException(parseResult.throwable);
}
VirtDataFlow flow = parseResult.flow;
String specifiedInputClassName = flow.getFirstExpression().getCall().getInputType();
Class<?> specifiedInputClass = ValueType.classOfType(specifiedInputClassName);
if (specifiedInputClass!=null) {
if (!ClassUtils.isAssignable(specifiedInputClass,requiredInputType,true)) {
throw new RuntimeException("The flow specifier '" + flowSpec + "' wants an input type of '" + specifiedInputClassName +"', but this" +
" type is not assignable to the input class required by the functional type requested '" + functionType.getCanonicalName() + "'. (type "+requiredInputType.getCanonicalName()+")" +
" Either remove the input type qualifier at the first function in the flow spec, or change it to something that can" +
" reliably be cast to type '" + requiredInputType.getCanonicalName() +"'");
}
} else {
logger.debug("Auto-assigning input type qualifier '" + requiredInputType.getCanonicalName() + "->' to specifier '" + flowSpec + "'");
flow.getFirstExpression().getCall().setInputType(requiredInputType.getCanonicalName());
}
String specifiedOutputClassName = flow.getLastExpression().getCall().getOutputType();
Class<?> specifiedOutputClass = ValueType.classOfType(specifiedOutputClassName);
if (specifiedOutputClass != null) {
if (!ClassUtils.isAssignable(specifiedOutputClass,requiredOutputType,true)) {
throw new RuntimeException("The flow specifier '" + flowSpec + "' wants an output type of '" + specifiedOutputClass +"', but this" +
" type is not assignable to the output class required by functional type '" + functionType.getCanonicalName() + "'. (type "+requiredOutputType.getCanonicalName()+")" +
" Either remove the output type qualifier at the last function in the flow spec, or change it to something that can" +
" reliably be cast to type '" + requiredOutputType.getCanonicalName() +"'");
}
} else {
logger.debug("Auto-assigning output type qualifier '->" + requiredOutputType.getCanonicalName() + "' to specifier '" + flowSpec + "'");
flow.getLastExpression().getCall().setOutputType(requiredOutputType.getCanonicalName());
}
VirtDataComposer composer = new VirtDataComposer();
composer.addCustomElements(config);
Optional<ResolvedFunction> resolvedFunction = composer.resolveFunctionFlow(flow);
return resolvedFunction.map(ResolvedFunction::getFunctionObject).map(functionType::cast);
}
/**
* Instantiate a data mapping function, or throw an exception.
*
* @param flowSpec The VirtData specifier for the mapping function
* @param <T> The parameterized return type of the function
* @return A data mapping function
* @throws RuntimeException if the function could not be resolved
*/
public static <T> DataMapper<T> getMapper(String flowSpec, Map<String,Object> config) {
Optional<DataMapper<T>> optionalMapper = getOptionalMapper(flowSpec,config);
return optionalMapper.orElseThrow(() -> new RuntimeException("Unable to find mapper: " + flowSpec));
}
public static <T> DataMapper<T> getMapper(String flowSpec) {
return getMapper(flowSpec, Collections.emptyMap());
}
/**
* Instantiate a data mapping function of the specified type, or throw an error.
*
* @param flowSpec The VirtData flow specifier for the function to be returned
* @param clazz The class of the data mapping function return type
* @param <T> The parameterized class of the data mapping return type
* @return A new data mapping function.
* @throws RuntimeException if the function could not be resolved
*/
public static <T> DataMapper<T> getMapper(String flowSpec, Class<? extends T> clazz, Map<String,Object> config) {
Optional<DataMapper<T>> dataMapper = getOptionalMapper(flowSpec, clazz);
DataMapper<T> mapper = dataMapper.orElseThrow(() -> new RuntimeException("Unable to find mapper: " + flowSpec));
return mapper;
}
public static <T> DataMapper<T> getMapper(String flowSpec, Class<? extends T> clazz) {
return getMapper(flowSpec, clazz, Collections.emptyMap());
}
}

View File

@ -0,0 +1,467 @@
package io.virtdata.core;
import io.virtdata.api.DataMapperLibrary;
import io.virtdata.api.ValueType;
import io.virtdata.api.VirtDataFunctionLibrary;
import io.virtdata.api.composers.FunctionAssembly;
import io.virtdata.ast.FunctionCall;
import io.virtdata.ast.VirtDataFlow;
import io.virtdata.parser.VirtDataDSL;
import org.apache.commons.lang3.ClassUtils;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.lang.invoke.MethodHandles;
import java.util.*;
import java.util.stream.Collectors;
/**
* <H2>Synopsis</H2>
* <p>This library implements the ability to compose a lambda function from a sequence of other functions.
* The resulting lambda will use the specialized primitive function interfaces, such as LongUnaryOperator, LongFunction, etc.
* Where there are two functions which do not have matching input and output types, the most obvious conversion is made.
* This means that while you are able to compose a LongUnaryOperator with a LongUnaryOperator for maximum
* efficiency, you can also compose LongUnaryOperator with an IntFunction, and a best effort attempt will be made to
* do a reasonable conversion in between.</p>
*
* <H2>Limitations</H2>
* <P>Due to type erasure, it is not possible to know the generic type parameters for non-primitive functional types.
* These include IntFunction&lt;?&gt;, LongFunction&lt;?&gt;, and in the worst case, Function&lt;?,?&gt;.
* For these types, annotations are provided to better inform the runtime lambda compositor.</P>
*
* <H2>Multiple Paths</H2>
* <P>The library allows for there to be multiple functions which match the spec, possibly because multiple
* functions have the same name, but exist in different libraries or in different packages within the same library.
* This means that the composer library must find a connecting path between the functions that can match at each stage,
* disregarding all but one.</P>
*
* <H2>Path Finding</H2>
* <P>The rule for finding the best path among the available functions is as follows, at each pairing between
* adjacent stages of functions:</P>
* <OL>
* <li>The co-compatible output and input types between the functions are mapped. Functions sharing the co-compatible
* types are kept in the list. Functions not sharing them are removed.</li>
* <li>As long as functions can be removed in this way, the process iterates through the chain, starting again
* at the front of the list.</li>
* <li>When no functions can be removed due to lack of co-compatible types, each stage is selected according to
* type preferences as represented in {@link ValueType}</li>
*
* <LI>If the next (outer) function does not have a compatible input type, move it down on the list.
* If, after this step, there are functions which do have matching signatures, all others are removed.</LI>
* </OL>
*/
public class VirtDataComposer {
private final static String PREAMBLE = "compose ";
private final static Logger logger = LogManager.getLogger(DataMapperLibrary.class);private final static MethodHandles.Lookup lookup = MethodHandles.publicLookup();
private final VirtDataFunctionLibrary functionLibrary;
private final Map<String,Object> customElements = new HashMap<>();
public VirtDataComposer(VirtDataFunctionLibrary functionLibrary) {
this.functionLibrary = functionLibrary;
}
public VirtDataComposer() {
this.functionLibrary = VirtDataLibraries.get();
}
public Optional<ResolvedFunction> resolveFunctionFlow(String flowspec) {
String strictSpec = flowspec.startsWith("compose ") ? flowspec.substring(8) : flowspec;
VirtDataDSL.ParseResult parseResult = VirtDataDSL.parse(strictSpec);
if (parseResult.throwable != null) {
throw new RuntimeException(parseResult.throwable);
}
VirtDataFlow flow = parseResult.flow;
return resolveFunctionFlow(flow);
}
public ResolverDiagnostics resolveDiagnosticFunctionFlow(String flowspec) {
String strictSpec = flowspec.startsWith("compose ") ? flowspec.substring(8) : flowspec;
VirtDataDSL.ParseResult parseResult = VirtDataDSL.parse(strictSpec);
if (parseResult.throwable != null) {
throw new RuntimeException(parseResult.throwable);
}
VirtDataFlow flow = parseResult.flow;
return resolveDiagnosticFunctionFlow(flow);
}
public ResolverDiagnostics resolveDiagnosticFunctionFlow(VirtDataFlow flow) {
ResolverDiagnostics diagnostics = new ResolverDiagnostics();
diagnostics.trace("processing flow " + flow.toString() + " from output to input");
LinkedList<List<ResolvedFunction>> funcs = new LinkedList<>();
LinkedList<Set<Class<?>>> nextFunctionInputTypes = new LinkedList<>();
Optional<Class<?>> finalValueTypeOption =
Optional.ofNullable(flow.getLastExpression().getCall().getOutputType())
.map(ValueType::valueOfClassName).map(ValueType::getValueClass);
nextFunctionInputTypes.add(new HashSet<>());
finalValueTypeOption.ifPresent(t -> nextFunctionInputTypes.get(0).add(t));
diagnostics.trace("working backwards from " + (flow.getExpressions().size()-1));
for (int i = flow.getExpressions().size() - 1; i >= 0; i--) {
FunctionCall call = flow.getExpressions().get(i).getCall();
diagnostics.trace("resolving args for " + call.toString());
List<ResolvedFunction> nodeFunctions = new LinkedList<>();
String funcName = call.getFunctionName();
Class<?> inputType = ValueType.classOfType(call.getInputType());
Class<?> outputType = ValueType.classOfType(call.getOutputType());
Object[] args = call.getArguments();
try {
args = populateFunctions(diagnostics, args, this.customElements);
} catch (Exception e) {
return diagnostics.error(e);
}
diagnostics.trace("resolved args: ");
for (Object arg : args) {
diagnostics.trace(" " + arg.getClass().getSimpleName() + ": " + arg.toString());
}
List<ResolvedFunction> resolved = functionLibrary.resolveFunctions(outputType, inputType, funcName, this.customElements,args);
if (resolved.size() == 0) {
return diagnostics.error(new RuntimeException("Unable to find even one function for " + call));
}
diagnostics.trace(" resolved functions:");
diagnostics.trace(summarize(resolved));
nodeFunctions.addAll(resolved);
funcs.addFirst(nodeFunctions);
Set<Class<?>> inputTypes = nodeFunctions.stream().map(ResolvedFunction::getInputClass).collect(Collectors.toSet());
nextFunctionInputTypes.addFirst(inputTypes);
}
if (!nextFunctionInputTypes.peekFirst().contains(Long.TYPE)) {
return diagnostics.error(new RuntimeException("There is no initial function which accepts a long input. Function chain, after type filtering: \n" + summarizeBulk(funcs)));
}
removeNonLongFunctions(funcs.getFirst());
List<ResolvedFunction> flattenedFuncs = optimizePath(funcs, ValueType.classOfType(flow.getLastExpression().getCall().getOutputType()));
if (flattenedFuncs.size() == 1) {
diagnostics.trace("FUNCTION resolution succeeded (single): '" + flow.toString() + "'");
return diagnostics.setResolvedFunction(flattenedFuncs.get(0));
}
FunctionAssembly assembly = new FunctionAssembly();
diagnostics.trace("composed summary: " + summarize(flattenedFuncs));
boolean isThreadSafe = true;
diagnostics.trace("FUNCTION chain selected: (multi) '" + this.summarize(flattenedFuncs) + "'");
for (ResolvedFunction resolvedFunction : flattenedFuncs) {
try {
Object functionObject = resolvedFunction.getFunctionObject();
assembly.andThen(functionObject);
if (!resolvedFunction.isThreadSafe()) {
isThreadSafe = false;
}
} catch (Exception e) {
String flowdata = flow!=null? flow.toString() : "undefined";
return diagnostics.error(new RuntimeException("FUNCTION resolution failed: '" + flowdata + "': " + e.toString()));
}
}
ResolvedFunction composedFunction = assembly.getResolvedFunction(isThreadSafe);
diagnostics.trace("FUNCTION resolution succeeded (lambda): '" + flow.toString() + "'");
return diagnostics.setResolvedFunction(composedFunction);
}
public Optional<ResolvedFunction> resolveFunctionFlow(VirtDataFlow flow) {
ResolverDiagnostics resolverDiagnostics = resolveDiagnosticFunctionFlow(flow);
return resolverDiagnostics.getResolvedFunction();
}
private Object[] populateFunctions(ResolverDiagnostics diagnostics, Object[] args, Map<String,?> cconfig) {
for (int i = 0; i < args.length; i++) {
Object o = args[i];
if (o instanceof FunctionCall) {
FunctionCall call = (FunctionCall) o;
String funcName = call.getFunctionName();
Class<?> inputType = ValueType.classOfType(call.getInputType());
Class<?> outputType = ValueType.classOfType(call.getOutputType());
Object[] fargs = call.getArguments();
diagnostics.trace("resolving argument as function '" + call.toString() + "'");
fargs = populateFunctions(diagnostics, fargs, cconfig);
List<ResolvedFunction> resolved = functionLibrary.resolveFunctions(outputType, inputType, funcName, cconfig, fargs);
if (resolved.size() == 0) {
throw new RuntimeException("Unable to resolve even one function for argument: " + call);
}
args[i] = resolved.get(0).getFunctionObject();
}
}
return args;
}
private void removeNonLongFunctions(List<ResolvedFunction> funcs) {
List<ResolvedFunction> toRemove = new LinkedList<>();
for (ResolvedFunction func : funcs) {
if (!func.getInputClass().isAssignableFrom(long.class)) {
logger.trace("input type " + func.getInputClass().getCanonicalName() + " is not assignable from long");
toRemove.add(func);
}
}
if (toRemove.size() > 0 && toRemove.size() == funcs.size()) {
throw new RuntimeException("removeNonLongFunctions would remove all functions: " + funcs);
}
funcs.removeAll(toRemove);
}
private String summarize(List<ResolvedFunction> funcs) {
return funcs.stream()
.map(String::valueOf).collect(Collectors.joining("|"));
}
private String summarizeBulk(List<List<ResolvedFunction>> funcs) {
List<List<String>> spans = new LinkedList<>();
funcs.forEach(l -> spans.add(l.stream().map(String::valueOf).collect(Collectors.toList())));
List<Optional<Integer>> widths = spans.stream().map(
l -> l.stream().map(String::length).max(Integer::compare)).collect(Collectors.toList());
String funcsdata = spans.stream().map(
l -> l.stream().map(String::valueOf).collect(Collectors.joining("|\n"))
).collect(Collectors.joining("\n\n"));
StringBuilder sb = new StringBuilder();
sb.append("---\\\\\n").append(funcsdata).append("\n---////\n");
return sb.toString();
}
/**
* <p>
* Attempt path optimizations on each phase junction, considering the set of
* candidate inner functions with the candidate outer functions.
* This is an iterative process, that will keep trying until no apparent
* progress is made. Each higher-precedence optimization strategy is used
* iteratively as long as it makes progress and then the lower precedence
* strategies are allowed to have their turn.
* </p>
* <p>
* <p>It is considered an error if the strategies are unable to reduce each
* phase down to a single preferred function. Therefore, the lowest precedence
* strategy is the most aggressive, simply sorting the functions by basic
* type preference and then removing all but the highest selected function.</p>
*
* @param funcs the list of candidate functions offered at each phase, in List&lt;List&gt; form.
* @return a List of resolved functions that has been fully optimized
*/
private List<ResolvedFunction> optimizePath(List<List<ResolvedFunction>> funcs, Class<?> type) {
List<ResolvedFunction> prevFuncs = null;
List<ResolvedFunction> nextFuncs = null;
int progress = -1;
int pass = 0;
while (progress != 0) {
pass++;
progress = 0;
progress += reduceByRequiredResultsType(funcs.get(funcs.size() - 1), type);
if (funcs.size() > 1) {
int stage = 0;
for (List<ResolvedFunction> funcList : funcs) {
stage++;
nextFuncs = funcList;
if (prevFuncs != null && nextFuncs != null) {
if (progress == 0) {
progress += reduceByDirectTypes(prevFuncs, nextFuncs);
if (progress == 0) {
progress += reduceByAssignableTypes(prevFuncs, nextFuncs, false);
if (progress == 0) {
progress += reduceByAssignableTypes(prevFuncs, nextFuncs, true);
if (progress == 0) {
progress += reduceByPreferredTypes(prevFuncs, nextFuncs);
}
}
}
}
} // else first pass, prime pointers
prevFuncs = nextFuncs;
}
nextFuncs = null;
prevFuncs = null;
} else {
progress += reduceByPreferredResultTypes(funcs.get(0));
}
}
List<ResolvedFunction> optimized = funcs.stream().map(l -> l.get(0)).collect(Collectors.toList());
return optimized;
}
private int reduceByRequiredResultsType(List<ResolvedFunction> endFuncs, Class<?> resultType) {
int progressed = 0;
LinkedList<ResolvedFunction> tmpList = new LinkedList<>(endFuncs);
for (ResolvedFunction endFunc : tmpList) {
if (resultType != null && !ClassUtils.isAssignable(endFunc.getResultClass(), resultType, true)) {
endFuncs.remove(endFunc);
String logmsg = "BY-REQUIRED-RESULT-TYPE removed function '" + endFunc + "' because is not assignable to " + resultType;
logger.trace(logmsg);
progressed++;
}
}
if (endFuncs.size() == 0) {
throw new RuntimeException("BY-REQUIRED-RESULT-TYPE No end funcs were found which are assignable to " + resultType);
}
return progressed;
}
private int reduceByPreferredResultTypes(List<ResolvedFunction> funcs) {
int progressed = 0;
if (funcs.size() > 1) {
progressed += funcs.size() - 1;
funcs.sort(ResolvedFunction.PREFERRED_TYPE_COMPARATOR);
while (funcs.size() > 1) {
logger.trace("BY-SINGLE-PREFERRED-TYPE removing func " + funcs.get(funcs.size() - 1)
+ " because " + funcs.get(0) + " has more preferred types.");
funcs.remove(funcs.size() - 1);
}
}
return progressed;
}
private int reduceByPreferredTypes(List<ResolvedFunction> prevFuncs, List<ResolvedFunction> nextFuncs) {
int progressed = 0;
if (prevFuncs.size() > 1) {
progressed += prevFuncs.size() - 1;
prevFuncs.sort(ResolvedFunction.PREFERRED_TYPE_COMPARATOR);
while (prevFuncs.size() > 1) {
String logmsg = "BY-PREV-PREFERRED-TYPE removing func " + prevFuncs.get(prevFuncs.size() - 1)
+ " because " + prevFuncs.get(0) + " has more preferred types.";
logger.trace(logmsg);
prevFuncs.remove(prevFuncs.size() - 1);
}
} else if (nextFuncs.size() > 1) {
progressed += nextFuncs.size() - 1;
nextFuncs.sort(ResolvedFunction.PREFERRED_TYPE_COMPARATOR);
while (nextFuncs.size() > 1) {
String logmsg = "BY-NEXT-PREFERRED-TYPE removing func " + nextFuncs.get(nextFuncs.size() - 1)
+ " because " + nextFuncs.get(0) + " has more preferred types.";
logger.trace(logmsg);
nextFuncs.remove(nextFuncs.size() - 1);
}
}
return progressed;
}
/**
* If there are direct type matches between the inner func and the outer func, then remove all
* other outer funcs except the ones with direct matches.
*
* @param prevFuncs The list of candidate inner functions
* @param nextFuncs The list of candidate outer functions
* @return count of items removed
*/
private int reduceByDirectTypes(List<ResolvedFunction> prevFuncs, List<ResolvedFunction> nextFuncs) {
int progressed = 0;
// Rule 1: If there are direct type matches, remove extraneous next funcs
Set<Class<?>> outputs = getOutputs(prevFuncs);
Set<Class<?>> inputs = getInputs(nextFuncs);
Set<Class<?>> directMatches =
inputs.stream().filter(outputs::contains).collect(Collectors.toCollection(HashSet::new));
if (directMatches.size() > 0) {
List<ResolvedFunction> toremove = new ArrayList<>();
for (ResolvedFunction nextFunc : nextFuncs) {
if (!directMatches.contains(nextFunc.getArgType())) {
String logmsg = "BY-DIRECT-TYPE removing next func: " + nextFunc + " because its input types are not satisfied by any previous func";
logger.trace(logmsg);
toremove.add(nextFunc);
progressed++;
}
}
nextFuncs.removeAll(toremove);
}
return progressed;
}
/**
* Remove any functions in the second set which do not have an input type which is assignable
* from any of the output types of the functions in the first set.
*
* @param prevFuncs the functions that come before the nextFuncs
* @param nextFuncs the functions that come after prevFuncs
* @return the number of next funcs that have been removed
*/
private int reduceByAssignableTypes(List<ResolvedFunction> prevFuncs, List<ResolvedFunction> nextFuncs, boolean autoboxing) {
// Rule 1: If there are direct type matches, remove extraneous next funcs
Set<Class<?>> outputs = getOutputs(prevFuncs);
Set<Class<?>> inputs = getInputs(nextFuncs);
Set<Class<?>> compatibleInputs = new HashSet<>();
for (Class<?> input : inputs) {
for (Class<?> output : outputs) {
if (ClassUtils.isAssignable(output, input, autoboxing)) {
compatibleInputs.add(input);
}
}
}
List<ResolvedFunction> toremove = new ArrayList<>();
for (ResolvedFunction nextfunc : nextFuncs) {
if (!compatibleInputs.contains(nextfunc.getInputClass())) {
toremove.add(nextfunc);
}
}
if (toremove.size() == nextFuncs.size()) {
String logmsg = "BY-ASSIGNABLE-TYPE Not removing remaining " + nextFuncs.size() + " next funcs " + (autoboxing ? "with autoboxing " : "") + "because no functions would be left.";
logger.trace(logmsg);
return 0;
} else {
toremove.forEach(nextfunc -> {
String logmsg = "BY-ASSIGNABLE-TYPE removing next func: " + nextfunc + " because its input types are not assignable from any of the previous funcs";
logger.trace(logmsg);
}
);
nextFuncs.removeAll(toremove);
return toremove.size();
}
}
private Set<Class<?>> getOutputs(List<ResolvedFunction> prevFuncs) {
Set<Class<?>> outputs = new HashSet<>();
for (ResolvedFunction func : prevFuncs) {
outputs.add(func.getResultClass());
}
return outputs;
}
private Set<Class<?>> getInputs(List<ResolvedFunction> nextFuncs) {
Set<Class<?>> inputs = new HashSet<>();
for (ResolvedFunction nextFunc : nextFuncs) {
inputs.add(nextFunc.getArgType());
}
return inputs;
}
public Map<String,?> getCustomElements() {
return this.customElements;
}
public VirtDataComposer addCustomElement(String name, Object element) {
this.customElements.put(name, element);
return this;
}
public VirtDataComposer addCustomElements(Map<String, ?> config) {
this.customElements.putAll(config);
return this;
}
}

View File

@ -0,0 +1,48 @@
package io.virtdata.core;
import io.virtdata.processors.DocFuncData;
import io.virtdata.processors.FunctionDocInfoProcessor;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.util.ArrayList;
import java.util.List;
/**
* This is the top-level API supporting access to the documentation models
* for all known {@link io.virtdata.annotations.ThreadSafeMapper} and
* {@link io.virtdata.annotations.PerThreadMapper} instances in the runtime.
*/
public class VirtDataDocs {
private final static MethodHandles.Lookup lookup = MethodHandles.publicLookup();
public static List<String> getAllNames() {
VirtDataFunctionFinder finder = new VirtDataFunctionFinder();
return finder.getFunctionNames();
}
public static List<DocFuncData> getAllDocs() {
VirtDataFunctionFinder finder = new VirtDataFunctionFinder();
List<String> functionNames = finder.getFunctionNames();
List<DocFuncData> docs = new ArrayList<>();
try {
for (String n : functionNames) {
String s = n + FunctionDocInfoProcessor.AUTOSUFFIX;
Class<?> aClass = Class.forName(s);
MethodHandle constructor = lookup.findConstructor(aClass, MethodType.methodType(Void.TYPE));
Object o = constructor.invoke();
if (DocFuncData.class.isAssignableFrom(o.getClass())) {
docs.add(DocFuncData.class.cast(o));
} else {
throw new RuntimeException("class " + o.getClass() + " could not be assigned to " + DocFuncData.class.getSimpleName());
}
}
} catch (Throwable e) {
throw new RuntimeException("Error while loading doc models:" + e.toString());
}
return docs;
}
}

View File

@ -0,0 +1,22 @@
package io.virtdata.core;
import io.virtdata.processors.DocFuncData;
import java.util.ArrayList;
import java.util.List;
import java.util.ServiceLoader;
import java.util.stream.Collectors;
public class VirtDataFunctionFinder {
public VirtDataFunctionFinder() {
}
public List<String> getFunctionNames() {
ServiceLoader<DocFuncData> loader =ServiceLoader.load(DocFuncData.class);
List<String> names = new ArrayList<>();
loader.iterator().forEachRemaining(d -> names.add(d.getPackageName() + "." + d.getClassName()));
List<String> cleaned = names.stream().sorted().distinct().collect(Collectors.toList());
return cleaned;
}
}

View File

@ -0,0 +1,252 @@
package io.virtdata.core;
import io.virtdata.annotations.ThreadSafeMapper;
import io.virtdata.api.config.ConfigAware;
import org.apache.commons.lang3.ClassUtils;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.lang.invoke.MethodHandle;
import java.lang.invoke.MethodHandles;
import java.lang.invoke.MethodType;
import java.lang.reflect.Constructor;
import java.lang.reflect.Method;
import java.lang.reflect.Modifier;
import java.util.*;
import java.util.stream.Collectors;
public class VirtDataFunctionResolver {
private final static Logger logger = LogManager.getLogger(VirtDataFunctionResolver.class);private final static MethodHandles.Lookup lookup = MethodHandles.publicLookup();
private final VirtDataFunctionFinder virtDataFunctionFinder = new VirtDataFunctionFinder();
public List<ResolvedFunction> resolveFunctions(Class<?> returnType, Class<?> inputType, String functionName, Map<String,?> customParameters, Object... parameters) {
// TODO: Make this look for both assignment compatible matches as well as exact assignment matches, and only
// TODO: return assignment compatible matches when there are none exact matching.
// TODO: Further, make lambda construction honor exact matches first as well.
Class<?>[] parameterTypes = new Class<?>[parameters.length];
for (int i = 0; i < parameters.length; i++) {
parameterTypes[i] = parameters[i].getClass();
}
List<ResolvedFunction> resolvedFunctions = new ArrayList<>();
List<Class<?>> matchingClasses = virtDataFunctionFinder.getFunctionNames()
.stream()
.filter(s -> s.endsWith("." + functionName))
.map(this::maybeClassForName)
.filter(Objects::nonNull)
.collect(Collectors.toList());
List<Constructor<?>> matchingConstructors = null;
matchingConstructors = matchingClasses.stream()
.filter(c -> {
// This form for debugging
boolean isFunctional = isFunctionalInterface(c);
boolean canAssignInput = inputType == null || canAssignInputType(c, inputType);
boolean canAssignReturn = returnType == null || canAssignReturnType(c, returnType);
boolean matchesSignature = isFunctional && canAssignInput && canAssignReturn;
return matchesSignature;
})
.flatMap(c -> Arrays.stream(c.getDeclaredConstructors()))
.filter(c -> {
Class<?>[] ctypes = c.getParameterTypes();
if (c.isVarArgs()) {
int commonLen=Math.min(ctypes.length-1,parameters.length);
Class<?>[] paramNonVarArgs = Arrays.copyOfRange(parameterTypes, 0, commonLen);
Class<?>[] ctorNonVarArgs = Arrays.copyOfRange(ctypes, 0, commonLen);
if (parameters.length< (ctypes).length-1) {
return false;
}
if (!ClassUtils.isAssignable(paramNonVarArgs, ctorNonVarArgs, true)) {
return false;
}
Class<?> componentType = ctypes[ctypes.length - 1].getComponentType();
if (parameterTypes.length >= ctypes.length && !ClassUtils.isAssignable(parameterTypes[ctypes.length - 1], componentType, true)) {
return false;
}
return true;
} else {
if (parameterTypes.length!=ctypes.length) {
return false;
}
return ClassUtils.isAssignable(parameterTypes, ctypes, true);
}
})
// .map(c -> {
// try {
// return lookup.findConstructor(c, MethodType.methodType(void.class, parameterTypes));
// } catch (NoSuchMethodException | IllegalAccessException e) {
// throw new RuntimeException(e);
// }
// })
.collect(Collectors.toList());
if (returnType != null && inputType != null && matchingConstructors.size() > 1) {
throw new RuntimeException(
"found more than one (" + matchingConstructors.size() + ") matching constructor for " +
"return type '" + returnType + "', " +
"inputType '" + inputType + "', " +
"function name '" + functionName + ", " +
"and parameter types '" + Arrays.toString(parameters) + "', " +
"ctors: " + matchingConstructors);
}
for (Constructor<?> ctor : matchingConstructors) {
try {
Class<?> ctorDClass = ctor.getDeclaringClass();
MethodType ctorMethodType = MethodType.methodType(void.class, ctor.getParameterTypes());
MethodHandle constructor = lookup.findConstructor(ctorDClass, ctorMethodType);
Object functionalInstance = constructor.invokeWithArguments(parameters);
if (functionalInstance instanceof ConfigAware) {
((ConfigAware)functionalInstance).applyConfig(customParameters);
}
boolean threadSafe = functionalInstance.getClass().getAnnotation(ThreadSafeMapper.class) != null;
resolvedFunctions.add(
new ResolvedFunction(
functionalInstance,
threadSafe,
parameterTypes,
parameters,
getInputClass(functionalInstance.getClass()),
getOutputClass(functionalInstance.getClass())
)
);
} catch (Throwable throwable) {
throw new RuntimeException(throwable);
}
}
return resolvedFunctions;
}
private boolean isFunctionalInterface(Class<?> c) {
Optional<Method> applyMethods = Arrays.stream(c.getMethods())
.filter(m -> {
boolean isNotDefault = !m.isDefault();
boolean isNotBridge = !m.isBridge();
boolean isNotSynthetic = !m.isSynthetic();
boolean isPublic = (m.getModifiers() & Modifier.PUBLIC) > 0;
boolean isNotString = !m.getName().equals("toString");
boolean isApplyMethod = m.getName().startsWith("apply");
boolean isFunctional = isNotDefault && isNotBridge && isNotSynthetic && isPublic && isNotString && isApplyMethod;
return isFunctional;
})
.findFirst();
return applyMethods.isPresent();
}
private boolean canAssignArguments(Constructor<?> targetCtor, Object[] sourceParameters) {
boolean isAssignable = true;
Class<?>[] targetTypes = targetCtor.getParameterTypes();
if (targetCtor.isVarArgs()) {
if (sourceParameters.length < (targetTypes.length - 1)) {
logger.trace(targetCtor.toString() + " (varargs) does not match, not enough source parameters: " + Arrays.toString(sourceParameters));
return false;
}
} else if (sourceParameters.length != targetTypes.length) {
logger.trace(targetCtor.toString() + " (varargs) does not match source parameters (size): " + Arrays.toString(sourceParameters));
return false;
}
Class<?>[] sourceTypes = new Class<?>[sourceParameters.length];
for (int i = 0; i < sourceTypes.length; i++) {
sourceTypes[i] = sourceParameters[i].getClass();
}
if (targetCtor.isVarArgs()) {
for (int i = 0; i < targetTypes.length - 1; i++) {
if (!ClassUtils.isAssignable(sourceTypes[i], targetTypes[i])) {
isAssignable = false;
break;
}
}
Class<?> componentType = targetTypes[targetTypes.length - 1].getComponentType();
for (int i = targetTypes.length - 1; i < sourceTypes.length; i++) {
if (!ClassUtils.isAssignable(sourceTypes[i], componentType, true)) {
isAssignable = false;
break;
}
}
} else {
for (int i = 0; i < targetTypes.length; i++) {
if (!ClassUtils.isAssignable(sourceTypes[i], targetTypes[i])) {
isAssignable = false;
break;
}
}
//
// isAssignable = ClassUtils.isAssignable(sourceTypes, targetTypes, true);
}
return isAssignable;
}
private boolean canAssignReturnType(Class<?> functionalClass, Class<?> returnType) {
Class<?> sourceType = toFunctionalMethod(functionalClass).getReturnType();
boolean isAssignable = returnType.isAssignableFrom(sourceType);
return isAssignable;
}
private Class<?> getInputClass(Class<?> functionalClass) {
return toFunctionalMethod(functionalClass).getParameterTypes()[0];
}
private Class<?> getOutputClass(Class<?> functionClass) {
return toFunctionalMethod(functionClass).getReturnType();
}
private boolean canAssignInputType(Class<?> functionalClass, Class<?> inputType) {
boolean isAssignable = toFunctionalMethod(functionalClass).getParameterTypes()[0].isAssignableFrom(inputType);
return isAssignable;
}
private Class<?> maybeClassForName(String className) {
try {
return Class.forName(className);
} catch (Exception e) {
return null;
}
}
private Method toFunctionalMethod(Class<?> clazz) {
Optional<Method> foundMethod = Arrays.stream(clazz.getMethods())
.filter(m -> !m.isDefault() && !m.isBridge() && !m.isSynthetic())
.filter(m -> m.getName().startsWith("apply"))
.findFirst();
return foundMethod.orElseThrow(
() -> new RuntimeException(
"Unable to find the function method on " + clazz.getCanonicalName()
)
);
}
public List<String> getFunctionNames() {
return virtDataFunctionFinder.getFunctionNames();
}
// public List<DocFuncData> getDocModels() {
// List<String> classes= virtDataFunctionFinder.getFunctionNames().stream().map(s -> s+"DocInfo").collect(Collectors.toList());
// List<DocFuncData> docFuncData = new ArrayList<>(classes.size());
// for (String aClass : classes) {
// try {
// Class<?> docClass = Class.forName(aClass);
// if (DocFuncData.class.isAssignableFrom(docClass)) {
// DocFuncData dfd = DocFuncData.class.cast(docClass);
// docFuncData.add(dfd);
// } else {
// throw new RuntimeException("Unable to cast " + docClass.getCanonicalName() + " to class DocFuncData");
// }
// } catch (ClassNotFoundException e) {
// throw new RuntimeException(e);
// }
// }
// return docFuncData;
// }
}

View File

@ -0,0 +1,49 @@
package io.virtdata.core;
import io.virtdata.api.DataMapper;
import io.virtdata.api.VirtDataFunctionLibrary;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
public class VirtDataLibraries implements VirtDataFunctionLibrary {
private final static Logger logger = LogManager.getLogger(VirtDataLibraries.class);private static VirtDataLibraries instance = new VirtDataLibraries();
private final Map<String,DataMapper<?>> threadSafeCache = new HashMap<>();
private final VirtDataFunctionResolver resolver = new VirtDataFunctionResolver();
public static VirtDataLibraries get() {
return instance;
}
private VirtDataLibraries() {
}
@Override
public String getName() {
return "ALL";
}
@Override
public List<ResolvedFunction> resolveFunctions(
Class<?> returnType,
Class<?> inputType,
String functionName,
Map<String,?> customConfig,
Object... parameters)
{
List<ResolvedFunction> resolvedFunctions = new ArrayList<>();
List<ResolvedFunction> resolved = resolver.resolveFunctions(returnType, inputType, functionName, customConfig, parameters);
// Written this way to allow for easy debugging and understanding, do not convert to .stream()...
if (resolved.size()>0) {
resolvedFunctions.addAll(resolved);
}
return resolvedFunctions;
}
}

View File

@ -0,0 +1,16 @@
package io.virtdata.core;
import io.virtdata.api.VirtDataFunctionLibrary;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
public interface VirtDataLibrary {
final static Logger logger = LogManager.getLogger(VirtDataLibrary.class);
VirtDataFunctionLibrary getFunctionLibrary();
String getLibname();
BindingsTemplate getBindingsTemplate(String... namesAndSpecs);
}

View File

@ -0,0 +1,52 @@
/*
* Copyright (C) 2014-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.virtdata.core.murmur;
import java.math.BigInteger;
import java.util.zip.Checksum;
/**
* Checksum interface to access 128 bit in various ways.
*/
public interface Checksum128 extends Checksum {
/**
* @return Returns the higher 64 bits of the 128 bit hash.
*/
long getValueHigh();
/**
* @return Positive value.
*/
BigInteger getValueBigInteger();
/**
* @return Padded with leading 0s to ensure length of 32.
*/
String getValueHexString();
/**
* Big endian is the default in Java / network byte order.
* @return Big Endian bytes
*/
byte[] getValueBytesBigEndian();
/**
* Big endian is used by most machines natively.
* @return Little Endian bytes
*/
byte[] getValueBytesLittleEndian();
}

View File

@ -0,0 +1,335 @@
/*
* Copyright (C) 2014-2016 Markus Junginger, greenrobot (http://greenrobot.org)
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package io.virtdata.core.murmur;
import java.math.BigInteger;
/** Murmur3F (MurmurHash3_x64_128) */
public class Murmur3F implements Checksum128 {
private static final long C1 = 0x87c37b91114253d5L;
private static final long C2 = 0x4cf5ad432745937fL;
private final long seed;
private long h1;
private long h2;
private int length;
private int partialPos;
private long partialK1;
private long partialK2;
private boolean finished;
private long finishedH1;
private long finishedH2;
/**
* This constructor allows you to require that an unsafe implementation of
* primitive array operations is used, for added speed on platforms that you
* know can support it. This allows callers to have an easy way to
* exclusively opt in or out of unsafe behavior at a class-loader level,
* rather than forcing an unsafe behavior before the caller gets a chance
* to intervene. The choice is either/or, not "optional, but fall back if not
* supported." Callers can instrument for this with exception handling if it
* is needed. Effectively, setting the unsafe value chooses an implementation.
*
* @param seed A seed to initialize this hash with, or the input when using it
* as a function.
* @param unsafe Whether to require that the implementation relies on an unsafe
* calls.
*/
public Murmur3F(int seed, boolean unsafe) {
this.seed = seed & 0xffffffffL;
h1 = h2 = this.seed;
}
public Murmur3F() {
this(0,false);
}
public Murmur3F(int seed) {
this(seed,false);
}
@Override
public void update(int b) {
finished = false;
switch (partialPos) {
case 0:
partialK1 = 0xff & b;
break;
case 1:
partialK1 |= (0xff & b) << 8;
break;
case 2:
partialK1 |= (0xff & b) << 16;
break;
case 3:
partialK1 |= (0xffL & b) << 24;
break;
case 4:
partialK1 |= (0xffL & b) << 32;
break;
case 5:
partialK1 |= (0xffL & b) << 40;
break;
case 6:
partialK1 |= (0xffL & b) << 48;
break;
case 7:
partialK1 |= (0xffL & b) << 56;
break;
case 8:
partialK2 = 0xff & b;
break;
case 9:
partialK2 |= (0xff & b) << 8;
break;
case 10:
partialK2 |= (0xff & b) << 16;
break;
case 11:
partialK2 |= (0xffL & b) << 24;
break;
case 12:
partialK2 |= (0xffL & b) << 32;
break;
case 13:
partialK2 |= (0xffL & b) << 40;
break;
case 14:
partialK2 |= (0xffL & b) << 48;
break;
case 15:
partialK2 |= (0xffL & b) << 56;
break;
}
partialPos++;
if (partialPos == 16) {
applyKs(partialK1, partialK2);
partialPos = 0;
}
length++;
}
/**
* Special update method to hash long values very efficiently using Java's native little endian (LE) byte order.
* Note, that you cannot mix this with other (previous) hash updates, because it only supports 8-bytes alignment.
*/
public void updateLongLE(long value) {
finished = false;
switch (partialPos) {
case 0:
partialK1 = value;
break;
case 8:
partialK2 = value;
break;
default:
throw new IllegalStateException("Cannot mix long with other alignments than 8: " + partialPos);
}
partialPos += 8;
if (partialPos == 16) {
applyKs(partialK1, partialK2);
partialPos = 0;
}
length += 8;
}
/**
* Consider {@link #updateLongLE(long)} for better performance if you do not rely on big endian (BE) byte order.
*/
public void updateLongBE(long value) {
updateLongLE(Long.reverseBytes(value));
}
public void update(byte[] b) {
update(b, 0, b.length);
}
@Override
public void update(byte[] b, int off, int len) {
finished = false;
while (partialPos != 0 && len > 0) {
update(b[off]);
off++;
len--;
}
int remainder = len & 0xF;
int stop = off + len - remainder;
for (int i = off; i < stop; i += 16) {
long k1 = getLongLE(b, i);
long k2 = getLongLE(b, i + 8);
applyKs(k1, k2);
}
length += stop - off;
for (int i = 0; i < remainder; i++) {
update(b[stop + i]);
}
}
private void applyKs(long k1, long k2) {
k1 *= C1;
k1 = Long.rotateLeft(k1, 31);
k1 *= C2;
h1 ^= k1;
h1 = Long.rotateLeft(h1, 27);
h1 += h2;
h1 = h1 * 5 + 0x52dce729;
k2 *= C2;
k2 = Long.rotateLeft(k2, 33);
k2 *= C1;
h2 ^= k2;
h2 = Long.rotateLeft(h2, 31);
h2 += h1;
h2 = h2 * 5 + 0x38495ab5;
}
private void checkFinished() {
if (!finished) {
finished = true;
finishedH1 = h1;
finishedH2 = h2;
if (partialPos > 0) {
if (partialPos > 8) {
long k2 = partialK2 * C2;
k2 = Long.rotateLeft(k2, 33);
k2 *= C1;
finishedH2 ^= k2;
}
long k1 = partialK1 * C1;
k1 = Long.rotateLeft(k1, 31);
k1 *= C2;
finishedH1 ^= k1;
}
finishedH1 ^= length;
finishedH2 ^= length;
finishedH1 += finishedH2;
finishedH2 += finishedH1;
finishedH1 = fmix64(finishedH1);
finishedH2 = fmix64(finishedH2);
finishedH1 += finishedH2;
finishedH2 += finishedH1;
}
}
private long fmix64(long k) {
k ^= k >>> 33;
k *= 0xff51afd7ed558ccdL;
k ^= k >>> 33;
k *= 0xc4ceb9fe1a85ec53L;
k ^= k >>> 33;
return k;
}
@Override
/** Returns the lower 64 bits of the 128 bit hash (you can use just this value this as a 64 bit hash). */
public long getValue() {
checkFinished();
return finishedH1;
}
/** Returns the higher 64 bits of the 128 bit hash. */
public long getValueHigh() {
checkFinished();
return finishedH2;
}
/** Positive value. */
public BigInteger getValueBigInteger() {
byte[] bytes = getValueBytesBigEndian();
return new BigInteger(1, bytes);
}
/** Padded with leading 0s to ensure length of 32. */
public String getValueHexString() {
checkFinished();
return getPaddedHexString(finishedH2) + getPaddedHexString(finishedH1);
}
private String getPaddedHexString(long value) {
String string = Long.toHexString(value);
while (string.length() < 16) {
string = '0' + string;
}
return string;
}
public byte[] getValueBytesBigEndian() {
checkFinished();
byte[] bytes = new byte[16];
for (int i = 0; i < 8; i++) {
bytes[i] = (byte) ((finishedH2 >>> (56 - i * 8)) & 0xff);
}
for (int i = 0; i < 8; i++) {
bytes[8 + i] = (byte) ((finishedH1 >>> (56 - i * 8)) & 0xff);
}
return bytes;
}
public byte[] getValueBytesLittleEndian() {
checkFinished();
byte[] bytes = new byte[16];
for (int i = 0; i < 8; i++) {
bytes[i] = (byte) ((finishedH1 >>> (i * 8)) & 0xff);
}
for (int i = 0; i < 8; i++) {
bytes[8 + i] = (byte) ((finishedH2 >>> (i * 8)) & 0xff);
}
return bytes;
}
@Override
public void reset() {
h1 = h2 = seed;
length = 0;
partialPos = 0;
finished = false;
// The remainder is not really necessary, but looks nicer when debugging
partialK1 = partialK2 = 0;
finishedH1 = finishedH2 = 0;
}
private static long getLongBE(byte[] bytes, int index) {
return (bytes[index + 7] & 0xff) | ((bytes[index + 6] & 0xff) << 8) |
((bytes[index + 5] & 0xff) << 16) | ((bytes[index + 4] & 0xffL) << 24) |
((bytes[index + 3] & 0xffL) << 32) | ((bytes[index + 2] & 0xffL) << 40) |
((bytes[index + 1] & 0xffL) << 48) | (((long) bytes[index]) << 56);
}
private static long getLongLE(byte[] bytes, int index) {
return (bytes[index] & 0xff) | ((bytes[index + 1] & 0xff) << 8) |
((bytes[index + 2] & 0xff) << 16) | ((bytes[index + 3] & 0xffL) << 24) |
((bytes[index + 4] & 0xffL) << 32) | ((bytes[index + 5] & 0xffL) << 40) |
((bytes[index + 6] & 0xffL) << 48) | (((long) bytes[index + 7]) << 56);
}
}

View File

@ -0,0 +1,40 @@
package io.virtdata.templates;
import java.util.Objects;
public class BindPoint {
private String anchor;
private String bindspec;
public BindPoint(String anchor, String bindspec) {
this.anchor = anchor;
this.bindspec = bindspec;
}
public String getAnchor() {
return anchor;
}
public String getBindspec() {
return bindspec;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
BindPoint bindPoint = (BindPoint) o;
if (!Objects.equals(anchor, bindPoint.anchor)) return false;
return Objects.equals(bindspec, bindPoint.bindspec);
}
@Override
public String toString() {
return "BindPoint{" +
"anchor='" + anchor + '\'' +
", bindspec='" + bindspec + '\'' +
'}';
}
}

View File

@ -0,0 +1,31 @@
package io.virtdata.templates;
import io.virtdata.api.Binder;
import io.virtdata.core.Bindings;
public class CSVBindings implements Binder<String> {
private Bindings bindings;
private int bufferlen=0;
public CSVBindings(Bindings bindings) {
this.bindings = bindings;
}
@Override
public String bind(long value) {
Object[] all = bindings.getAll(value);
StringBuilder sb = new StringBuilder();
for (Object o : all) {
sb.append(o.toString());
sb.append(",");
}
sb.setLength(sb.length()-1);
if (sb.length()>bufferlen) {
bufferlen=sb.length()+5;
}
return sb.toString();
}
}

View File

@ -0,0 +1,18 @@
package io.virtdata.templates;
import io.virtdata.core.Bindings;
import io.virtdata.core.BindingsTemplate;
public class CSVBindingsTemplate {
private BindingsTemplate bindingsTemplate;
public CSVBindingsTemplate(BindingsTemplate bindingsTemplate) {
this.bindingsTemplate = bindingsTemplate;
}
public CSVBindings resolve() {
Bindings bindings = bindingsTemplate.resolveBindings();
return new CSVBindings(bindings);
}
}

View File

@ -0,0 +1,352 @@
/*
*
* Copyright 2016 jshook
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* /
*/
package io.virtdata.templates;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.security.InvalidParameterException;
import java.util.*;
import java.util.function.Function;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;
import java.util.stream.StreamSupport;
/**
* A parsed template is a form of a raw template which has been parsed for its
* named anchors and sanity checked against a set of provided bindings.
*
* Once the parsed template is constructed, the method {@link ParsedTemplate#orError()}
* should <em>always</em> called before it is used.
*
* <H2>Validity Checks</H2>
*
* A parsed template is considered to be valid if and only if the raw template contained only
* named anchors which were defined in the provided bindings. Extra bindings are not presumed
* to make a template invalid, but this interpretation is left to the caller for extra checks
* if needed.
*
* <H2>Parsed Details</H2>
* After parsing, the following details are available:
*
* <H3>Parsed Spans</H3>
* This is an alternating list of the literal sections of the raw template
* interspersed with the anchor names. This list always starts and ends with a literal section, so
* will always contain an odd number of elements. (some span sections may be empty if necessary, but
* not null)
*
* <H3>Specific Bindings</H3>
* These are the binding names and definitions which were used
* in a named anchor and also found in the provided bindings. If an anchor references
* a binding which is not provided, then it will <em>not</em> be in this map.
*
* <H3>Missing Bindings</H3>
* This is a list of binding names which were found in the
* raw template but which were not found in the provided bindings by name.
*
* <H3>Extra Bindings</H3>
* This is a list of binding names which were provided by the user, but which were not used in the raw template by name.
*/
public class ParsedTemplate {
/**
* The default patterns match one of two forms:
* <UL>
* <LI>an opening curly brace, followed by a word character, followed by any contiguous
* combination of dashes, underscores, digits, words, and dots, followed by
* a closing curly brace.</LI>
* <LI>A question mark, followed by a word character, followed by any contiguous
* combination of dashes, underscores, digits, word characters, or dots.</LI>
* </UL>
*
* <H2>Examples</H2>
* <pre>
* {var1}
* {var2.var3__-var5}
* ?var6
* ?var7.__var8-var9
* </pre>
*/
private final static Pattern[] DEFAULT_PATTERNS = new Pattern[]{
Pattern.compile("\\{(?<anchor>\\w+[-_\\d\\w.]*)}"),
Pattern.compile("\\?(?<anchor>\\w+[-_\\d\\w.]*)")
};
private final static Logger logger = LogManager.getLogger(ParsedTemplate.class);private final Pattern[] patterns;
// Spans is an even-odd form of (literal, variable, ..., ..., literal)
private final String rawtemplate;
private final String[] spans;
private final Set<String> missingBindings = new HashSet<>();
private final Set<String> extraBindings = new HashSet<>();
private final Map<String, String> bindings = new LinkedHashMap<>();
private final Map<String, String> specificBindings = new LinkedHashMap<>();
/**
* Construct a new ParsedTemplate from the provided statement template.
*
* @param rawtemplate The string that contains literal sections and anchor sections interspersed
* @param providedBindings The bindings that are provided for the template to be parsed
*/
public ParsedTemplate(String rawtemplate, Map<String, String> providedBindings) {
this(rawtemplate, providedBindings, DEFAULT_PATTERNS);
}
/**
* Parse the given raw template, check the bind points against the provide bindings, and
* provide detailed template checks for validity.
*
* <H2>Overriding Patterns</H2>
* <P>
* If patterns are not provided then {@link ParsedTemplate#DEFAULT_PATTERNS} are used, which includes
* the ability to match {var1} and ?var1 style anchors. If patterns are
* provided, then they must be compatible with the {@link Matcher#find()} method, and must also
* have a named group with the name 'anchor', as in (?&lt;anchor&gt;...)
* </P>
*
* @param rawtemplate A string template which contains optionally embedded named anchors
* @param providedBindings The bindings which are provided by the user to fulfill the named anchors in this raw template
* @param providedPatterns The patterns which match the named anchor format and extract anchor names from the raw template
*/
public ParsedTemplate(String rawtemplate, Map<String, String> providedBindings, Pattern... providedPatterns) {
this.rawtemplate = rawtemplate;
this.bindings.putAll(providedBindings);
this.patterns = providedPatterns;
this.spans = parse();
}
public ParsedTemplate orError() {
if (hasError()) {
throw new RuntimeException("Unable to parse statement: " + this.toString());
}
return this;
}
/**
* After this method runs, the following conditions should apply:
* <ul>
* <li>spans will contain all the literal and variable sections in order, starting a literal, even if it is empty</li>
* <li>spans will be an odd number in length, meaning that the last section will also be a literal, even if it is empty</li>
* <li>specificBindings will contain an ordered map of the binding definitions</li>
* </ul>
*/
private String[] parse() {
List<String> spans = new ArrayList<>();
Set<String> usedAnchors = new HashSet<>();
extraBindings.addAll(bindings.keySet());
String statement = rawtemplate;
int patternsMatched = 0;
int lastMatch = 0;
for (Pattern pattern : patterns) {
if (!pattern.toString().contains("?<anchor>")) {
throw new InvalidParameterException("The provided pattern '" + pattern.toString() + "' must contain a named group called anchor," +
"as in '(?<anchor>...)'");
}
Matcher m = pattern.matcher(rawtemplate);
if (!m.find()) { // sanity check that this matcher works at all or go to the next pattern
continue;
}
while (m.find(lastMatch)) {
String pre = statement.substring(lastMatch, m.start());
spans.add(pre);
String tokenName = m.group("anchor");
lastMatch = m.end();
spans.add(tokenName);
if (extraBindings.contains(tokenName)) {
usedAnchors.add(tokenName);
specificBindings.put(tokenName, bindings.get(tokenName));
} else {
missingBindings.add(tokenName);
}
}
usedAnchors.forEach(extraBindings::remove);
break; // If the last matcher worked at all, only do one cycle
}
if (lastMatch >= 0) {
spans.add(statement.substring(lastMatch));
} else {
spans.add(statement);
}
return spans.toArray(new String[0]);
//
// //Matcher m = stmtToken.matcher(statement);
// int lastMatch = 0;
// String remainder = "";
// while (m.find(lastMatch)) {
// String pre = statement.substring(lastMatch, m.start());
//
// String form1 = m.group(1);
// String form2 = m.group(2);
// String tokenName = (form1 != null && !form1.isEmpty()) ? form1 : form2;
// lastMatch = m.end();
// spans.add(pre);
//
// if (extraBindings.contains(tokenName)) {
// anchors.add(tokenName);
// bindspecs.add(stmtDef.getBindings().get(tokenName));
// usedAnchors.add(tokenName);
//// specificBindings.put(tokenName, stmtDef.getBindings().get(tokenName));
// } else {
// missingBindings.add(tokenName);
// }
// }
// usedAnchors.forEach(extraBindings::remove);
//
// if (lastMatch >= 0) {
// spans.add(statement.substring(lastMatch));
// } else {
// spans.add(statement);
// }
//
// return spans.toArray(new String[0]);
}
public String toString() {
StringBuilder sb = new StringBuilder();
sb.append("template: '").append(rawtemplate).append("'");
sb.append("\n parsed: ");
sb.append(StreamSupport.stream(Arrays.spliterator(spans), false)
.map(s -> "[" + s + "]").collect(Collectors.joining(",")));
sb.append("\n missing bindings: ")
.append(missingBindings.stream().collect(Collectors.joining(",", "[", "]")));
sb.append(" extra bindings: ");
sb.append("\n extra bindings: ")
.append(extraBindings.stream().collect(Collectors.joining(",", "[", "]")));
return sb.toString();
}
/**
* @return true if the parsed statement is not usable.
*/
public boolean hasError() {
return missingBindings.size() > 0;
}
/**
* The list of binding names returned by this method does not
* constitute an error. They may be used for
* for informational purposes in error handlers, for example.
*
* @return a set of bindings names which were provided to
* this parsed statement, but which were not referenced
* in either <pre>{anchor}</pre> or <pre>?anchor</pre> form.
*/
public Set<String> getExtraBindings() {
return extraBindings;
}
/**
* Returns a list of binding names which were referenced
* in either <pre>{anchor}</pre> or <pre>?anchor</pre> form,
* but which were not present in the provided bindings map.
* If any binding names are present in the returned set, then
* this binding will not be usable.
*
* @return A list of binding names which were referenced but not defined*
*/
public Set<String> getMissingBindings() {
return missingBindings;
}
/**
* Return a map of bindings which were referenced in the statement.
* This is an easy way to get the list of effective bindings for
* a statement for diagnostic purposes without including a potentially
* long list of library bindings. This method does <em>not</em>
* represent all of the binding points, as when anchor names are
* used more than once.
*
* @return a bindings map of referenced bindings in the statement
*/
public Map<String, String> getSpecificBindings() {
return specificBindings;
}
/**
* @return a list of anchors as fou nd in the raw template.
*/
public List<String> getAnchors() {
List<String> anchors = new ArrayList<>();
for (int i = 1; i < spans.length; i += 2) {
anchors.add(spans[i]);
}
return anchors;
}
/**
* Get the named anchors and their associated binding specifiers as found
* in the raw template.
*
* @return A list of bind points
* @throws InvalidParameterException if the template has an error,
* such as an anchor which has no provided binding.
*/
public List<BindPoint> getBindPoints() {
List<BindPoint> bindpoints = new ArrayList<>();
for (int i = 1; i < spans.length; i += 2) {
if (!bindings.containsKey(spans[i])) {
throw new InvalidParameterException("Binding named '" + spans[i] + "' is not provided for template '" + rawtemplate + "'");
}
bindpoints.add(new BindPoint(spans[i], bindings.get(spans[i])));
}
return bindpoints;
}
/**
* Return the statement that can be used as-is by any driver specific version.
* This uses the anchor token as provided to yield a version of the statement
* which contains positional anchors, but no named bindings.
*
* @param tokenFormatter The mapping from a token name to a place holder
* @return A driver or usage-specific format of the statement, with anchors
*/
public String getPositionalStatement(Function<String, String> tokenFormatter) {
StringBuilder sb = new StringBuilder(spans[0]);
for (int i = 1; i < spans.length; i += 2) {
sb.append(tokenFormatter.apply(spans[i]));
sb.append(spans[i + 1]);
}
return sb.toString();
}
/**
* Return the parsed template in (<em>literal, variable, ..., ..., literal</em>) form.
*
* @return
*/
public String[] getSpans() {
return spans;
}
}

View File

@ -0,0 +1,29 @@
package io.virtdata.templates;
import io.virtdata.api.Binder;
import io.virtdata.core.Bindings;
/**
* Allows the generation of strings from a string template and bindings template.
*/
public class StringBindings implements Binder<String> {
private final StringCompositor compositor;
private Bindings bindings;
public StringBindings(StringCompositor compositor, Bindings bindings) {
this.compositor = compositor;
this.bindings = bindings;
}
/**
* Call the data mapper bindings, assigning the returned values positionally to the anchors in the string binding.
* @param value a long input value
* @return a new String containing the mapped values
*/
@Override
public String bind(long value) {
String s = compositor.bindValues(compositor,bindings,value);
return s;
}
}

View File

@ -0,0 +1,37 @@
package io.virtdata.templates;
import io.virtdata.core.Bindings;
import io.virtdata.core.BindingsTemplate;
import java.util.HashSet;
/**
* Uses a string template and a bindings template to create instances of {@link StringBindings}.
*/
public class StringBindingsTemplate {
private String stringTemplate;
private BindingsTemplate bindingsTemplate;
public StringBindingsTemplate(String stringTemplate, BindingsTemplate bindingsTemplate) {
this.stringTemplate = stringTemplate;
this.bindingsTemplate = bindingsTemplate;
}
/**
* Create a new instance of {@link StringBindings}, preferably in the thread context that will use it.
* @return a new StringBindings
*/
public StringBindings resolve() {
StringCompositor compositor = new StringCompositor(stringTemplate);
HashSet<String> unqualifiedNames = new HashSet<>(compositor.getBindPointNames());
unqualifiedNames.removeAll(new HashSet<>(bindingsTemplate.getBindPointNames()));
if (unqualifiedNames.size()>0) {
throw new RuntimeException("Named anchors were specified in the template which were not provided in the bindings: " + unqualifiedNames.toString());
}
Bindings bindings = bindingsTemplate.resolveBindings();
return new StringBindings(compositor,bindings);
}
}

View File

@ -0,0 +1,129 @@
package io.virtdata.templates;
import io.virtdata.api.ValuesBinder;
import io.virtdata.core.Bindings;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.function.Function;
/**
* StringCompositor provides a way to build strings from a string template and provided values.
*
* <p>
* The template is simply an array of string values, where odd indices represent token positions, and even indices represent
* literals. This version of the StringCompositor fetches data from the bindings only for the named fields in the template.
* </p>
*/
public class StringCompositor implements ValuesBinder<StringCompositor, String> {
// protected static Pattern tokenPattern = Pattern.compile("(?<section>(?<literal>([^{])+)?(?<anchor>\\{(?<token>[a-zA-Z0-9-_.]+)?\\})?)");
private String[] templateSegments;
private Function<Object, String> stringfunc = String::valueOf;
/**
* Create a string template which has positional tokens, in "{}" form.
*
* @param template The string template
*/
public StringCompositor(String template) {
templateSegments = parseTemplate(template);
}
public StringCompositor(String template, Function<Object, String> stringfunc) {
this(template);
this.stringfunc = stringfunc;
}
// for testing
protected String[] parseTemplate(String template) {
ParsedTemplate parsed = new ParsedTemplate(template, Collections.emptyMap());
return parsed.getSpans();
}
// // for testing
// protected String[] parseSection(String template) {
// StringBuilder literalBuf = new StringBuilder();
// int i = 0;
// for (; i < template.length(); i++) {
// char c = template.charAt(i);
// if (c == '\\') {
// i++;
// c = template.charAt(i);
// literalBuf.append(c);
// } else if (c != '{') {
// literalBuf.append(c);
// } else {
// i++;
// break;
// }
// }
// StringBuilder tokenBuf = new StringBuilder();
// for (; i < template.length(); i++) {
// char c = template.charAt(i);
// if (c != '}') {
// tokenBuf.append(c);
// } else {
// i++;
// break;
// }
// }
// String literal=literalBuf.toString();
// String token = tokenBuf.toString();
// if (token.length()>0) {
// return new String[] { literalBuf.toString(), tokenBuf.toString(), template.substring(i)};
// } else {
// return new String[] { literalBuf.toString() };
// }
// }
//
// /**
// * Parse the template according to the description for {@link StringCompositor}.
// *
// * @param template A string template.
// * @return A template array.
// */
// protected String[] parseTemplate(String template) {
// List<String> sections = new ArrayList<>();
//
// String[] parts = parseSection(template);
// while (parts.length>0) {
// sections.add(parts[0]);
// if (parts.length>1) {
// sections.add(parts[1]);
// }
// parts = parts.length>=2 ? parseSection(parts[2]) : new String[0];
// }
// if ((sections.size() % 2) == 0) {
// sections.add("");
// }
// return sections.toArray(new String[0]);
// }
@Override
public String bindValues(StringCompositor context, Bindings bindings, long cycle) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < templateSegments.length; i++) {
if (i % 2 == 0) {
sb.append(templateSegments[i]);
} else {
String key = templateSegments[i];
Object value = bindings.get(key, cycle);
String valueString = stringfunc.apply(value);
sb.append(valueString);
}
}
return sb.toString();
}
public List<String> getBindPointNames() {
List<String> tokens = new ArrayList<>();
for (int i = 0; i < templateSegments.length; i++) {
if (i % 2 == 1) {
tokens.add(templateSegments[i]);
}
}
return tokens;
}
}

View File

@ -0,0 +1,86 @@
package io.virtdata.templates;
import io.virtdata.api.ValuesArrayBinder;
import java.util.ArrayList;
import java.util.List;
import java.util.Optional;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
/**
* StringCompositor provides a way to build strings from a string template and provided values.
*
* <p>
* The template is simply an array of string values, where odd indices represent literals, and even indices represent token
* positions. If the token positions contains words, then these can be used as keys for looking up values in an associated
* map. If not, then values are simply positional, in which case simple numerals are used as indices for debugging purposes,
* although they are not referenced during string interpolation.
* </p>
*/
public class StringMapCompositor implements ValuesArrayBinder<StringMapCompositor, String> {
// private static Pattern tokenPattern = Pattern.compile("(?<!\\\\)\\{([^}]*)\\}(.*?)?",Pattern.DOTALL);
private static Pattern tokenPattern = Pattern.compile("(?<section>(?<literal>[^{}]+)?(?<anchor>\\{(?<token>[a-zA-Z.-]+)?\\})?)");
private String[] templateSegments;
private int buffersize=0;
/**
* Create a string template which has positional tokens, in "{}" form.
* @param template The string template
*/
public StringMapCompositor(String template) {
templateSegments =parseTemplate(template);
}
/**
* Parse the template according to the description for {@link StringMapCompositor}.
*
* @param template A string template.
* @return A template array.
*/
private String[] parseTemplate(String template) {
Matcher matcher = tokenPattern.matcher(template);
List<String> sections = new ArrayList<>();
int previous=0;
int counter=0;
while (matcher.find()) {
String literal = matcher.group("literal");
String anchor = matcher.group("anchor");
String token = matcher.group("token");
if (anchor==null && literal==null) {
break;
}
sections.add(Optional.ofNullable(literal).orElse(""));
if (anchor!=null) {
sections.add(Optional.ofNullable(token).orElse(String.valueOf(counter++)));
}
}
if ((sections.size()%2)==0) {
sections.add("");
}
return sections.toArray(new String[0]);
}
@Override
public String bindValues(StringMapCompositor context, Object[] values) {
StringBuilder sb = new StringBuilder(buffersize);
int len=values.length;
if (values.length != templateSegments.length>>1) {
throw new RuntimeException("values array has " + values.length + " elements, but "
+ " the template needs " + (templateSegments.length>>1));
}
sb.append(templateSegments[0]);
for (int i = 0; i < len; i++) {
sb.append(values[i]);
sb.append(templateSegments[((2*i)+2)]);
}
if (sb.length()>buffersize) {
buffersize=sb.length()+5;
}
return sb.toString();
}
}

View File

@ -0,0 +1,137 @@
package io.virtdata.util;
import java.math.BigDecimal;
import java.math.BigInteger;
public class StringObjectPromoter {
/**
* Specialize the type of an object according to a target class.
*
* @param raw The string representation of an object.
* @param targetType The target object type
* @return The promoted form, in the target class, or the original value if the format
* failed or the class type was not supported.
*/
public static Object promote(String raw, Class<?> targetType) {
try {
if (targetType == String.class) {
return (raw.matches("^'.+'$")) ? raw.substring(1, raw.length() - 1) : raw;
} else if (targetType == Double.class || targetType == double.class) {
Double val = Double.valueOf(raw);
return (targetType.isPrimitive()) ? val.doubleValue() : val;
} else if (targetType == Float.class || targetType == float.class) {
Float val = Float.valueOf(raw);
return (targetType.isPrimitive()) ? val.floatValue() : val;
} else if (targetType == Long.class || targetType == long.class) {
Long val = Long.valueOf(raw);
return (targetType.isPrimitive()) ? val.longValue() : val;
} else if (targetType == Integer.class || targetType == int.class) {
Integer val = Integer.valueOf(raw);
return (targetType.isPrimitive()) ? val.intValue() : val;
}
} catch (Throwable ignored) {
}
return raw;
}
/**
* Specialize the form of a string argument around the apparent object type.
*
* @param stringArg The raw value in string form
* @return the specialized object type, or the original string format if nothing was found to be
*/
public static Object promote(String stringArg) {
if (stringArg.matches("^'.*'$")) {
return stringArg.substring(1, stringArg.length() - 1);
}
if (stringArg.matches("^\\d+\\.\\d+(E\\d+)?[dD]$")) { // explicit double, no exponent
try {
Double doubleValue = Double.valueOf(stringArg);
return doubleValue;
} catch (NumberFormatException ignored) {
}
} else if (stringArg.matches("^\\d+\\.\\d+(E\\d+)?[fF]$")) { // explicit float, no exponent
try {
Float floatValue = Float.valueOf(stringArg.substring(0, stringArg.length() - 1));
return floatValue;
} catch (NumberFormatException ignored) {
}
} else if (stringArg.matches("^\\d+\\.\\d+(E\\d+)?$")) { // apparently floating point
try { // default to float
Float floatValue = Float.valueOf(stringArg);
if (!Float.isInfinite(floatValue)) {
return floatValue;
}
} catch (NumberFormatException ignored) {
}
try { // fall back to double
Double doubleValue = Double.valueOf(stringArg);
if (!doubleValue.isInfinite()) {
return doubleValue;
}
} catch (NumberFormatException ignored) {
}
try { // Fall back to BigDecimal
BigDecimal val = new BigDecimal(stringArg);
return val;
} catch (NumberFormatException ignored) {
}
} else if (stringArg.matches("^\\d+[lL]$")) { // explicit long
try {
Long longval = Long.valueOf(stringArg.substring(0, stringArg.length() - 1));
return longval;
} catch (NumberFormatException ignored) {
}
} else if (stringArg.matches("^\\d+$")) { // apparently integer
try { // default to int
Integer intValue = Integer.valueOf(stringArg);
return intValue;
} catch (NumberFormatException ignored) {
}
try { // fall back to long
Long longval = Long.valueOf(stringArg);
return longval;
} catch (NumberFormatException ignored) {
}
try { // fall back to BigInteger
BigInteger val = new BigInteger(stringArg);
return val;
} catch (NumberFormatException ignored) {
}
} else if (stringArg.equals("true")) {
return true;
}
return stringArg;
}
/**
* If a boxed type would suffice for a constructor call, even though
* {@link Class#isAssignableFrom(Class)} says the assignment wouldn't work,
* return true;
* @param have The class that we have.
* @param need The class that we need.
* @return true, if the class that we have would work for a constructor call, due to unboxing.
*/
public static boolean isAssignableForConstructor(Class<?> have, Class<?> need) {
if (need.isAssignableFrom(have)) {
return true;
}
if (
(need == boolean.class && have == Boolean.class) ||
(need == byte.class && have == Byte.class) ||
(need == short.class && have == Short.class) ||
(need == char.class && have == Character.class) ||
(need == int.class && have == Integer.class) ||
(need == long.class && have == Long.class) ||
(need == float.class && have == Float.class) ||
(need == double.class && have == Double.class)) {
return true;
}
return false;
}
}

View File

@ -0,0 +1,284 @@
package io.virtdata.util;
import org.apache.commons.lang3.ClassUtils;
import java.lang.reflect.TypeVariable;
import java.security.InvalidParameterException;
import java.util.function.*;
public class VirtDataFunctions {
private enum FuncType {
LongFunction(LongFunction.class, long.class),
LongUnaryOperator(java.util.function.LongUnaryOperator.class, long.class),
IntFunction(java.util.function.IntFunction.class, int.class),
IntUnaryOperator(java.util.function.IntUnaryOperator.class, int.class),
DoubleFunction(java.util.function.DoubleFunction.class, double.class),
DoubleUnaryOperator(java.util.function.DoubleUnaryOperator.class, double.class),
Function(java.util.function.Function.class, Object.class);
private final Class<?> functionClazz;
private final Class<?> inputClazz;
FuncType(Class functionClazz, Class<?> example) {
this.functionClazz = functionClazz;
this.inputClazz = example;
}
public static FuncType valueOf(Class<?> clazz) {
for (FuncType value : FuncType.values()) {
if (value.functionClazz.isAssignableFrom(clazz)) {
return value;
}
}
throw new InvalidParameterException("No func type was found for " + clazz.getCanonicalName());
}
}
/**
* Adapt a functional object into a different type of functional object.
*
* @param func The original function object.
* @param type The type of function object needed.
* @param output The output type required for the adapted function.
* @param truncate Whether to throw an exception on any narrowing conversion. If this is set to false,
* then basic roll-over logic is applied on narrowing conversions.
* @param <F> The type of function object needed.
* @return An instance of F
*/
public static <F> F adapt(Object func, Class<F> type, Class<?> output, boolean truncate) {
FuncType funcType = FuncType.valueOf(type);
switch (funcType) {
case LongUnaryOperator:
return truncate ? (F) adaptLongUnaryOperator(func, output) : (F) adaptLongUnaryOperatorStrict(func, output);
case DoubleUnaryOperator:
return truncate ? adaptDoubleUnaryOperator(func, output) : adaptDoubleUnaryOperatorStrict(func, output);
case IntUnaryOperator:
return truncate ? adaptIntUnaryOperator(func, output) : adaptIntUnaryOperatorStrict(func, output);
case DoubleFunction:
return truncate ? adaptDoubleFunction(func, output) : adaptDoubleFunctionStrict(func, output);
case LongFunction:
return truncate ? (F) adaptLongFunction(func, output) : (F) adaptLongFunctionStrict(func, output);
case IntFunction:
return truncate ? adaptIntFunction(func, output) : adaptIntFunction(func, output);
case Function:
return truncate ? (F) adaptFunction(func, output) : adaptFunctionStrict(func, output);
default:
throw new RuntimeException("Unable to convert " + func.getClass().getCanonicalName() +
" to " + type.getCanonicalName() + (truncate ? " WITH " : " WITHOUT ") + "truncation");
}
}
private static LongFunction<?> adaptLongFunctionStrict(Object func, Class<?> output) {
FuncType isaType = FuncType.valueOf(func.getClass());
switch (isaType) {
case LongFunction:
LongFunction f1 = assertTypesAssignable(func, LongFunction.class, Object.class);
return f1;
case LongUnaryOperator:
LongUnaryOperator f2 = assertTypesAssignable(func, LongUnaryOperator.class);
return f2::applyAsLong;
case Function:
Function<Long, Long> f7 = assertTypesAssignable(func, Function.class, Long.class);
return (long l) -> f7.apply(l);
default:
throw new RuntimeException("Unable to convert " + func.getClass().getCanonicalName() + " to a " +
LongUnaryOperator.class.getCanonicalName() + " since this would cause a narrowing conversion.");
}
}
private static Function<?,?> adaptFunction(Object func, Class<?> output) {
FuncType isaType = FuncType.valueOf(func.getClass());
switch (isaType) {
case LongFunction:
LongFunction<?> f1 = (LongFunction<?>)func;
Function<Long,?> rf1 = f1::apply;
return rf1;
case LongUnaryOperator:
LongUnaryOperator f2 = (LongUnaryOperator)func;
Function<Long,Long> rf2 = f2::applyAsLong;
return rf2;
case IntFunction:
IntFunction f3 = (IntFunction)func;
Function<Integer,?> rf3 = f3::apply;
return rf3;
case IntUnaryOperator:
IntUnaryOperator f4 = (IntUnaryOperator)func;
Function<Integer,?> rf4 = f4::applyAsInt;
return rf4;
case DoubleFunction:
DoubleFunction f5 = (DoubleFunction)func;
Function<Double,?> rf5 = f5::apply;
return rf5;
case DoubleUnaryOperator:
DoubleUnaryOperator f6 = (DoubleUnaryOperator)func;
Function<Double,?> rf6 = f6::applyAsDouble;
return rf6;
case Function:
return (Function<?,?>) func;
default:
throw new RuntimeException("Unable to map function:" + func);
}
}
private static <F> F adaptFunctionStrict(Object func, Class<?> output) {
throw new RuntimeException("This must be implemented, now that it is used.");
}
private static <F> F adaptDoubleFunctionStrict(Object func, Class<?> output) {
throw new RuntimeException("This must be implemented, now that it is used.");
}
private static <F> F adaptIntUnaryOperatorStrict(Object func, Class<?> output) {
throw new RuntimeException("This must be implemented, now that it is used.");
}
private static <F> F adaptDoubleUnaryOperatorStrict(Object func, Class<?> output) {
throw new RuntimeException("This must be implemented, now that it is used.");
}
private static LongUnaryOperator adaptLongUnaryOperatorStrict(Object func, Class<?> output) {
FuncType isaType = FuncType.valueOf(func.getClass());
switch (isaType) {
case LongFunction:
LongFunction<Long> o2 = assertTypesAssignable(func, LongFunction.class, long.class);
return o2::apply;
case LongUnaryOperator:
LongUnaryOperator o5 = assertTypesAssignable(func, LongUnaryOperator.class);
return o5;
case Function:
Function<Long, Long> o7 = assertTypesAssignable(func, Function.class, long.class, long.class);
return o7::apply;
default:
throw new RuntimeException("Unable to convert " + func.getClass().getCanonicalName() + " to a " +
LongUnaryOperator.class.getCanonicalName() + " since this would cause a narrowing conversion.");
}
}
private static <F> F adaptIntFunction(Object func, Class<?> output) {
throw new RuntimeException("This must be implemented, now that it is used.");
}
private static LongFunction<?> adaptLongFunction(Object func, Class<?> output) {
FuncType isaType = FuncType.valueOf(func.getClass());
switch (isaType) {
case LongFunction:
LongFunction f1 = assertTypesAssignable(func, LongFunction.class, Object.class);
return f1;
case LongUnaryOperator:
LongUnaryOperator f2 = assertTypesAssignable(func, LongUnaryOperator.class);
return f2::applyAsLong;
case IntFunction:
IntFunction f3 = assertTypesAssignable(func, IntFunction.class);
return (long l) -> f3.apply((int) (l % Integer.MAX_VALUE));
case IntUnaryOperator:
IntUnaryOperator f4 = assertTypesAssignable(func, IntUnaryOperator.class);
return (long l) -> f4.applyAsInt((int) (l % Integer.MAX_VALUE));
case DoubleFunction:
DoubleFunction f5 = assertTypesAssignable(func, DoubleFunction.class);
return f5::apply;
case DoubleUnaryOperator:
DoubleUnaryOperator f6 = assertTypesAssignable(func, DoubleUnaryOperator.class);
return f6::applyAsDouble;
case Function:
Function<Long, Object> f7 = assertTypesAssignable(func, Function.class);
assertOutputAssignable(f7.apply(1L),output);
return (long l) -> f7.apply(l);
default:
throw new RuntimeException("Unable to convert " + func.getClass().getCanonicalName() + " to a " +
LongUnaryOperator.class.getCanonicalName());
}
}
private static void assertOutputAssignable(Object result, Class<?> clazz) {
if (!ClassUtils.isAssignable(result.getClass(), clazz, true)) {
throw new InvalidParameterException("Unable to assign type of " + result.getClass().getCanonicalName()
+ " to " + clazz.getCanonicalName());
}
// if (!clazz.isAssignableFrom(result.getClass())) {
// throw new InvalidParameterException("Unable to assign type of " + result.getClass().getCanonicalName()
// + " to " + clazz.getCanonicalName());
// }
}
private static <F> F adaptDoubleFunction(Object func, Class<?> output) {
throw new RuntimeException("This must be implemented, now that it is used.");
}
private static <F> F adaptIntUnaryOperator(Object func, Class<?> output) {
throw new RuntimeException("This must be implemented, now that it is used.");
}
private static <F> F adaptDoubleUnaryOperator(Object func, Class<?> output) {
throw new RuntimeException("This must be implemented, now that it is used.");
}
private static LongUnaryOperator adaptLongUnaryOperator(Object func, Class<?> output) {
FuncType isaType = FuncType.valueOf(func.getClass());
switch (isaType) {
case IntFunction:
IntFunction<Long> o1 = assertTypesAssignable(func, IntFunction.class, long.class);
return (long l) -> o1.apply((int) l % Integer.MAX_VALUE);
case LongFunction:
LongFunction<Long> o2 = assertTypesAssignable(func, LongFunction.class, long.class);
return o2::apply;
case DoubleFunction:
DoubleFunction<Long> o3 = assertTypesAssignable(func, DoubleFunction.class, long.class);
return o3::apply;
case IntUnaryOperator:
IntUnaryOperator o4 = assertTypesAssignable(func, IntUnaryOperator.class);
return (long l) -> o4.applyAsInt((int) l % Integer.MAX_VALUE);
case LongUnaryOperator:
LongUnaryOperator o5 = assertTypesAssignable(func, LongUnaryOperator.class);
return o5;
case DoubleUnaryOperator:
DoubleUnaryOperator o6 = assertTypesAssignable(func, DoubleUnaryOperator.class);
return (long l) -> (long) (o6.applyAsDouble(l) % Long.MAX_VALUE);
case Function:
Function<Long, Long> o7 = assertTypesAssignable(func, Function.class, long.class, long.class);
return o7::apply;
}
throw new InvalidParameterException("Unable to convert " + func.getClass().getCanonicalName() + " to a " +
LongUnaryOperator.class.getCanonicalName());
}
private static <T> T assertTypesAssignable(
Object base,
Class<T> wantType,
Class<?>... clazzes) {
if (!wantType.isAssignableFrom(base.getClass())) {
throw new InvalidParameterException("Unable to assign " + wantType.getCanonicalName() + " from " +
base.getClass().getCanonicalName());
}
TypeVariable<? extends Class<?>>[] typeParameters = base.getClass().getTypeParameters();
if (typeParameters.length > 0) {
if (clazzes.length != typeParameters.length) {
throw new InvalidParameterException(
"type parameter lengths are mismatched:" + clazzes.length + ", " + typeParameters.length
);
}
for (int i = 0; i < clazzes.length; i++) {
Class<?> from = clazzes[i];
TypeVariable<? extends Class<?>> to = typeParameters[i];
boolean assignableFrom = to.getGenericDeclaration().isAssignableFrom(from);
if (!assignableFrom) {
throw new InvalidParameterException("Can not assign " + from.getCanonicalName() + " to " + to.getGenericDeclaration().getCanonicalName());
}
}
}
return (T) (base);
}
}

View File

@ -0,0 +1,304 @@
/*
*
* Copyright 2016 jshook
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* /
*/
package io.virtdata.util;
import org.apache.commons.csv.CSVFormat;
import org.apache.commons.csv.CSVParser;
import org.apache.logging.log4j.Logger;
import org.apache.logging.log4j.LogManager;
import java.io.*;
import java.net.URI;
import java.net.URISyntaxException;
import java.net.URL;
import java.nio.CharBuffer;
import java.nio.file.*;
import java.nio.file.attribute.BasicFileAttributes;
import java.nio.file.spi.FileSystemProvider;
import java.util.*;
import java.util.stream.Collectors;
public class VirtDataResources {
public final static String DATA_DIR = "data";
private final static Logger logger = LogManager.getLogger(VirtDataResources.class);public static CharBuffer readDataFileToCharBuffer(String basename) {
return loadFileToCharBuffer(basename, DATA_DIR);
}
public static List<String> readDataFileLines(String basename) {
return readFileLines(basename, DATA_DIR);
}
public static String readDataFileString(String basename) {
return readFileString(basename, DATA_DIR);
}
public static InputStream findRequiredStreamOrFile(String basename, String extension, String... searchPaths) {
Optional<InputStream> optionalStreamOrFile = findOptionalStreamOrFile(basename, extension, searchPaths);
return optionalStreamOrFile.orElseThrow(() -> new RuntimeException(
"Unable to find " + basename + " with extension " + extension + " in file system or in classpath, with"
+ " search paths: " + Arrays.stream(searchPaths).collect(Collectors.joining(","))
));
}
public static Reader findRequiredReader(String basename, String extension, String... searchPaths) {
Optional<Reader> optionalReader = findOptionalReader(basename, extension, searchPaths);
return optionalReader.orElseThrow(() -> new RuntimeException(
"Unable to find " + basename + " with extension " + extension + " in file system or in classpath, with"
+ " search paths: " + Arrays.stream(searchPaths).collect(Collectors.joining(","))
));
}
public static Optional<Reader> findOptionalReader(String basename, String extenion, String... searchPaths) {
return findOptionalStreamOrFile(basename, extenion, searchPaths)
.map(InputStreamReader::new)
.map(BufferedReader::new);
}
public static Optional<Path> findOptionalDirPath(String pathName) {
URL systemResource = ClassLoader.getSystemResource(pathName);
if (systemResource != null) {
try {
return Optional.of(Path.of(systemResource.toURI()));
} catch (URISyntaxException e) {
throw new RuntimeException(e);
}
}
return Optional.empty();
}
public static Optional<InputStream> findOptionalStreamOrFile(String basename, String extension, String... searchPaths) {
boolean needsExtension = (extension != null && !extension.isEmpty() && !basename.endsWith("." + extension));
String filename = basename + (needsExtension ? "." + extension : "");
ArrayList<String> paths = new ArrayList<String>() {{
add(filename);
if (!isRemote(basename)) {
addAll(Arrays.stream(searchPaths).map(s -> s + File.separator + filename)
.collect(Collectors.toCollection(ArrayList::new)));
}
}};
for (String path : paths) {
Optional<InputStream> stream = getInputStream(path);
if (stream.isPresent()) {
return stream;
}
}
return Optional.empty();
}
private static boolean isRemote(String path) {
return (path.toLowerCase().startsWith("http:")
|| path.toLowerCase().startsWith("https:"));
}
public static Optional<InputStream> getInputStream(String path) {
// URLs, if http: or https:
if (isRemote(path)) {
Optional<InputStream> inputStream = getInputStreamForUrl(path);
if (inputStream != null) return inputStream;
}
// Files
try {
InputStream stream = new FileInputStream(path);
return Optional.of(stream);
} catch (FileNotFoundException ignored) {
}
// Classpath
ClassLoader classLoader = VirtDataResources.class.getClassLoader();
InputStream stream = classLoader.getResourceAsStream(path);
if (stream != null) {
return Optional.of(stream);
}
return Optional.empty();
}
public static Optional<InputStream> getInputStreamForUrl(String path) {
URL url;
try {
url = new URL(path);
InputStream inputStream = url.openStream();
if (inputStream != null) {
return Optional.of(inputStream);
}
} catch (Exception e) {
throw new RuntimeException(e);
}
return null;
}
public static List<String> readFileLines(String basename, String... searchPaths) {
InputStream requiredStreamOrFile = findRequiredStreamOrFile(basename, "", DATA_DIR);
try (BufferedReader buffer = new BufferedReader((new InputStreamReader(requiredStreamOrFile)))) {
List<String> collected = buffer.lines().collect(Collectors.toList());
return collected;
} catch (IOException ioe) {
throw new RuntimeException("Error while reading required file to string", ioe);
}
}
public static String readFileString(String basename, String... searchPaths) {
InputStream requiredStreamOrFile = findRequiredStreamOrFile(basename, "", searchPaths);
try (BufferedReader buffer = new BufferedReader((new InputStreamReader(requiredStreamOrFile)))) {
String filedata = buffer.lines().collect(Collectors.joining("\n"));
return filedata;
} catch (IOException ioe) {
throw new RuntimeException("Error while reading required file to string", ioe);
}
}
public static CSVParser readFileCSV(String basename, String... searchPaths) {
Reader reader = findRequiredReader(basename, "csv", searchPaths);
CSVFormat format = CSVFormat.newFormat(',').withFirstRecordAsHeader();
try {
CSVParser parser = new CSVParser(reader, format);
return parser;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
public static CharBuffer loadFileToCharBuffer(String filename, String... searchPaths) {
InputStream stream = findRequiredStreamOrFile(filename, "", searchPaths);
CharBuffer linesImage;
try {
InputStreamReader isr = new InputStreamReader(stream);
linesImage = CharBuffer.allocate(1024 * 1024);
while (isr.read(linesImage) > 0) {
}
isr.close();
} catch (IOException e) {
logger.error(e.getMessage());
throw new RuntimeException(e);
}
linesImage.flip();
return linesImage.asReadOnlyBuffer();
}
/**
* <p>Look in all the provided path specifiers for an extant Path, and return
* the first one found.</p>
*
* <p>If the final character of any path specifier is the default file
* separator, then the request is for a directory. During searching,
* if a directory is found when a file is requested, or vice-versa, then
* an error is thrown withouth looking further.</p>
*
* <p>The locations that are searched include:</p>
* <OL>
* <LI>URLs. If the path specifier is a URI, then it is checked for a positive response
* before the path is returned. URLs can not be used for directories.</LI>
* <LI>The local filesystem, starting from the current directory of the process.</LI>
* <LI>The class path.</LI>
* </OL>
*
* @param pathspecs A specifier for a URL, a directory with a trailing slash, or a file
* with no trailing slash.
* @return A Path
* @throws RuntimeException if none of the specified paths is found in any of the locations
*/
public static Path findPathIn(String... pathspecs) {
for (String pathspec : pathspecs) {
Path foundPath = null;
if (isRemote(pathspec)) {
try {
Optional<InputStream> inputStreamForUrl = getInputStreamForUrl(pathspec);
if (inputStreamForUrl.isPresent()) {
foundPath = Path.of(URI.create(pathspec));
logger.debug("Found accessible remote file at " + foundPath.toString());
}
} catch (Exception ignored) {
}
} else {
boolean wantsADirectory = pathspec.endsWith(FileSystems.getDefault().getSeparator());
String candidatePath = wantsADirectory ? pathspec.substring(0, pathspec.length() - 1) : pathspec;
Path candidate = Path.of(candidatePath);
try {
FileSystemProvider provider = candidate.getFileSystem().provider();
provider.checkAccess(candidate, AccessMode.READ);
BasicFileAttributes attrs = provider.readAttributes(candidate, BasicFileAttributes.class);
boolean foundADirectory = attrs.isDirectory();
if (wantsADirectory != foundADirectory) {
throw new RuntimeException("for path " + pathspec + ", user wanted a " +
(wantsADirectory ? "directory" : "file") + ", but found a " +
(foundADirectory ? "directory" : "file") + " while searching paths " +
Arrays.toString(pathspecs));
}
foundPath = candidate;
} catch (Exception ignored) {
}
if (foundPath == null) {
try {
URL url = ClassLoader.getSystemResource(candidatePath);
if (url != null) {
URI uri = URI.create(url.toExternalForm());
foundPath = getPathInFilesystem(uri);
logger.debug("Found path in classpath: " + candidatePath + ": " + foundPath.toString());
}
} catch (Exception e) {
logger.trace("Error while looking in classpath for " + e.getMessage(), e);
}
}
}
if (foundPath != null) {
return foundPath;
}
}
throw new RuntimeException("Unable to find path in " + Arrays.toString(pathspecs));
}
private synchronized static Path getPathInFilesystem(URI uri) {
FileSystem fileSystem = null;
try {
fileSystem = FileSystems.getFileSystem(uri);
} catch (FileSystemNotFoundException ignored) {
try {
fileSystem = FileSystems.newFileSystem(uri, new HashMap<>());
} catch (IOException e) {
throw new RuntimeException(e);
}
}
return Path.of(uri);
}
public static CSVParser readDelimFile(String basename, char delimiter, String... searchPaths) {
Reader reader = findRequiredReader(basename, "csv", searchPaths);
CSVFormat format = CSVFormat.newFormat(delimiter).withFirstRecordAsHeader();
try {
CSVParser parser = new CSVParser(reader, format);
return parser;
} catch (IOException e) {
throw new RuntimeException(e);
}
}
}

View File

@ -0,0 +1,30 @@
package io.virtdata.annotations;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class ExampleDataTest {
@Test
public void testRangeFormats() {
ExampleData e = new ExampleData(new String[]{"Example('a')", "an example", "[1..5]"});
long[] onetofive = e.getLongInputs();
assertThat(onetofive).containsExactly(1L,2L,3L,4L,5L);
}
@Test
public void testNegativeIncrRange() {
ExampleData e2 = new ExampleData(new String[]{"Example('b')","e2","[10..-10 -5]"});
long[] downBy5 = e2.getLongInputs();
assertThat(downBy5).containsExactly(10L,5L,0L,-5L,-10L);
}
@Test
public void testSequence() {
ExampleData e3 = new ExampleData(new String[]{"Example('c')","e3","[1,2,-3]"});
long[] afew = e3.getLongInputs();
assertThat(afew).containsExactly(1L,2L,-3L);
}
}

View File

@ -0,0 +1,16 @@
package io.virtdata.api;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class ValueTypeTest {
@Test
public void testMatchingRawObject() {
ValueType vt = ValueType.valueOfClassName("Object");
assertThat(vt).isEqualTo(ValueType.OBJECT);
}
}

View File

@ -0,0 +1,282 @@
package io.virtdata.composers;
import io.virtdata.api.DataMapper;
import io.virtdata.api.FunctionType;
import io.virtdata.api.composers.FunctionAssembly;
import io.virtdata.api.composers.FunctionComposer;
import io.virtdata.core.DataMapperFunctionMapper;
import org.junit.Test;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.*;
public class FunctionAssemblerMatrixTest {
@Test
public void testFullPrimitiveMatrix() {
int iteration=0;
List<Object> funcs = new ArrayList<>();
for (FunctionType functionType : FunctionType.values()) {
Object[] objects = genFunctions(functionType);
funcs.addAll(Arrays.asList(objects));
}
long totalIterations = funcs.size() * funcs.size();
for (Object f1 : funcs) {
// if (ft1 == FunctionType.R_T
// || ft1 == FunctionType.long_T
// || ft1 == FunctionType.int_T
// || ft1 == FunctionType.double_T) {
// continue;
// }
for (Object f2 : funcs) {
// if (ft2 == FunctionType.R_T
// || ft2 == FunctionType.long_T
// || ft2 == FunctionType.int_T
// || ft2 == FunctionType.double_T) {
// continue;
// }
iteration++;
double pctDone = 100.0 * ((double) iteration / totalIterations);
String testingSignature = "testing: f1:" + f1 + ", f2:" + f2;
System.out.format("%3d/%3d %s",iteration,totalIterations, testingSignature);
FunctionComposer assy = new FunctionAssembly();
assy = assy.andThen(f1);
assy = assy.andThen(f2);
DataMapper g = DataMapperFunctionMapper.map(assy.getResolvedFunction().getFunctionObject());
Object o = g.get(1L);
System.out.println(" out:" + o);
}
}
}
private Object[] genFunctions(FunctionType ftype) {
switch (ftype) {
case long_double:
return new Object[]{ new F_long_double() };
case long_int:
return new Object[]{ new F_long_int() };
case long_long:
return new Object[]{ new F_long_long() };
case long_T:
return new Object[]{ new F_long_T_Object(), new F_long_T_DOUBLE(), new F_long_T_LONG(), new F_long_T_INT() };
case int_int:
return new Object[]{ new F_int_int() };
case R_T:
return new Object[]{ new F_R_T_Object(), new F_R_T_LONG(), new F_R_T_DOUBLE(), new F_R_T_INT() };
case int_long:
return new Object[]{ new F_int_long() };
case int_double:
return new Object[]{ new F_int_double() };
case int_T:
return new Object[]{ new F_int_T_Object(), new F_int_T_LONG(), new F_int_T_DOUBLE(), new F_int_T_INT() };
case double_double:
return new Object[]{ new F_double_double() };
case double_int:
return new Object[]{ new F_double_int() };
case double_long:
return new Object[]{ new F_double_long() };
case double_T:
return new Object[]{ new F_double_T_Object(), new F_double_T_LONG(), new F_double_T_DOUBLE(), new F_double_T_INT() };
default:
throw new RuntimeException("unrecognized function type: " + ftype);
}
}
private static class SimpleNamer {
@Override
public String toString() {
return this.getClass().getSimpleName();
}
}
@Override
public String toString() {
return getClass().getSimpleName();
}
private static class F_double_T_LONG extends SimpleNamer implements DoubleToLongFunction {
@Override
public long applyAsLong(double value) {
return (long) value;
}
}
private static class F_double_T_DOUBLE extends SimpleNamer implements DoubleUnaryOperator {
@Override
public double applyAsDouble(double operand) {
return operand;
}
}
private static class F_double_T_INT extends SimpleNamer implements DoubleToIntFunction {
@Override
public int applyAsInt(double value) {
return (int) value;
}
}
private static class F_double_T_Object extends SimpleNamer implements DoubleFunction<Object>{
@Override
public Object apply(double value) {
return (long) value;
}
}
private static class F_double_int extends SimpleNamer implements DoubleToIntFunction {
@Override
public int applyAsInt(double value) {
return (int) value;
}
}
private static class F_double_long extends SimpleNamer implements DoubleToLongFunction {
@Override
public long applyAsLong(double value) {
return (long) value;
}
}
private static class F_long_double extends SimpleNamer implements LongToDoubleFunction {
@Override
public double applyAsDouble(long value) {
return (double) value;
}
}
private static class F_long_int extends SimpleNamer implements LongToIntFunction {
@Override
public int applyAsInt(long value) {
return (int) value;
}
}
private static class F_long_long extends SimpleNamer implements LongUnaryOperator {
@Override
public long applyAsLong(long operand) {
return operand;
}
}
private static class F_double_double extends SimpleNamer implements DoubleUnaryOperator {
@Override
public double applyAsDouble(double operand) {
return operand;
}
}
private static class F_long_T_Object extends SimpleNamer implements LongFunction<Object> {
@Override
public Object apply(long value) {
return value;
}
}
private static class F_long_T_LONG extends SimpleNamer implements LongFunction<Long> {
@Override
public Long apply(long value) {
return value;
}
}
private static class F_long_T_INT extends SimpleNamer implements LongFunction<Integer> {
@Override
public Integer apply(long value) {
return (int) value;
}
}
private static class F_long_T_DOUBLE extends SimpleNamer implements LongFunction<Double> {
@Override
public Double apply(long value) {
return (double) value;
}
}
private static class F_R_T_Object extends SimpleNamer implements Function<Object, Object> {
@Override
public String apply(Object object) {
return String.valueOf(object);
}
}
private static class F_R_T_LONG extends SimpleNamer implements Function<Object, Long> {
@Override
public Long apply(Object object) {
return Double.valueOf(String.valueOf(object)).longValue();
}
}
private static class F_R_T_DOUBLE extends SimpleNamer implements Function<Object, Double> {
@Override
public Double apply(Object object) {
return Double.valueOf(String.valueOf(object));
}
}
private static class F_R_T_INT extends SimpleNamer implements Function<Object, Integer> {
@Override
public Integer apply(Object object) {
return Double.valueOf(String.valueOf(object)).intValue();
}
}
private static class F_int_int extends SimpleNamer implements IntUnaryOperator {
@Override
public int applyAsInt(int operand) {
return operand;
}
}
private static class F_int_long extends SimpleNamer implements IntToLongFunction {
@Override
public long applyAsLong(int value) {
return value;
}
}
private static class F_int_double extends SimpleNamer implements IntToDoubleFunction {
@Override
public double applyAsDouble(int value) {
return value;
}
}
private static class F_int_T_LONG extends SimpleNamer implements IntFunction<Long> {
@Override
public Long apply(int value) {
return (long) value;
}
}
private static class F_int_T_DOUBLE extends SimpleNamer implements IntFunction<Double> {
@Override
public Double apply(int value) {
return (double) value;
}
}
private static class F_int_T_INT extends SimpleNamer implements IntUnaryOperator {
@Override
public int applyAsInt(int operand) {
return operand;
}
}
private static class F_int_T_Object extends SimpleNamer implements IntFunction<Object> {
@Override
public Object apply(int value) {
return (long) value;
}
}
}

View File

@ -0,0 +1,132 @@
package io.virtdata.composers;
import io.virtdata.api.DataMapper;
import io.virtdata.api.composers.FunctionAssembly;
import io.virtdata.api.composers.FunctionComposer;
import org.junit.Test;
import java.util.function.Function;
import java.util.function.LongFunction;
import java.util.function.LongUnaryOperator;
import static org.assertj.core.api.Assertions.assertThat;
public class FunctionAssemblerTest {
@Test
public void testLongUnary() {
FunctionComposer fass = new FunctionAssembly();
fass.andThen(new IdentityOperator());
DataMapper<Long> dataMapper = fass.getDataMapper();
Long aLong = dataMapper.get(5);
assertThat(aLong).isEqualTo(5);
}
@Test
public void testLongUnaryLongUnary() {
FunctionComposer fass = new FunctionAssembly();
fass.andThen(new IdentityOperator());
fass.andThen(new IdentityOperator());
DataMapper<Long> dataMapper = fass.getDataMapper();
Long aLong = dataMapper.get(5);
assertThat(aLong).isEqualTo(5);
}
@SuppressWarnings("Duplicates")
@Test
public void testLongFunction() throws Exception {
FunctionComposer fass = new FunctionAssembly();
fass.andThen(new LongAddFiveFunction());
DataMapper<Long> dataMapper = fass.getDataMapper();
Long aLong = dataMapper.get(5);
assertThat(aLong).isEqualTo(10);
}
@Test
public void testLongFunctionLongFunctionProper() {
FunctionComposer fass = new FunctionAssembly();
fass.andThen(new LongAddFiveFunction());
fass.andThen(new LongAddFiveFunction());
DataMapper<Long> dataMapper = fass.getDataMapper();
Long aLong = dataMapper.get(5);
assertThat(aLong).isEqualTo(15);
}
@Test(expected = ClassCastException.class)
public void testLongFunctionLongFunctionMistyped() throws Exception {
FunctionComposer fass = new FunctionAssembly();
fass.andThen(new LongAddFiveFunction());
fass.andThen(new GenericStringCat());
DataMapper<String> dataMapper = fass.getDataMapper();
dataMapper.get(5);
}
@Test
public void testAndThenFunction() {
FunctionComposer fass = new FunctionAssembly();
fass.andThen(new GenericLongToString());
DataMapper<String> dataMapper = fass.getDataMapper();
String s = dataMapper.get(5);
assertThat(s).isEqualTo("5");
}
// @Test
// public void testFunctionFunctionProper() {
// FunctionComposer fass = new FunctionAssembly();
// fass.andThen(new GenericLongToString());
// fass.andThen(new GenericStringCat());
// DataMapper<String> dataMapper = fass.getDataMapper();
// String s = dataMapper.get(5);
// assertThat(s).isEqualTo("Cat5");
// }
@Test(expected= ClassCastException.class)
public void testFunctionFunctionMistyped() {
FunctionComposer fass = new FunctionAssembly();
fass.andThen(new GenericStringCat());
DataMapper<String> dataMapper = fass.getDataMapper();
String s = dataMapper.get(5);
}
@Test
public void testLongUnaryLongFunctionFunctionProper() {
FunctionComposer fass = new FunctionAssembly();
fass.andThen(new IdentityOperator());
fass.andThen(new LongAddFiveFunction());
fass.andThen(new GenericLongToString());
DataMapper<String> dataMapper = fass.getDataMapper();
String s = dataMapper.get(5);
assertThat(s).isEqualTo("10");
}
private static class IdentityOperator implements LongUnaryOperator {
@Override
public long applyAsLong(long operand) {
return operand;
}
}
private static class LongAddFiveFunction implements LongFunction<Long> {
@Override
public Long apply(long value) {
return value + 5;
}
}
private static class GenericLongToString implements Function<Long,String> {
@Override
public String apply(Long aLong) {
return String.valueOf(aLong);
}
}
private static class GenericStringCat implements Function<String,String> {
@Override
public String apply(String s) {
return "Cat" + s;
}
}
}

View File

@ -0,0 +1,35 @@
package io.virtdata.core;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class CompatibilityFixupsTest {
@Test
public void testInlineChange() {
assertThat(CompatibilityFixups.fixup("Hash(); uniform_integer(0,1000000000); ToString() -> String"))
.isEqualTo("Hash(); Uniform(0,1000000000,'hash','interpolate'); ToString() -> String");
}
@Test
public void testFixupModifiers() {
assertThat(CompatibilityFixups.fixup("compute_levy(ASDF)")).isEqualTo("Levy(ASDF,'hash','compute')");
assertThat(CompatibilityFixups.fixup("interpolate_levy(ASDF)")).isEqualTo("Levy(ASDF,'hash','interpolate')");
assertThat(CompatibilityFixups.fixup("mapto_levy(ASDF)")).isEqualTo("Levy(ASDF,'map','interpolate')");
assertThat(CompatibilityFixups.fixup("hashto_levy(ASDF)")).isEqualTo("Levy(ASDF,'hash','interpolate')");
}
@Test
public void testFixupNames() {
assertThat(CompatibilityFixups.fixup("gamma(foo)")).isEqualTo("Gamma(foo,'hash','interpolate')");
assertThat(CompatibilityFixups.fixup("mapto_uniform_integer(foo)")).isEqualTo("Uniform(foo,'map','interpolate')");
assertThat(CompatibilityFixups.fixup("hashto_uniform_real(foo)")).isEqualTo("Uniform(foo,'hash','interpolate')");
}
@Test
public void testParsingSanity() {
assertThat(CompatibilityFixups.fixup("long -> Add(5) -> long")).isEqualTo("long -> Add(5) -> long");
}
}

View File

@ -0,0 +1,50 @@
package io.virtdata.core;
import org.junit.Test;
import java.util.function.LongUnaryOperator;
import static org.assertj.core.api.Assertions.assertThat;
public class ResolvedFunctionTest {
@Test
public void testToStringWithVarArgs() {
try {
TestAdd testAdd = new TestAdd(1, 2, 3);
Class<?>[] parameterTypes = TestAdd.class.getConstructor(int.class, int[].class).getParameterTypes();
ResolvedFunction rf = new ResolvedFunction(testAdd, true, parameterTypes, new Object[]{1, 2, 3}, long.class, long.class);
assertThat(rf.toString()).isEqualTo("long->io.virtdata.core.ResolvedFunctionTest$TestAdd->long [Integer=>int,Integer...=>int...]");
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
@Test
public void testToStringWithEmptyVarArgs() {
try {
TestAdd testAdd = new TestAdd(1);
Class<?>[] parameterTypes = TestAdd.class.getConstructor(int.class, int[].class).getParameterTypes();
ResolvedFunction rf = new ResolvedFunction(testAdd, true, parameterTypes, new Object[]{1, 2, 3}, long.class, long.class);
assertThat(rf.toString()).isEqualTo("long->io.virtdata.core.ResolvedFunctionTest$TestAdd->long [Integer=>int,Integer...=>int...]");
} catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
private final static class TestAdd implements LongUnaryOperator {
private final int a;
private final int[] b;
public TestAdd(int a, int... b) {
this.a = a;
this.b = b;
}
@Override
public long applyAsLong(long operand) {
return a + operand;
}
}
}

View File

@ -0,0 +1,20 @@
package io.virtdata.core;
import org.junit.Test;
public class VirtDataComposerTest {
@Test
public void testResolveFunctionFlow() {
VirtDataComposer composer = new VirtDataComposer();
ResolverDiagnostics dashrepeats = composer.resolveDiagnosticFunctionFlow("TestableMapper('--', TestingRepeater(2));");
}
@Test
public void testResolveDiagnosticFunctionFlow() {
}
@Test
public void testResolveFunctionFlow1() {
}
}

View File

@ -0,0 +1,15 @@
package io.virtdata.core;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class VirtDataTest {
@Test
public void testBasicBindings() {
BindingsTemplate bt = VirtData.getTemplate("a","Mod(5)");
assertThat(bt).isNotNull();
}
}

View File

@ -0,0 +1,117 @@
package io.virtdata.templates;
import org.junit.Test;
import java.security.InvalidParameterException;
import java.util.HashMap;
import java.util.Map;
import java.util.regex.Pattern;
import static org.assertj.core.api.Assertions.assertThat;
public class ParsedTemplateTest {
private final Map<String, String> bindings = new HashMap<>() {{
put("bindname1", "bindspec1");
put("bindname2", "bindspec2");
}};
private final String rawNothing = "This has no anchors";
private final String oneCurly = "A {curly} brace.";
private final String oneQuestion = " A ?question anchor.";
private final String oneExtraneous = "An {this is an extraneous form} invalid anchor.";
@Test
public void testShouldMatchRawLiteral() {
ParsedTemplate pt = new ParsedTemplate(rawNothing, bindings);
assertThat(pt.getSpans()).containsExactly("This has no anchors");
assertThat(pt.getSpecificBindings()).isEmpty();
assertThat(pt.getExtraBindings()).hasSameElementsAs(bindings.keySet());
assertThat(pt.getMissingBindings()).isEmpty();
}
@Test
public void testShoudlMatchCurlyBraces() {
ParsedTemplate pt = new ParsedTemplate(oneCurly, bindings);
assertThat(pt.getSpans()).containsExactly("A ", "curly", " brace.");
assertThat(pt.getSpecificBindings().isEmpty());
assertThat(pt.getMissingBindings()).contains("curly");
assertThat(pt.getExtraBindings()).hasSameElementsAs(bindings.keySet());
}
@Test
public void testShouldMatchQuestionMark() {
ParsedTemplate pt = new ParsedTemplate(oneQuestion, bindings);
assertThat(pt.getSpans()).containsExactly(" A ", "question", " anchor.");
assertThat(pt.getSpecificBindings()).isEmpty();
assertThat(pt.getMissingBindings()).containsExactly("question");
assertThat(pt.getExtraBindings()).hasSameElementsAs(bindings.keySet());
}
@Test
public void testShouldIgnoreExtraneousAnchors() {
ParsedTemplate pt = new ParsedTemplate(oneExtraneous, bindings);
assertThat(pt.getSpans()).containsExactly("An {this is an extraneous form} invalid anchor.");
assertThat(pt.getSpecificBindings()).isEmpty();
assertThat(pt.getMissingBindings()).isEmpty();
assertThat(pt.getExtraBindings()).hasSameElementsAs(bindings.keySet());
}
@Test
public void testShouldMatchLiteralVariableOnly() {
String literalVariableOnly = "literal {bindname1}";
ParsedTemplate pt = new ParsedTemplate(literalVariableOnly, bindings);
assertThat(pt.getSpans()).containsExactly("literal ", "bindname1", "");
assertThat(pt.getSpecificBindings()).containsOnlyKeys("bindname1");
assertThat(pt.getMissingBindings()).isEmpty();
assertThat(pt.getExtraBindings()).containsExactly("bindname2");
}
@Test
public void testShouldMatchVariableLiteralOnly() {
String variableLiteralOnly = "{bindname2} literal";
ParsedTemplate pt = new ParsedTemplate(variableLiteralOnly, bindings);
assertThat(pt.getSpans()).containsExactly("", "bindname2", " literal");
assertThat(pt.getSpecificBindings()).containsOnlyKeys("bindname2");
assertThat(pt.getMissingBindings()).isEmpty();
assertThat(pt.getExtraBindings()).containsExactly("bindname1");
}
@Test
public void testShouldMatchProvidedValidPattern() {
String basic = "A [provided] pattern.";
Pattern p = Pattern.compile("\\[(?<anchor>\\w[_a-zA-Z]+)]");
ParsedTemplate pt = new ParsedTemplate(basic, bindings, p);
assertThat(pt.getSpans()).containsExactly("A ", "provided", " pattern.");
assertThat(pt.getSpecificBindings()).isEmpty();
assertThat(pt.getMissingBindings()).containsExactly("provided");
assertThat(pt.getExtraBindings()).containsAll(bindings.keySet());
}
//, expectedExceptionsMessageRegExp = ".*must contain a named group called anchor.*"
@Test(expected= InvalidParameterException.class)
public void testShouldErrorOnInvalidPattern() {
String wontuse = "This won't get used.";
Pattern p = Pattern.compile("\\[(\\w[_a-zA-Z]+)]");
ParsedTemplate pt = new ParsedTemplate(wontuse, bindings, p);
}
@Test
public void testPositionalExpansionShouldBeValid() {
String multi = "A {bindname1} of {bindname2} sort.";
ParsedTemplate pt = new ParsedTemplate(multi, bindings);
assertThat(pt.getSpans()).containsExactly("A ", "bindname1", " of ", "bindname2", " sort.");
assertThat(pt.getSpecificBindings()).containsOnlyKeys("bindname1", "bindname2");
assertThat(pt.getMissingBindings()).isEmpty();
assertThat(pt.getExtraBindings()).isEmpty();
assertThat(pt.getPositionalStatement(s -> "##")).isEqualTo("A ## of ## sort.");
assertThat(pt.getPositionalStatement(s -> "[[" + s + "]]")).isEqualTo("A [[bindname1]] of [[bindname2]] sort.");
assertThat(pt.getBindPoints()).containsExactly(
new BindPoint("bindname1", "bindspec1"),
new BindPoint("bindname2", "bindspec2")
);
}
}

View File

@ -0,0 +1,18 @@
package io.virtdata.templates;
import io.virtdata.core.BindingsTemplate;
import org.junit.Test;
public class StringBindingsTemplateTest {
// , expectedExceptionsMessageRegExp = ".*not provided in the bindings: \\[two, three\\]")
@Test(expected = RuntimeException.class)
public void testUnqualifiedBindings() {
BindingsTemplate bt1 = new BindingsTemplate();
bt1.addFieldBinding("one", "Identity()");
String template="{one} {two} {three}\n";
StringBindingsTemplate sbt = new StringBindingsTemplate(template,bt1);
StringBindings resolved = sbt.resolve();
}
}

View File

@ -0,0 +1,31 @@
package io.virtdata.templates;
import org.junit.Test;
import static org.assertj.core.api.Assertions.assertThat;
public class StringCompositorTest {
@Test
public void testShouldMatchSpanOnly() {
StringCompositor c = new StringCompositor("A");
String[] spans = c.parseTemplate("A\\{ {one}two");
assertThat(spans).containsExactly("A\\{ ", "one", "two");
}
@Test
public void testShouldNotMatchEscaped() {
StringCompositor c = new StringCompositor("A");
String[] spans = c.parseTemplate("A\\{{B}C");
assertThat(spans).containsExactly("A\\{","B","C");
}
// @Test
// public void testShoulsIgnoreExplicitExcapes() {
// StringCompositor c = new StringCompositor("A");
// String[] spans = c.parseTemplate("A\\{B}C");
// assertThat(spans).containsExactly("A\\{B}C");
// }
}

View File

@ -0,0 +1,28 @@
package io.virtdata.testmappers;
import io.virtdata.annotations.ThreadSafeMapper;
import java.util.function.LongFunction;
@ThreadSafeMapper
public class TestableTemplate implements LongFunction<String> {
private LongFunction<?>[] funcs;
private String separator;
public TestableTemplate(String separator, LongFunction<?>... funcs) {
this.funcs = funcs;
this.separator = separator;
}
@Override
public String apply(long value) {
StringBuilder sb = new StringBuilder();
for (LongFunction<?> func : funcs) {
sb.append(func.apply(value).toString());
sb.append(separator);
}
sb.setLength(sb.length()-separator.length());
return sb.toString();
}
}

Some files were not shown because too many files have changed in this diff Show More