Browse Source

Cleaned up and documented mediaMachineAPI.

David Piuva 2 years ago
parent
commit
46273d790a

+ 23 - 2
Source/DFPSR/api/mediaMachineAPI.cpp

@@ -1041,9 +1041,16 @@ static const InsSig mediaMachineInstructions[] = {
 
 
 // API implementation
 // API implementation
 
 
+static void checkMachine(MediaMachine& machine) {
+	if (machine.get() == nullptr) {
+		throwError("The given media machine does not exist!");
+	}
+}
+
 static void checkMethodIndex(MediaMachine& machine, int methodIndex) {
 static void checkMethodIndex(MediaMachine& machine, int methodIndex) {
+	checkMachine(machine);
 	if (methodIndex < 0 || methodIndex >= machine->methods.length()) {
 	if (methodIndex < 0 || methodIndex >= machine->methods.length()) {
-		throwError("Invalid method index ", methodIndex, " of 0..", (machine->methods.length() - 1), ".");
+		throwError("Invalid method index ", methodIndex, " of 0..", (machine->methods.length() - 1), "!");
 	}
 	}
 }
 }
 
 
@@ -1129,8 +1136,17 @@ OrderedImageRgbaU8 machine_getImageRgbaU8OutputByIndex(MediaMachine& machine, in
 	return accessOutputByIndex<OrderedImageRgbaU8>(((MediaMemory*)machine->memory.get())->OrderedImageRgbaU8Memory, machine->memory->current.framePointer[DataType_ImageRgbaU8], machine->methods[methodIndex], DataType_ImageRgbaU8, outputIndex);
 	return accessOutputByIndex<OrderedImageRgbaU8>(((MediaMemory*)machine->memory.get())->OrderedImageRgbaU8Memory, machine->memory->current.framePointer[DataType_ImageRgbaU8], machine->methods[methodIndex], DataType_ImageRgbaU8, outputIndex);
 }
 }
 
 
+bool machine_exists(MediaMachine& machine) {
+	return machine.get() != nullptr;
+}
+
 int machine_findMethod(MediaMachine& machine, const ReadableString& methodName) {
 int machine_findMethod(MediaMachine& machine, const ReadableString& methodName) {
-	return machine->findMethod(methodName);
+	if (!machine_exists(machine)) {
+		throwError(U"Can not look for ", methodName, U" in a media machine that does not exist!\n");
+		return -1;
+	} else {
+		return machine->findMethod(methodName);
+	}
 }
 }
 
 
 MediaMethod machine_getMethod(MediaMachine& machine, const ReadableString& methodName, int contextIndex, bool mustExist) {
 MediaMethod machine_getMethod(MediaMachine& machine, const ReadableString& methodName, int contextIndex, bool mustExist) {
@@ -1146,6 +1162,11 @@ String machine_getMethodName(MediaMachine& machine, int methodIndex) {
 	return machine->methods[methodIndex].name;
 	return machine->methods[methodIndex].name;
 }
 }
 
 
+int machine_getMethodCount(MediaMachine& machine) {
+	checkMachine(machine);
+	return machine->methods.length();
+}
+
 int machine_getInputCount(MediaMachine& machine, int methodIndex) {
 int machine_getInputCount(MediaMachine& machine, int methodIndex) {
 	checkMethodIndex(machine, methodIndex);
 	checkMethodIndex(machine, methodIndex);
 	return machine->methods[methodIndex].inputCount;
 	return machine->methods[methodIndex].inputCount;

+ 104 - 8
Source/DFPSR/api/mediaMachineAPI.h

@@ -29,35 +29,123 @@
 
 
 namespace dsr {
 namespace dsr {
 
 
+// TODO: Complete VirtualMachine with conditional jumps and document the language dialect used by MediaMachine.
+// Side-effect: Creates a media machine from Media Machine Code (*.mmc file).
+// Post-condition: Returns a reference counted MediaMachine handle to the virtual machine. 
 MediaMachine machine_create(const ReadableString& code);
 MediaMachine machine_create(const ReadableString& code);
 
 
+// Post-condition: Returns true iff machine exists.
+bool machine_exists(MediaMachine& machine);
+
+// Pre-condition:
+//   * The machine must exist.
+//     machine_exists(machine)
+// Returns the index to the method who's name matches methodName with case insensitivity in machine, or -1 if it does not exist in machine.
 int machine_findMethod(MediaMachine& machine, const ReadableString& methodName);
 int machine_findMethod(MediaMachine& machine, const ReadableString& methodName);
+
+// Assign an input argument of a method before your call to machine_executeMethod.
+// Pre-condition:
+//   * The machine must exist.
+//     machine_exists(machine)
+//   * methodIndex must refer to the method to call in machine.
+//     0 <= methodIndex < machine_getMethodCount(machine)
+//   * inputIndex must refer to an input of the method in machine.
+//     0 <= inputIndex < machine_getInputCount(machine, methodIndex)
+// Side-effect: Sets the input at inputIndex in machine's method at methodIndex to input.
 void machine_setInputByIndex(MediaMachine& machine, int methodIndex, int inputIndex, int32_t input);
 void machine_setInputByIndex(MediaMachine& machine, int methodIndex, int inputIndex, int32_t input);
 void machine_setInputByIndex(MediaMachine& machine, int methodIndex, int inputIndex, const FixedPoint& input);
 void machine_setInputByIndex(MediaMachine& machine, int methodIndex, int inputIndex, const FixedPoint& input);
 void machine_setInputByIndex(MediaMachine& machine, int methodIndex, int inputIndex, const AlignedImageU8& input);
 void machine_setInputByIndex(MediaMachine& machine, int methodIndex, int inputIndex, const AlignedImageU8& input);
 void machine_setInputByIndex(MediaMachine& machine, int methodIndex, int inputIndex, const OrderedImageRgbaU8& input);
 void machine_setInputByIndex(MediaMachine& machine, int methodIndex, int inputIndex, const OrderedImageRgbaU8& input);
+
+// Call a method in the media machine, reading from input registers and writing to output registers.
+// Pre-condition:
+//   * The machine must exist.
+//     machine_exists(machine)
+//   * All inputs of the method must be assigned before the call using the same methodIndex.
+//   * methodIndex must refer to the method to call in machine.
+//     0 <= methodIndex < machine_getMethodCount(machine)
+// Side-effect: Writes the results to output arguments.
 void machine_executeMethod(MediaMachine& machine, int methodIndex);
 void machine_executeMethod(MediaMachine& machine, int methodIndex);
+
+// Read output register at outputIndex
+// Pre-condition:
+//   * The machine must exist.
+//     machine_exists(machine)
+//   * methodIndex must refer to the method in machine's last call to machine_executeMethod.
+//     0 <= methodIndex < machine_getMethodCount(machine)
+//   * The output index must be within range.
+//     0 <= outputIndex < machine_getOutputCount(machine, methodIndex)
+// Post-condition: Returns the output at outputIndex.
 FixedPoint machine_getFixedPointOutputByIndex(MediaMachine& machine, int methodIndex, int outputIndex);
 FixedPoint machine_getFixedPointOutputByIndex(MediaMachine& machine, int methodIndex, int outputIndex);
 AlignedImageU8 machine_getImageU8OutputByIndex(MediaMachine& machine, int methodIndex, int outputIndex);
 AlignedImageU8 machine_getImageU8OutputByIndex(MediaMachine& machine, int methodIndex, int outputIndex);
 OrderedImageRgbaU8 machine_getImageRgbaU8OutputByIndex(MediaMachine& machine, int methodIndex, int outputIndex);
 OrderedImageRgbaU8 machine_getImageRgbaU8OutputByIndex(MediaMachine& machine, int methodIndex, int outputIndex);
+
+// Pre-condition:
+//   * The machine must exist.
+//     machine_exists(machine)
+// Post-condition: Returns the number of methods in machine.
+int machine_getMethodCount(MediaMachine& machine);
+
+// Pre-condition:
+//   * The machine must exist.
+//     machine_exists(machine)
+//   * methodIndex must refer to the method that you want to get the name from.
+//     0 <= methodIndex < machine_getMethodCount(machine)
+// Post-condition: Returns the name of the method at methodIndex in machine.
 String machine_getMethodName(MediaMachine& machine, int methodIndex);
 String machine_getMethodName(MediaMachine& machine, int methodIndex);
+
+// Pre-condition:
+//   * The machine must exist.
+//     machine_exists(machine)
+//   * methodIndex must refer to the method that you want to get the input count from.
+//     0 <= methodIndex < machine_getMethodCount(machine)
+// Post-condition: Returns the input argument count for the method at methodIndex in machine.
 int machine_getInputCount(MediaMachine& machine, int methodIndex);
 int machine_getInputCount(MediaMachine& machine, int methodIndex);
+
+// Pre-condition:
+//   * The machine must exist.
+//     machine_exists(machine)
+//   * methodIndex must refer to the method that you want to get the output count from.
+//     0 <= methodIndex < machine_getMethodCount(machine)
+// Post-condition: Returns the output argument count for the method at methodIndex in machine.
 int machine_getOutputCount(MediaMachine& machine, int methodIndex);
 int machine_getOutputCount(MediaMachine& machine, int methodIndex);
+
+// Pre-condition:
+//   * The machine must exist.
+//     machine_exists(machine)
+//   * methodIndex must refer to the method that you want to get an input argument's name from.
+//     0 <= methodIndex < machine_getMethodCount(machine)
+//   * The inputIndex must refer to the input argument that you want to get the name of.
+//     0 <= inputIndex < machine_getInputCount(machine, methodIndex)
+// Post-condition: Returns the input argument name at inputIndex for the method at methodIndex in machine.
 String machine_getInputName(MediaMachine& machine, int methodIndex, int inputIndex);
 String machine_getInputName(MediaMachine& machine, int methodIndex, int inputIndex);
+
+// Pre-condition:
+//   * The machine must exist.
+//     machine_exists(machine)
+//   * methodIndex must refer to the method that you want to get an output argument's name from.
+//     0 <= methodIndex < machine_getMethodCount(machine)
+//   * The outputIndex must refer to the output argument that you want to get the name of.
+//     0 <= outputIndex < machine_getOutputCount(machine, methodIndex)
+// Post-condition: Returns the output argument name at outputIndex for the method at methodIndex in machine.
 String machine_getOutputName(MediaMachine& machine, int methodIndex, int outputIndex);
 String machine_getOutputName(MediaMachine& machine, int methodIndex, int outputIndex);
 
 
-inline constexpr int argCount() {
+// Helper function counting the number of arguments given to it.
+inline constexpr int machine_argCount() {
 	return 0;
 	return 0;
 }
 }
 template<typename HEAD, typename... TAIL>
 template<typename HEAD, typename... TAIL>
-inline constexpr int argCount(HEAD& first, TAIL&... args) {
-	return argCount(args...) + 1;
+inline constexpr int machine_argCount(HEAD& first, TAIL&... args) {
+	return machine_argCount(args...) + 1;
 }
 }
 
 
-// TODO: Prevent saving the result to avoid reading after another call
+// A temporary type generated from () calls to MediaMethod, which is used for writing outputs to targets within the next ().
 class MediaResult {
 class MediaResult {
 private:
 private:
-	MediaMachine machine;
+	// Holding the machine by reference prevents storing MediaResult,
+	//   because it may not be used after other calls to the machine.
+	// It is only used to assign outputs with the () operator.
+	MediaMachine &machine;
 	int methodIndex;
 	int methodIndex;
 	void writeResult(int outputIndex, int8_t& target) {
 	void writeResult(int outputIndex, int8_t& target) {
 		target = fixedPoint_round(machine_getFixedPointOutputByIndex(this->machine, this->methodIndex, outputIndex));
 		target = fixedPoint_round(machine_getFixedPointOutputByIndex(this->machine, this->methodIndex, outputIndex));
@@ -87,12 +175,12 @@ private:
 		this->writeResults(firstInputIndex + 1, args...);
 		this->writeResults(firstInputIndex + 1, args...);
 	}
 	}
 public:
 public:
-	MediaResult(const MediaMachine& machine, int methodIndex)
+	MediaResult(MediaMachine& machine, int methodIndex)
  	: machine(machine), methodIndex(methodIndex) {}
  	: machine(machine), methodIndex(methodIndex) {}
 	// Write target references within () after a call to assign multiple outputs
 	// Write target references within () after a call to assign multiple outputs
 	template <typename... ARGS>
 	template <typename... ARGS>
 	void operator () (ARGS&... args) {
 	void operator () (ARGS&... args) {
-		int givenCount = argCount(args...);
+		int givenCount = machine_argCount(args...);
 		int expectedCount = machine_getOutputCount(this->machine, this->methodIndex);
 		int expectedCount = machine_getOutputCount(this->machine, this->methodIndex);
 		if (givenCount != expectedCount) {
 		if (givenCount != expectedCount) {
 			throwError("The call to ", machine_getMethodName(this->machine, this->methodIndex), " expected ", expectedCount, " outputs, but ", givenCount, " references were assigned.\n");
 			throwError("The call to ", machine_getMethodName(this->machine, this->methodIndex), " expected ", expectedCount, " outputs, but ", givenCount, " references were assigned.\n");
@@ -101,6 +189,13 @@ public:
 	}
 	}
 };
 };
 
 
+// How to call a MediaMethod:
+// * Using arguments in the same order as declared in the Media Machine Code.
+//     myMediaMethod(inputA, inputB, inputC...)(outputX, outputY...)
+//     This allow returning more than one return value without having to declare any structures in the virtual machine.
+// * Using keyword arguments.
+//     You can also call myMediaMethod and just define a lambda that is called with the argument name and index for each input argument.
+//     Then your function calls machine_setInputByIndex with the given arguments and the input data identified by name.
 class MediaMethod {
 class MediaMethod {
 public:
 public:
 	MediaMachine machine;
 	MediaMachine machine;
@@ -122,7 +217,7 @@ public:
 	// Useful when you know the arguments in advance.
 	// Useful when you know the arguments in advance.
 	template <typename... ARGS>
 	template <typename... ARGS>
 	MediaResult operator () (ARGS&&... args) {
 	MediaResult operator () (ARGS&&... args) {
-		int givenCount = argCount(args...);
+		int givenCount = machine_argCount(args...);
 		int expectedCount = machine_getInputCount(this->machine, this->methodIndex);
 		int expectedCount = machine_getInputCount(this->machine, this->methodIndex);
 		if (givenCount != expectedCount) {
 		if (givenCount != expectedCount) {
 			throwError("The call to ", machine_getMethodName(this->machine, this->methodIndex), " expected ", expectedCount, " inputs, but ", givenCount, " values were given.\n");
 			throwError("The call to ", machine_getMethodName(this->machine, this->methodIndex), " expected ", expectedCount, " inputs, but ", givenCount, " values were given.\n");
@@ -138,6 +233,7 @@ public:
 	MediaResult callUsingKeywords(std::function<void(MediaMachine &machine, int methodIndex, int inputIndex, const ReadableString &argumentName)> setInputAction);
 	MediaResult callUsingKeywords(std::function<void(MediaMachine &machine, int methodIndex, int inputIndex, const ReadableString &argumentName)> setInputAction);
 };
 };
 
 
+// Post-condition: Returns a MediaMethod structure, which can be stored as a reference counting function pointer that keeps the virtual machine alive.
 MediaMethod machine_getMethod(MediaMachine& machine, const ReadableString& methodName, int contextIndex, bool mustExist = true);
 MediaMethod machine_getMethod(MediaMachine& machine, const ReadableString& methodName, int contextIndex, bool mustExist = true);
 
 
 }
 }

+ 1 - 1
Source/DFPSR/gui/VisualComponent.cpp

@@ -662,7 +662,7 @@ bool VisualComponent::managesChildren() {
 }
 }
 
 
 MediaResult dsr::component_generateImage(VisualTheme theme, MediaMethod &method, int width, int height, int red, int green, int blue, int pressed, int focused, int hover) {
 MediaResult dsr::component_generateImage(VisualTheme theme, MediaMethod &method, int width, int height, int red, int green, int blue, int pressed, int focused, int hover) {
-	return method.callUsingKeywords([&theme, &method, width, height, red, green, blue, pressed, focused, hover](MediaMachine &machine, int methodIndex, int inputIndex, const ReadableString &argumentName){
+	return method.callUsingKeywords([&theme, &method, width, height, red, green, blue, pressed, focused, hover](MediaMachine &machine, int methodIndex, int inputIndex, const ReadableString &argumentName) {
 		if (string_caseInsensitiveMatch(argumentName, U"width")) {
 		if (string_caseInsensitiveMatch(argumentName, U"width")) {
 			machine_setInputByIndex(machine, methodIndex, inputIndex, width);
 			machine_setInputByIndex(machine, methodIndex, inputIndex, width);
 		} else if (string_caseInsensitiveMatch(argumentName, U"height")) {
 		} else if (string_caseInsensitiveMatch(argumentName, U"height")) {