mirror of
https://github.com/nosqlbench/nosqlbench.git
synced 2025-02-25 18:55:28 -06:00
import virtdata
This commit is contained in:
parent
0b733bfa1d
commit
62d53ecec6
16
virtdata-annotations/pom.xml
Normal file
16
virtdata-annotations/pom.xml
Normal 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>
|
@ -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();
|
||||
}
|
@ -0,0 +1,12 @@
|
||||
package io.virtdata.annotations;
|
||||
|
||||
public enum Category {
|
||||
datetime,
|
||||
state,
|
||||
distributions,
|
||||
diagnostics,
|
||||
conversion,
|
||||
collections,
|
||||
premade,
|
||||
nulls, functional, general
|
||||
}
|
@ -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();
|
||||
}
|
@ -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();
|
||||
}
|
@ -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();
|
||||
|
||||
}
|
@ -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+"'");
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
@ -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();
|
||||
}
|
@ -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();
|
||||
}
|
@ -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 {
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
@ -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();
|
||||
}
|
@ -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();
|
||||
}
|
@ -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 {
|
||||
}
|
@ -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();
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
@ -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");
|
||||
}});
|
||||
}}
|
||||
));
|
||||
|
||||
}};
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
13
virtdata-api/docs/types.puml
Normal file
13
virtdata-api/docs/types.puml
Normal 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
77
virtdata-api/pom.xml
Normal 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>
|
15
virtdata-api/src/main/java/io/virtdata/api/Binder.java
Normal file
15
virtdata-api/src/main/java/io/virtdata/api/Binder.java
Normal 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);
|
||||
}
|
@ -0,0 +1,5 @@
|
||||
package io.virtdata.api;
|
||||
|
||||
public interface DataMapper<R> {
|
||||
R get(long input);
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
||||
|
||||
}
|
69
virtdata-api/src/main/java/io/virtdata/api/FunctionType.java
Normal file
69
virtdata-api/src/main/java/io/virtdata/api/FunctionType.java
Normal 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;
|
||||
}
|
||||
}
|
10
virtdata-api/src/main/java/io/virtdata/api/Named.java
Normal file
10
virtdata-api/src/main/java/io/virtdata/api/Named.java
Normal 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();
|
||||
}
|
11
virtdata-api/src/main/java/io/virtdata/api/VALUE.java
Normal file
11
virtdata-api/src/main/java/io/virtdata/api/VALUE.java
Normal 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.
|
||||
}
|
91
virtdata-api/src/main/java/io/virtdata/api/ValueType.java
Normal file
91
virtdata-api/src/main/java/io/virtdata/api/ValueType.java
Normal 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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
30
virtdata-api/src/main/java/io/virtdata/api/ValuesBinder.java
Normal file
30
virtdata-api/src/main/java/io/virtdata/api/ValuesBinder.java
Normal 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);
|
||||
}
|
@ -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);
|
||||
}
|
@ -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")));
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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");
|
||||
|
||||
}
|
||||
}
|
||||
}
|
@ -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");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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");
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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());
|
||||
}
|
||||
|
||||
}
|
@ -0,0 +1,8 @@
|
||||
package io.virtdata.api.config;
|
||||
|
||||
import java.util.Map;
|
||||
|
||||
public interface ConfigAware {
|
||||
void applyConfig(Map<String,?> element);
|
||||
ConfigModel getConfigModel();
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
354
virtdata-api/src/main/java/io/virtdata/core/Bindings.java
Normal file
354
virtdata-api/src/main/java/io/virtdata/core/Bindings.java
Normal 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 -> val1</li>
|
||||
* <li>gamma -> val2</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* <li>
|
||||
* <ul>
|
||||
* <li>alpha -> val3</li>
|
||||
* <li>gamma -> val4</li>
|
||||
* </ul>
|
||||
* </li>
|
||||
* <li>
|
||||
* <ul>
|
||||
* <li>alpha -> val5</li>
|
||||
* <li>gamma -> 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 -> val1</li>
|
||||
* <li>gamma0 -> val2</li>
|
||||
* <li>alpha1 -> val3</li>
|
||||
* <li>gamma1 -> val4</li>
|
||||
* <li>alpha2 -> val5</li>
|
||||
* <li>gamma2 -> 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<String,Object>
|
||||
* @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<String,Object>
|
||||
* @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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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+")";
|
||||
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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.");
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
276
virtdata-api/src/main/java/io/virtdata/core/VirtData.java
Normal file
276
virtdata-api/src/main/java/io/virtdata/core/VirtData.java
Normal 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());
|
||||
}
|
||||
|
||||
}
|
@ -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<?>, LongFunction<?>, and in the worst case, Function<?,?>.
|
||||
* 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<List> 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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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;
|
||||
// }
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
335
virtdata-api/src/main/java/io/virtdata/core/murmur/Murmur3F.java
Normal file
335
virtdata-api/src/main/java/io/virtdata/core/murmur/Murmur3F.java
Normal 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);
|
||||
}
|
||||
|
||||
}
|
@ -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 + '\'' +
|
||||
'}';
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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 (?<anchor>...)
|
||||
* </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;
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
@ -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);
|
||||
}
|
||||
|
||||
}
|
@ -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);
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
|
||||
}
|
@ -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");
|
||||
|
||||
}
|
||||
|
||||
}
|
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
@ -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() {
|
||||
}
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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")
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
}
|
@ -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();
|
||||
}
|
||||
|
||||
}
|
@ -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");
|
||||
// }
|
||||
|
||||
}
|
@ -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
Loading…
Reference in New Issue
Block a user