Wie am besten Java in C++ Programm umwandeln?
-
Nabend, bevor ich noch lange herumraten muss oder bei der KI nachfrage... Wie sähe das Pendant in C++ zu dieser Main-Methode in Java aus?
private enum Symbol { SLEEP1, TARGET1, ACTION1, ACTION2 } public static void main(String[] args) { if (args.length == 0) { exitApp(); } long sleep = 100; String target1 = "127.0.0.1"; Map<Integer, Map<Symbol, Integer>> fsm = new HashMap<>(); fsm.put( 0, Map.of( Symbol.SLEEP1, 1, Symbol.TARGET1, 2, Symbol.ACTION1, 3, Symbol.ACTION2, 3)); fsm.put( 1, Map.of( Symbol.TARGET1, 3, Symbol.ACTION1, 3, Symbol.ACTION2, 3)); fsm.put( 2, Map.of( Symbol.SLEEP1, 3, Symbol.ACTION1, 3, Symbol.ACTION2, 3)); fsm.put( 3, Map.of( Symbol.ACTION1, 3, Symbol.ACTION2, 3)); List<Runnable> runnables = new LinkedList<>(); int state = 0; for (String arg : args) { String[] parts = arg.split("=", 2); if (parts.length != 2) { exitApp(); } String key = parts[0]; String value = parts[1]; switch (key) { case "target1" -> { if (!fsm.get(state).containsKey(Symbol.TARGET1)) { exitApp(); } target1 = value; state = fsm.get(state).get(Symbol.TARGET1); } case "sleep" -> { if (!fsm.get(state).containsKey(Symbol.SLEEP1)) { exitApp(); } sleep = checkAndParse1(value); state = fsm.get(state).get(Symbol.SLEEP1); } case "a", "b" -> { switch (key) { case "a" -> { if (!fsm.get(state).containsKey(Symbol.ACTION1)) { exitApp(); } String finalTarget = target1; int finalNum = checkAndParse2(value); long finalSleep = sleep; runnables.add(() -> action1(finalTarget, finalNum)); runnables.add(() -> action3(finalSleep)); state = fsm.get(state).get(Symbol.ACTION1); } case "b" -> { if (!fsm.get(state).containsKey(Symbol.ACTION2)) { exitApp(); } String finalTarget = target1; int finalNum = checkAndParse2(value); long finalSleep = sleep; runnables.add(() -> action2(finalTarget, finalNum, 1000)); runnables.add(() -> action3(finalSleep)); state = fsm.get(state).get(Symbol.ACTION2); } default -> exitApp(); } } default -> exitApp(); } } if (runnables.isEmpty()) { exitApp(); } runnables.remove(runnables.size() - 1); // Remove last action // Run all actions runnables.forEach(Runnable::run); }Vermutlich ginge es (viel) einfacher, da C++ ja Funktionspointer kennt?
-
@Lennox Wie wäre es, wenn du es erstmal selbst versuchst?
-
@Schlangenmensch
Ja gut, ich versuche es erst selbst... aber erwartet keine Wunder von mir...Die FSM (also das argument parsing...) ist im Prinzip so, dass eine beliebige Reihenfolge von target1 und/oder sleep1 erlaubt ist, aber die a/b-Auflistung immer danach folgen muss...
Beispiel:
program.exe target=1.1.1.1 sleep=2000 a=1 b=3 a=1
Oder auch:
program.exe a=1
program.exe a=1 b=3 a=1
program.exe sleep=2000 a=1 b=3 a=1
program.exe target=1.1.1.1 a=1 b=3 a=1
program.exe sleep=2000 target=1.1.1.1 a=1 b=3 a=1Jetzt sollte es deutlich sein. Ungültig wäre z. B.: program.exe target=1.1.1.1
Muster:
program.exe (sleep=<int_ms>) (target=<ip/host>) [a/b]=<int> ...Ich war mir erst nicht sicher, ob man dafür wirklich eine FSM braucht, aber offenbar genügt ein einfacher https://de.wikipedia.org/wiki/Behavior_Tree für die Verarbeitung der Argumente und das Starten der Runnables nicht, oder?
-
@Lennox Macht das Programm denn in Java was du erwartest? Ich sehe auf Anhieb nämlich nicht, warum dein ungültiges Beispiel von deiner
mainverworfen werden sollte. Tipp: In kleinere Teile zerlegen und Unit Tests schreibenMir ist nicht klar, warum deine State Machine brauchst? Es gibt verschiedene Dinge, die man damit lösen kann, aber um Kommandozeilenparameter zu parsen und überprüfen würde ich die jetzt nicht nehmen. Mir wäre da auch nicht klar, was die Zustände und die Zustandsübergänge sind.
Die
statevariable wird auch nur gesetzt und nirgends verwendet. D.h. du könntest den ganzen fsm Kram löschen und die Funktion würde exakt dasselbe machen.Wenn ich dich richtig verstehe, kann man ein Target angeben und man kann einen Sleep angeben. Muss man aber nicht, wenn nicht gibt es einen default.
Dann gibt es verschiedene Aktionen, die einen Parameter benötigen, (eine beliebige Nummer).
Was irgendwie eine triviale Möglichkeit wäre, wäre sowas:
#include <vector> #include <algorithm> #include <iostream> #include <string> enum class Action { A, B }; void action1(std::string target, int action) { } void action2(std::string target, int action, int magic) { } void action3(int sleep) { } int main(int argc, char* argv[]) { int i = 1; //first argument is program name std::vector<std::pair<Action, int>> actions; //default values std::string target="127.0.01"; int sleep = 1000; //parse command line while (i < argc) { std::string arg{argv[i]}; size_t equals = arg.find('='); if (equals != std::string::npos) { std::string key = arg.substr(0, equals); std::string value = arg.substr(equals + 1); if(key == "target1") { target=value; } if(key == "sleep") { sleep = std::stoi(value); } if(key == "a") { actions.emplace_back(std::pair(Action::A, std::stoi(value) )); } if(key == "b") { actions.emplace_back(std::pair(Action::B, std::stoi(value) )); } } } //Perfom actions for(auto& action : actions) { switch (action.first) { case Action::A: { action1(target, action.second); action3(sleep); break; } case Action::B: { action2(target, action.second, 1000); action3(sleep); break; } default: break; } } return 0; }
-
@Schlangenmensch sagte in Wie am besten Java in C++ Programm umwandeln?:
Macht das Programm denn in Java was du erwartest?
Ja.
Ich habe noch vergessen, eine doppelte Angabe von sleep oder target soll NICHT möglich sein. Das geht nicht ohne FSM.
@Schlangenmensch sagte in Wie am besten Java in C++ Programm umwandeln?:
Mir wäre da auch nicht klar, was die Zustände und die Zustandsübergänge sind.
Zustand: Bei welcher Eingabe man gerade ist. Übergang: vom aktuellen Zustand durch die nächste Eingabe zum folgenden Zustand.
0 = akzeptiere alles
1 = sleep wurde angegeben, es darf nur noch target oder die Liste angegeben werden
2 = target wurde angegeben, es darf nur noch sleep oder die Liste angegeben werden
3 = nur noch die Liste darf angegeben werden, gleichzeitig Endzustand@Schlangenmensch sagte in Wie am besten Java in C++ Programm umwandeln?:
Die statevariable wird auch nur gesetzt und nirgends verwendet. D.h. du könntest den ganzen fsm Kram löschen und die Funktion würde exakt dasselbe machen.
Das stimmt nicht, schaue noch mal genau hin. Wenn
fsm.get(state).containsKey(Symbol...)NICHT zutrifft, wird die Anwendung sofort beendet.
-
@Lennox sagte in Wie am besten Java in C++ Programm umwandeln?:
Ich habe noch vergessen, eine doppelte Angabe von sleep oder target soll NICHT möglich sein. Das geht nicht ohne FSM.
Oder mit jeweils einem bool Schalter.
@Lennox sagte in Wie am besten Java in C++ Programm umwandeln?:
fsm.get(state).containsKey(Symbol...)
Ah... deine erlaubten Zustandsübergänge... Kommentare wäre praktisch.
Mir scheint dein Ansatz overengineered zu sein, aber jeder so wie er mag.
-
@Schlangenmensch sagte in Wie am besten Java in C++ Programm umwandeln?:
overengineered
Na ja, Ansichtssache... Hierbei mit booleschen Variablen zu hantieren, das würde irgendwann unübersichtlich werden.
Eigentlich wollte ich nur wissen, wie
Map<Integer, Map<Symbol, Integer>> fsm = new HashMap<>();in C++ geht, sowie wie
List<Runnable> runnables = new LinkedList<>();undrunnables.forEach(Runnable::run);dann geht...Anstatt
<Runnable>dann Funktionen? Und wie ist das mit den konkreten Parametern der Funktionen?In Java kann ich einfach
runnables.add(() -> action1(finalTarget, finalNum));schreiben, wenn die Parameter effektiv final sind. Vermutlich geht das in C++ aber nicht...
-
@Lennox
std::map<int, std::map<Symbol, int>> fmt;für deine
runnablesmusst du ein bisschen schauen, da du nur Funktionspointer mit der selben Signatur in einen Container bekommst. Aberstd::functionundstd::bindsind deine Freunde.