rusefi/java_tools/configuration_definition_base/src/main/java/com/rusefi/output/GetOutputValueConsumer.java

141 lines
5.1 KiB
Java

package com.rusefi.output;
import com.rusefi.ConfigField;
import com.rusefi.ReaderState;
import com.rusefi.parse.TypesHelper;
import com.rusefi.output.variables.VariableRecord;
import com.rusefi.util.LazyFile;
import org.jetbrains.annotations.NotNull;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.concurrent.atomic.AtomicInteger;
import static com.rusefi.output.ConfigStructureImpl.ALIGNMENT_FILL_AT;
import static com.rusefi.output.DataLogConsumer.UNUSED;
import static com.rusefi.output.GetConfigValueConsumer.getCompareName;
/**
* here we generate C++ code needed for https://github.com/rusefi/rusefi/wiki/Lua-Scripting#getoutputname implementation
*
* @see GetConfigValueConsumer
*/
@SuppressWarnings("StringConcatenationInsideStringBufferAppend")
public class GetOutputValueConsumer implements ConfigurationConsumer {
private final List<VariableRecord> getterPairs = new ArrayList<>();
private final String fileName;
private final LazyFile.LazyFileFactory fileFactory;
public String currentSectionPrefix = "engine->outputChannels";
public boolean moduleMode;
public String currentEngineModule;
public String conditional;
public Boolean isPtr = false;
public GetOutputValueConsumer(String fileName, LazyFile.LazyFileFactory fileFactory) {
this.fileName = fileName;
this.fileFactory = fileFactory;
}
@Override
public void handleEndStruct(ReaderState state, ConfigStructure structure) throws IOException {
if (state.isStackEmpty()) {
PerFieldWithStructuresIterator iterator = new PerFieldWithStructuresIterator(state, structure.getTsFields(), "",
(readerState, cf, prefix) -> processOutput(cf, prefix), ".");
iterator.loop();
}
}
private String processOutput(ConfigField cf, String prefix) {
if (cf.getName().contains(UNUSED) || cf.getName().contains(ALIGNMENT_FILL_AT))
return "";
if (cf.isArray() || cf.isFromIterate() || cf.isDirective())
return "";
if (!TypesHelper.isPrimitive(cf.getTypeName()) && !TypesHelper.isBoolean(cf.getTypeName())) {
return "";
}
String userName = prefix + cf.getName();
String javaName;
if (moduleMode) {
javaName = "engine->module<" + currentEngineModule + ">()->" + prefix;
} else {
javaName = currentSectionPrefix + (isPtr ? "->" : ".") + prefix;
}
getterPairs.add(new VariableRecord(userName, javaName + cf.getName(), null, conditional));
return "";
}
@Override
public void endFile() throws IOException {
GetConfigValueConsumer.writeStringToFile(fileName, getContent(), fileFactory);
}
public String getContent() {
StringBuilder switchBody = new StringBuilder();
StringBuilder getterBody = getGetters(switchBody, getterPairs);
String fullSwitch = wrapSwitchStatement(switchBody);
return "#if !EFI_UNIT_TEST\n" +
GetConfigValueConsumer.getHeader(getClass()) +
"float getOutputValueByName(const char *name) {\n" +
fullSwitch +
getterBody + GetConfigValueConsumer.GET_METHOD_FOOTER +
"#endif\n";
}
@NotNull
static String wrapSwitchStatement(StringBuilder switchBody) {
String fullSwitch = switchBody.length() == 0 ? "" :
("\tint hash = djb2lowerCase(name);\n" +
"\tswitch(hash) {\n" + switchBody + "\t}\n");
return fullSwitch;
}
@NotNull
static StringBuilder getGetters(StringBuilder switchBody, List<VariableRecord> getterPairs) {
HashMap<Integer, AtomicInteger> hashConflicts = getHashConflicts(getterPairs);
StringBuilder getterBody = new StringBuilder();
for (VariableRecord pair : getterPairs) {
String returnLine = "\t\treturn " + pair.getFullName() + ";\n";
String conditional = pair.getConditional();
String before = conditional == null ? "" : "#if " + conditional + "\n";
String after = conditional == null ? "" : "#endif\n";
int hash = HashUtil.hash(pair.getUserName());
if (hashConflicts.get(hash).get() == 1) {
switchBody.append("// " + pair.getUserName() + "\n");
switchBody.append(before);
switchBody.append("\t\tcase " + hash + ":\n");
switchBody.append("\t" + returnLine);
switchBody.append(after);
} else {
getterBody.append(getCompareName(pair.getUserName()));
getterBody.append(returnLine);
}
}
return getterBody;
}
@NotNull
static HashMap<Integer, AtomicInteger> getHashConflicts(List<VariableRecord> getterPairs) {
HashMap<Integer, AtomicInteger> hashConflicts = new HashMap<>();
for (VariableRecord pair : getterPairs) {
hashConflicts.computeIfAbsent(HashUtil.hash(pair.getUserName()), integer -> new AtomicInteger(0)).incrementAndGet();
}
return hashConflicts;
}
}