Răsfoiți Sursa

Made a Callback alias for std::function that can be used until a custom implementation is completed.

David Piuva 3 ore în urmă
părinte
comite
bf69a1fcfb

+ 0 - 1
Source/DFPSR/api/bufferAPI.h

@@ -26,7 +26,6 @@
 
 #include <cstdint>
 #include <memory>
-#include <functional>
 #include "../base/SafePointer.h"
 #include "../settings.h"
 #include "../base/Handle.h"

+ 2 - 2
Source/DFPSR/api/configAPI.h

@@ -25,12 +25,12 @@
 #define DFPSR_API_CONFIG
 
 #include "stringAPI.h"
-#include <functional>
+#include "../base/Callback.h"
 
 namespace dsr {
 	// A type of function sending (block, key, value) to the caller.
 	//   One can have hard-coded options, lookup-tables, dictionaries, et cetera for looking up the given key names.
-	using ConfigIniCallback = std::function<void(const ReadableString& block, const ReadableString& key, const ReadableString& value)>;
+	using ConfigIniCallback = Callback<void(const ReadableString& block, const ReadableString& key, const ReadableString& value)>;
 	/*
 		Parsing the given content of a *.ini configuration file.
 		Sending callbacks to receiverLambda for each key being assigned a value.

+ 2 - 2
Source/DFPSR/api/fileAPI.cpp

@@ -586,7 +586,7 @@ EntryType file_getEntryType(const ReadableString &path) {
 	return result;
 }
 
-bool file_getFolderContent(const ReadableString& folderPath, std::function<void(const ReadableString& entryPath, const ReadableString& entryName, EntryType entryType)> action) {
+bool file_getFolderContent(const ReadableString& folderPath, Callback<void(const ReadableString& entryPath, const ReadableString& entryName, EntryType entryType)> action) {
 	String optimizedPath = file_optimizePath(folderPath, LOCAL_PATH_SYNTAX);
 	#ifdef USE_MICROSOFT_WINDOWS
 		String pattern = file_combinePaths(optimizedPath, U"*.*", LOCAL_PATH_SYNTAX);
@@ -639,7 +639,7 @@ bool file_getFolderContent(const ReadableString& folderPath, std::function<void(
 	return true;
 }
 
-void file_getPathEntries(const ReadableString& path, std::function<void(ReadableString, int64_t, int64_t)> action) {
+void file_getPathEntries(const ReadableString& path, Callback<void(ReadableString, int64_t, int64_t)> action) {
 	int64_t sectionStart = 0;
 	int64_t length = string_length(path);
 	for (int64_t i = 0; i < string_length(path); i++) {

+ 2 - 2
Source/DFPSR/api/fileAPI.h

@@ -98,7 +98,7 @@ namespace dsr {
 	// The first entry must be something selectable to be included. Otherwise it is ignored.
 	//   C: would be returned as an entry, because other drives can be selected.
 	//   The implicit Windows drive \ and Posix system root / will not be returned, because they are implicit and can't be replaced in the path.
-	void file_getPathEntries(const ReadableString& path, std::function<void(ReadableString, int64_t, int64_t)> action);
+	void file_getPathEntries(const ReadableString& path, Callback<void(ReadableString, int64_t, int64_t)> action);
 
 	// Path-syntax: Depends on pathSyntax argument.
 	// Turns / and \ into the path convention specified by pathSyntax, which is the local system's by default.
@@ -258,7 +258,7 @@ namespace dsr {
 	//               entryName equals file_getPathlessName(entryPath).
 	//               entryType equals file_getEntryType(entryPath).
 	// Post-condition: Returns true iff the folder could be found.
-	bool file_getFolderContent(const ReadableString& folderPath, std::function<void(const ReadableString& entryPath, const ReadableString& entryName, EntryType entryType)> action);
+	bool file_getFolderContent(const ReadableString& folderPath, Callback<void(const ReadableString& entryPath, const ReadableString& entryName, EntryType entryType)> action);
 
 	// Path-syntax: According to the local computer.
 	// Access permissions: Default settings according to the local operating system, either inherited from the parent folder or no specific restrictions.

+ 4 - 4
Source/DFPSR/api/filterAPI.h

@@ -26,7 +26,7 @@
 #define DFPSR_API_FILTER
 
 #include "../implementation/image/Image.h"
-#include <functional>
+#include "../base/Callback.h"
 
 namespace dsr {
 
@@ -51,9 +51,9 @@ namespace dsr {
 //   Create images from Lambda expressions when speed is not critical.
 //     Capture images within [] and sample pixels from them using image_readPixel_border, image_readPixel_clamp and image_readPixel_tile.
 	// Lambda expressions for generating integer images.
-	using ImageGenRgbaU8 = std::function<ColorRgbaI32(int32_t x, int32_t y)>;
-	using ImageGenI32 = std::function<int32_t(int32_t x, int32_t y)>; // Used for U8 and U16 images using different saturations.
-	using ImageGenF32 = std::function<float(int32_t x, int32_t y)>;
+	using ImageGenRgbaU8 = Callback<ColorRgbaI32(int32_t x, int32_t y)>;
+	using ImageGenI32 = Callback<int32_t(int32_t x, int32_t y)>; // Used for U8 and U16 images using different saturations.
+	using ImageGenF32 = Callback<float(int32_t x, int32_t y)>;
 	// In-place image generation to an existing image.
 	//   The pixel at the upper left corner gets (startX, startY) as x and y arguments to the function.
 	void filter_mapRgbaU8(const ImageRgbaU8 &target, const ImageGenRgbaU8& lambda, int32_t startX = 0, int32_t startY = 0);

+ 2 - 2
Source/DFPSR/api/guiAPI.cpp

@@ -146,7 +146,7 @@ Component dsr::component_getChild(const Component& parent, int32_t childIndex) {
 	}
 }
 
-static void findAllComponentsByName(const Component& component, const ReadableString& name, std::function<void(Component, int32_t)> callback) {
+static void findAllComponentsByName(const Component& component, const ReadableString& name, Callback<void(Component, int32_t)> callback) {
 	if (component_exists(component)) {
 		// Check if the current component matches
 		if (string_match(component->getName(), name)) {
@@ -159,7 +159,7 @@ static void findAllComponentsByName(const Component& component, const ReadableSt
 		}
 	}
 }
-void dsr::window_findAllComponentsByName(const Window& window, const ReadableString& name, std::function<void(Component, int32_t)> callback) {
+void dsr::window_findAllComponentsByName(const Window& window, const ReadableString& name, Callback<void(Component, int32_t)> callback) {
 	MUST_EXIST(window, window_findAllComponentsByName);
 	findAllComponentsByName(window->getRootComponent(), name, callback);
 }

+ 1 - 1
Source/DFPSR/api/guiAPI.h

@@ -127,7 +127,7 @@ namespace dsr {
 	// To allow detaching components while iterating over the list of children, order is reversed for child components.
 	// Raises an exception if window doesn't exist.
 	// Component names are case sensitive to reduce the risk of accidental naming conflicts among many components.
-	void window_findAllComponentsByName(const Window& window, const ReadableString& name, std::function<void(Component component, int32_t index)> callback);
+	void window_findAllComponentsByName(const Window& window, const ReadableString& name, Callback<void(Component component, int32_t index)> callback);
 
 // The three main events to run in a loop at the end of the main function
 	// If the window's event queue contained any resize of the window, the canvas and the depth buffer will be replaced during this call.

+ 1 - 1
Source/DFPSR/api/mediaMachineAPI.cpp

@@ -1197,7 +1197,7 @@ String machine_getOutputName(const MediaMachine& machine, int32_t methodIndex, i
 	return method->locals[method->inputCount + outputIndex].name;
 }
 
-MediaResult MediaMethod::callUsingKeywords(std::function<void(MediaMachine &machine, int32_t methodIndex, int32_t inputIndex, const ReadableString &argumentName)> setInputAction) {
+MediaResult MediaMethod::callUsingKeywords(Callback<void(MediaMachine &machine, int32_t methodIndex, int32_t inputIndex, const ReadableString &argumentName)> setInputAction) {
 	if (this->methodIndex < 0 || this->methodIndex >= this->machine->methods.length()) {
 		throwError(U"Method index ", this->methodIndex, U" is out of bound 0..", this->machine->methods.length() - 1, U"\n");
 	}

+ 1 - 1
Source/DFPSR/api/mediaMachineAPI.h

@@ -239,7 +239,7 @@ public:
 	// The function setInputAction should simply make a call to machine_setInputByIndex with the provided machine, methodIndex, inputIndex and the value corresponding to argumentName in setInputAction.
 	// If you don't recognize argumentName, then throw an exception because default input arguments are currently not implemented.
 	// Useful when the called function can be extended or reduced with only the arguments needed.
-	MediaResult callUsingKeywords(std::function<void(MediaMachine &machine, int32_t methodIndex, int32_t inputIndex, const ReadableString &argumentName)> setInputAction);
+	MediaResult callUsingKeywords(Callback<void(MediaMachine &machine, int32_t methodIndex, int32_t 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.

+ 4 - 4
Source/DFPSR/api/soundAPI.cpp

@@ -9,7 +9,7 @@ namespace dsr {
 
 // See the Source/soundManagers folder for implementations of sound_streamToSpeakers for different operating systems.
 
-bool sound_streamToSpeakers_fixed(int32_t channels, int32_t sampleRate, int32_t periodSamplesPerChannel, std::function<bool(SafePointer<float> fixedTarget)> soundOutput) {
+bool sound_streamToSpeakers_fixed(int32_t channels, int32_t sampleRate, int32_t periodSamplesPerChannel, Callback<bool(SafePointer<float> fixedTarget)> soundOutput) {
 	int32_t bufferSamplesPerChannel = 0;
 	int32_t blockBytes = channels * sizeof(float);
 	Buffer fixedBuffer;
@@ -251,7 +251,7 @@ static String readChar4(SafePointer<const uint8_t> nameStart) {
 	return name;
 }
 
-static void getRiffChunks(const Chunk &parentChunk, std::function<void(const ReadableString &name, const Chunk &chunk)> returnChunk) {
+static void getRiffChunks(const Chunk &parentChunk, Callback<void(const ReadableString &name, const Chunk &chunk)> returnChunk) {
 	SafePointer<const uint8_t> chunkStart = parentChunk.chunkStart;
 	SafePointer<const uint8_t> chunkEnd = chunkStart + parentChunk.chunkSize;
 	while (chunkStart.getUnchecked() + 8 <= chunkEnd.getUnchecked()) {
@@ -267,7 +267,7 @@ static void getRiffChunks(const Chunk &parentChunk, std::function<void(const Rea
 	}
 }
 
-static void getRiffChunks(const Buffer &fileBuffer, std::function<void(const ReadableString &name, const Chunk &chunk)> returnChunk) {
+static void getRiffChunks(const Buffer &fileBuffer, Callback<void(const ReadableString &name, const Chunk &chunk)> returnChunk) {
 	Chunk rootChunk = Chunk(U"RIFF", fileBuffer);
 	getRiffChunks(rootChunk, [&returnChunk](const ReadableString &name, const Chunk &chunk) {
 		if (string_match(name, U"RIFF")) {
@@ -440,7 +440,7 @@ bool sound_save_RiffWave(const ReadableString& filename, const SoundBuffer &soun
 	}
 }
 
-SoundBuffer sound_generate_function(uint32_t samplesPerChannel, uint32_t channelCount, uint32_t sampleRate, std::function<float(double time, uint32_t channelIndex)> generator) {
+SoundBuffer sound_generate_function(uint32_t samplesPerChannel, uint32_t channelCount, uint32_t sampleRate, Callback<float(double time, uint32_t channelIndex)> generator) {
 	SoundBuffer result = sound_create(samplesPerChannel, channelCount, sampleRate);
 	SafePointer<float> target = sound_getSafePointer(result);
 	double time = 0.0;

+ 3 - 3
Source/DFPSR/api/soundAPI.h

@@ -23,14 +23,14 @@ namespace dsr {
 	//   Call sound_streamToSpeakers with desired channels and sampleRate from a separate thread.
 	//   Handle callbacks to soundOutput by feeding the next packed sound samples and letting it return false when done.
 	//   Close the thread and let the sound engine clean up resources.
-	bool sound_streamToSpeakers(int32_t channels, int32_t sampleRate, std::function<bool(dsr::SafePointer<float> target, int32_t length)> soundOutput);
+	bool sound_streamToSpeakers(int32_t channels, int32_t sampleRate, Callback<bool(dsr::SafePointer<float> target, int32_t length)> soundOutput);
 
 	// Wrapper for sound_streamToSpeakers to allow working with a fixed size period for better determinism across different hardware.
 	//   The target elements should be filled for indices 0 to (periodSamplesPerChannel * channels) - 1
 	// This allow using SIMD vectorization with a perfectly aligned period size without wasting any padding, even if the hardware's period size is an odd number.
 	// A fixed period can also be used for perfect timing when playing music.
 	// Pre-condition: periodSamplesPerChannel must be a power of two.
-	bool sound_streamToSpeakers_fixed(int32_t channels, int32_t sampleRate, int32_t periodSamplesPerChannel, std::function<bool(dsr::SafePointer<float> target)> soundOutput);
+	bool sound_streamToSpeakers_fixed(int32_t channels, int32_t sampleRate, int32_t periodSamplesPerChannel, Callback<bool(dsr::SafePointer<float> target)> soundOutput);
 
 	// A sound buffer with packed channels of 32-bit floats.
 	// The duration in seconds equals samplesPerChannel / sampleRate
@@ -55,7 +55,7 @@ namespace dsr {
 
 	inline SafePointer<float> sound_getSafePointer(const SoundBuffer &sound) { return buffer_getSafeData<float>(sound.impl_samples, "Sound buffer"); }
 
-	SoundBuffer sound_generate_function(uint32_t samplesPerChannel, uint32_t channelCount, uint32_t sampleRate, std::function<float(double time, uint32_t channelIndex)> generator);
+	SoundBuffer sound_generate_function(uint32_t samplesPerChannel, uint32_t channelCount, uint32_t sampleRate, Callback<float(double time, uint32_t channelIndex)> generator);
 
 	enum class RiffWaveFormat {
 		RawU8,

+ 7 - 7
Source/DFPSR/api/stringAPI.cpp

@@ -134,7 +134,7 @@ static void generateCharacterRange(String &result, DsrChar firstIn, DsrChar last
 	}
 }
 // Pre-condition: The transform function must change at least one character.
-static String generateCharacterMapping(std::function<DsrChar(const DsrChar character)> transform, DsrChar first, DsrChar last) {
+static String generateCharacterMapping(Callback<DsrChar(const DsrChar character)> transform, DsrChar first, DsrChar last) {
 	String result;
 	int64_t rangeStart = -1;
 	int64_t rangeEnd = -1;
@@ -965,11 +965,11 @@ void dsr::string_fromDouble(String& target, double value, int decimalCount, bool
 
 // A function definition for receiving a stream of bytes
 //   Instead of using std's messy inheritance
-using ByteWriterFunction = std::function<void(uint8_t value)>;
+using ByteWriterFunction = Callback<void(uint8_t value)>;
 
 // A function definition for receiving a stream of UTF-32 characters
 //   Instead of using std's messy inheritance
-using UTF32WriterFunction = std::function<void(DsrChar character)>;
+using UTF32WriterFunction = Callback<void(DsrChar character)>;
 
 // Filter out unwanted characters for improved portability
 static void feedCharacter(const UTF32WriterFunction &receiver, DsrChar character) {
@@ -1486,7 +1486,7 @@ static std::ostream& toStream(std::ostream& out, const ReadableString &source) {
 	return out;
 }
 
-static const std::function<void(const ReadableString &message, MessageType type)> defaultMessageAction = [](const ReadableString &message, MessageType type) {
+static const Callback<void(const ReadableString &message, MessageType type)> defaultMessageAction = [](const ReadableString &message, MessageType type) {
 	if (type == MessageType::Error) {
 		#ifdef DSR_HARD_EXIT_ON_ERROR
 			// Print the error.
@@ -1506,7 +1506,7 @@ static const std::function<void(const ReadableString &message, MessageType type)
 	}
 };
 
-static std::function<void(const ReadableString &message, MessageType type)> globalMessageAction = defaultMessageAction;
+static Callback<void(const ReadableString &message, MessageType type)> globalMessageAction = defaultMessageAction;
 
 void dsr::string_sendMessage(const ReadableString &message, MessageType type) {
 	globalMessageAction(message, type);
@@ -1516,7 +1516,7 @@ void dsr::string_sendMessage_default(const ReadableString &message, MessageType
 	defaultMessageAction(message, type);
 }
 
-void dsr::string_assignMessageHandler(std::function<void(const ReadableString &message, MessageType type)> newHandler) {
+void dsr::string_assignMessageHandler(Callback<void(const ReadableString &message, MessageType type)> newHandler) {
 	globalMessageAction = newHandler;
 }
 
@@ -1524,7 +1524,7 @@ void dsr::string_unassignMessageHandler() {
 	globalMessageAction = defaultMessageAction;
 }
 
-void dsr::string_split_callback(std::function<void(ReadableString separatedText)> action, const ReadableString& source, DsrChar separator, bool removeWhiteSpace) {
+void dsr::string_split_callback(Callback<void(ReadableString separatedText)> action, const ReadableString& source, DsrChar separator, bool removeWhiteSpace) {
 	intptr_t sectionStart = 0;
 	for (intptr_t i = 0; i < source.view.length; i++) {
 		DsrChar c = source[i];

+ 4 - 4
Source/DFPSR/api/stringAPI.h

@@ -25,7 +25,7 @@
 #define DFPSR_API_STRING
 
 #include <cstdint>
-#include <functional>
+#include "../base/Callback.h"
 #include "bufferAPI.h"
 #include "../base/SafePointer.h"
 #include "../base/DsrTraits.h"
@@ -417,9 +417,9 @@ List<String> string_split(const ReadableString& source, DsrChar separator, bool
 // Use string_splitCount on the same source and separator if you need to know the element count in advance.
 // Side-effects:
 //   Calls action for each sub-string divided by separator in source given as the separatedText argument.
-void string_split_callback(std::function<void(ReadableString separatedText)> action, const ReadableString& source, DsrChar separator, bool removeWhiteSpace = false);
+void string_split_callback(Callback<void(ReadableString separatedText)> action, const ReadableString& source, DsrChar separator, bool removeWhiteSpace = false);
 // An alternative overload for having a very long lambda at the end.
-inline void string_split_callback(const ReadableString& source, DsrChar separator, bool removeWhiteSpace, std::function<void(ReadableString separatedText)> action) {
+inline void string_split_callback(const ReadableString& source, DsrChar separator, bool removeWhiteSpace, Callback<void(ReadableString separatedText)> action) {
 	string_split_callback(action, source, separator, removeWhiteSpace);
 }
 // Split source using separator, only to return the number of splits.
@@ -617,7 +617,7 @@ void string_sendMessage_default(const ReadableString &message, MessageType type)
 // Terminating the program as soon as possible is ideal, but one might want to save a backup or show what went wrong in a graphical interface before terminating.
 // Do not throw and catch errors as if they were warnings, because throwing and catching creates a partial transaction, potentially violating type invariants.
 //   Better to use warnings and let the sender of the warning figure out how to abort the action safely.
-void string_assignMessageHandler(std::function<void(const ReadableString &message, MessageType type)> action);
+void string_assignMessageHandler(Callback<void(const ReadableString &message, MessageType type)> action);
 
 // Undo string_assignMessageHandler, so that any messages will be handled the default way again.
 void string_unassignMessageHandler();

+ 38 - 0
Source/DFPSR/base/Callback.h

@@ -0,0 +1,38 @@
+// zlib open source license
+//
+// Copyright (c) 2026 David Forsgren Piuva
+// 
+// This software is provided 'as-is', without any express or implied
+// warranty. In no event will the authors be held liable for any damages
+// arising from the use of this software.
+// 
+// Permission is granted to anyone to use this software for any purpose,
+// including commercial applications, and to alter it and redistribute it
+// freely, subject to the following restrictions:
+// 
+//    1. The origin of this software must not be misrepresented; you must not
+//    claim that you wrote the original software. If you use this software
+//    in a product, an acknowledgment in the product documentation would be
+//    appreciated but is not required.
+// 
+//    2. Altered source versions must be plainly marked as such, and must not be
+//    misrepresented as being the original software.
+// 
+//    3. This notice may not be removed or altered from any source
+//    distribution.
+
+#ifndef DFPSR_CALLBACK
+#define DFPSR_CALLBACK
+
+// TODO: Remove the dependency on std::function, so that the library is less affected by deprecated features in the standard library.
+#include <functional>
+
+namespace dsr {
+
+	// TODO: Implement a function type that allocates memory using heap.h, so that memory is always quickly reused.
+	template<class T>
+	using Callback = std::function<T>;
+
+}
+
+#endif

+ 2 - 2
Source/DFPSR/base/heap.cpp

@@ -790,7 +790,7 @@ namespace dsr {
 		unlockMemory();
 	}
 
-	static void forAllHeapAllocations(HeapMemory &heap, std::function<void(AllocationHeader * header, void * allocation)> callback) {
+	static void forAllHeapAllocations(HeapMemory &heap, Callback<void(AllocationHeader * header, void * allocation)> callback) {
 		uint8_t * current = heap.allocationPointer;
 		while (current < heap.bottom) {
 			HeapHeader *header = (HeapHeader*)current;
@@ -802,7 +802,7 @@ namespace dsr {
 		}
 	}
 
-	void heap_forAllHeapAllocations(std::function<void(AllocationHeader * header, void * allocation)> callback) {
+	void heap_forAllHeapAllocations(Callback<void(AllocationHeader * header, void * allocation)> callback) {
 		HeapMemory *currentHeap = defaultHeap.lastHeap;
 		while (currentHeap != nullptr) {
 			forAllHeapAllocations(*currentHeap, callback);

+ 2 - 2
Source/DFPSR/base/heap.h

@@ -53,7 +53,7 @@
 #define DFPSR_HEAP
 
 #include "SafePointer.h"
-#include <functional>
+#include "Callback.h"
 
 namespace dsr {
 	#ifdef SAFE_POINTER_CHECKS
@@ -147,7 +147,7 @@ namespace dsr {
 
 	// Call back for each used heap allocation.
 	//   Recycled allocations are not included.
-	void heap_forAllHeapAllocations(std::function<void(AllocationHeader * header, void * allocation)> callback);
+	void heap_forAllHeapAllocations(Callback<void(AllocationHeader * header, void * allocation)> callback);
 
 	// Prints the allocation to the terminal.
 	void heap_debugPrintAllocation(void const * const allocation, uintptr_t maxLength = 128u);

+ 12 - 10
Source/DFPSR/base/threading.cpp

@@ -49,7 +49,7 @@ int32_t getThreadCount() {
 	#endif
 }
 
-void threadedWorkByIndex(std::function<void(void *context, int32_t jobIndex)> job, void *context, int32_t jobCount, int32_t maxThreadCount) {
+void threadedWorkByIndex(Callback<void(void *context, int32_t jobIndex)> job, void *context, int32_t jobCount, int32_t maxThreadCount) {
 	#ifdef DISABLE_MULTI_THREADING
 		// Reference implementation
 		for (int32_t i = 0; i < jobCount; i++) {
@@ -79,6 +79,7 @@ void threadedWorkByIndex(std::function<void(void *context, int32_t jobIndex)> jo
 			} else {
 				// A shared counter protected by getTaskLock.
 				int32_t nextJobIndex = 0;
+				// std::async can not replace std::function with a custom implementation, so Callback is not used here.
 				DestructibleVirtualStackAllocation<std::function<void()>> workers(workerCount);
 				DestructibleVirtualStackAllocation<std::future<void>> helpers(helperCount);
 				for (int32_t w = 0; w < workerCount; w++) {
@@ -113,7 +114,7 @@ void threadedWorkByIndex(std::function<void(void *context, int32_t jobIndex)> jo
 	#endif
 }
 
-void threadedWorkFromArray(std::function<void()>* jobs, int32_t jobCount, int32_t maxThreadCount) {
+void threadedWorkFromArray(Callback<void()>* jobs, int32_t jobCount, int32_t maxThreadCount) {
 	#ifdef DISABLE_MULTI_THREADING
 		// Reference implementation
 		for (int32_t i = 0; i < jobCount; i++) {
@@ -143,6 +144,7 @@ void threadedWorkFromArray(std::function<void()>* jobs, int32_t jobCount, int32_
 			} else {
 				// A shared counter protected by getTaskLock.
 				int32_t nextJobIndex = 0;
+				// std::async can not replace std::function with a custom implementation, so Callback is not used here.
 				DestructibleVirtualStackAllocation<std::function<void()>> workers(workerCount);
 				DestructibleVirtualStackAllocation<std::future<void>> helpers(helperCount);
 				for (int32_t w = 0; w < workerCount; w++) {
@@ -177,18 +179,18 @@ void threadedWorkFromArray(std::function<void()>* jobs, int32_t jobCount, int32_
 	#endif
 }
 
-void threadedWorkFromArray(SafePointer<std::function<void()>> jobs, int32_t jobCount, int32_t maxThreadCount) {
+void threadedWorkFromArray(SafePointer<Callback<void()>> jobs, int32_t jobCount, int32_t maxThreadCount) {
 	threadedWorkFromArray(jobs.getUnsafe(), jobCount, maxThreadCount);
 }
 
-void threadedWorkFromList(List<std::function<void()>> jobs, int32_t maxThreadCount) {
+void threadedWorkFromList(List<Callback<void()>> jobs, int32_t maxThreadCount) {
 	if (jobs.length() > 0) {
 		threadedWorkFromArray(&jobs[0], jobs.length(), maxThreadCount);
 	}
 	jobs.clear();
 }
 
-void threadedSplit(int32_t startIndex, int32_t stopIndex, std::function<void(int32_t startIndex, int32_t stopIndex)> task, int32_t minimumJobSize, int32_t jobsPerThread) {
+void threadedSplit(int32_t startIndex, int32_t stopIndex, Callback<void(int32_t startIndex, int32_t stopIndex)> task, int32_t minimumJobSize, int32_t jobsPerThread) {
 	#ifndef DISABLE_MULTI_THREADING
 		int32_t totalCount = stopIndex - startIndex;
 		int32_t maxJobs = totalCount / minimumJobSize;
@@ -203,7 +205,7 @@ void threadedSplit(int32_t startIndex, int32_t stopIndex, std::function<void(int
 		task(startIndex, stopIndex);
 	} else {
 		// Use multiple threads
-		DestructibleVirtualStackAllocation<std::function<void()>> jobs(jobCount);
+		DestructibleVirtualStackAllocation<Callback<void()>> jobs(jobCount);
 		int32_t givenRow = startIndex;
 		for (int32_t s = 0; s < jobCount; s++) {
 			int32_t remainingJobs = jobCount - s;
@@ -220,11 +222,11 @@ void threadedSplit(int32_t startIndex, int32_t stopIndex, std::function<void(int
 	}
 }
 
-void threadedSplit_disabled(int32_t startIndex, int32_t stopIndex, std::function<void(int32_t startIndex, int32_t stopIndex)> task) {
+void threadedSplit_disabled(int32_t startIndex, int32_t stopIndex, Callback<void(int32_t startIndex, int32_t stopIndex)> task) {
 	task(startIndex, stopIndex);
 }
 
-void threadedSplit(const IRect& bound, std::function<void(const IRect& bound)> task, int32_t minimumRowsPerJob, int32_t jobsPerThread) {
+void threadedSplit(const IRect& bound, Callback<void(const IRect& bound)> task, int32_t minimumRowsPerJob, int32_t jobsPerThread) {
 	#ifndef DISABLE_MULTI_THREADING
 		int32_t maxJobs = bound.height() / minimumRowsPerJob;
 		int32_t jobCount = getThreadCount() * jobsPerThread;
@@ -238,7 +240,7 @@ void threadedSplit(const IRect& bound, std::function<void(const IRect& bound)> t
 		task(bound);
 	} else {
 		// Use multiple threads
-		DestructibleVirtualStackAllocation<std::function<void()>> jobs(jobCount);
+		DestructibleVirtualStackAllocation<Callback<void()>> jobs(jobCount);
 		int32_t givenRow = bound.top();
 		for (int32_t s = 0; s < jobCount; s++) {
 			int32_t remainingJobs = jobCount - s;
@@ -255,7 +257,7 @@ void threadedSplit(const IRect& bound, std::function<void(const IRect& bound)> t
 	}
 }
 
-void threadedSplit_disabled(const IRect& bound, std::function<void(const IRect& bound)> task) {
+void threadedSplit_disabled(const IRect& bound, Callback<void(const IRect& bound)> task) {
 	task(bound);
 }
 

+ 9 - 9
Source/DFPSR/base/threading.h

@@ -26,7 +26,7 @@
 
 #include "../../DFPSR/collection/List.h"
 #include "../../DFPSR/math/IRect.h"
-#include <functional>
+#include "Callback.h"
 
 namespace dsr {
 
@@ -35,19 +35,19 @@ int32_t getThreadCount();
 
 // Calls the same job function with indices 0 to jobIndex - 1.
 //   This removes the need for capturing the same data over and over again when each task is identical with a different index.
-void threadedWorkByIndex(std::function<void(void *context, int32_t jobIndex)> job, void *context, int32_t jobCount, int32_t maxThreadCount = 0);
+void threadedWorkByIndex(Callback<void(void *context, int32_t jobIndex)> job, void *context, int32_t jobCount, int32_t maxThreadCount = 0);
 
 // Executes every function in the array of jobs from jobs[0] to jobs[jobCount - 1].
 //   The maxThreadCount argument is the maximum number of threads to use when enough threads are available.
 //     Letting maxThreadCount be 0 removes the limit and uses as many threads as possible, limited only by getThreadCount() - 1 and jobCount.
 //     Letting maxThreadCount be 1 forces single-threaded execution on the calling thread.
 //   Useful when each job to execute is different.
-void threadedWorkFromArray(SafePointer<std::function<void()>> jobs, int32_t jobCount, int32_t maxThreadCount = 0);
-void threadedWorkFromArray(std::function<void()>* jobs, int32_t jobCount, int32_t maxThreadCount = 0);
+void threadedWorkFromArray(SafePointer<Callback<void()>> jobs, int32_t jobCount, int32_t maxThreadCount = 0);
+void threadedWorkFromArray(Callback<void()>* jobs, int32_t jobCount, int32_t maxThreadCount = 0);
 
 // Executes every function in the list of jobs.
 //   Also clears the list when done.
-void threadedWorkFromList(List<std::function<void()>> jobs, int32_t maxThreadCount = 0);
+void threadedWorkFromList(List<Callback<void()>> jobs, int32_t maxThreadCount = 0);
 
 // Calling the given function with sub-sets of the interval using multiple threads in parallel.
 //   Useful when you have lots of tiny jobs that can be grouped together into larger jobs.
@@ -63,15 +63,15 @@ void threadedWorkFromList(List<std::function<void()>> jobs, int32_t maxThreadCou
 //     * Do not use for manipulation of pointers, stack memory from the calling thread or anything where corrupted output may lead to a crash.
 //       Drawing pixel values is okay, because a race condition would only be some noisy pixels that can be spotted and fixed.
 //       Race conditions cannot be tested nor proven away, so assume that they will happen and do your best to avoid them.
-void threadedSplit(int32_t startIndex, int32_t stopIndex, std::function<void(int32_t startIndex, int32_t stopIndex)> task, int32_t minimumJobSize = 128, int32_t jobsPerThread = 2);
+void threadedSplit(int32_t startIndex, int32_t stopIndex, Callback<void(int32_t startIndex, int32_t stopIndex)> task, int32_t minimumJobSize = 128, int32_t jobsPerThread = 2);
 // Use as a place-holder if you want to disable multi-threading but easily turn it on and off for comparing performance
-void threadedSplit_disabled(int32_t startIndex, int32_t stopIndex, std::function<void(int32_t startIndex, int32_t stopIndex)> task);
+void threadedSplit_disabled(int32_t startIndex, int32_t stopIndex, Callback<void(int32_t startIndex, int32_t stopIndex)> task);
 // A more convenient version for images looping over a rectangular bound of pixels.
 //   The same left and right sides are given to each sub-bound to make memory alignment easy.
 //   The top and bottoms are subdivided so that memory access is simple for cache prediction.
-void threadedSplit(const IRect& bound, std::function<void(const IRect& bound)> task, int32_t minimumRowsPerJob = 128, int32_t jobsPerThread = 2);
+void threadedSplit(const IRect& bound, Callback<void(const IRect& bound)> task, int32_t minimumRowsPerJob = 128, int32_t jobsPerThread = 2);
 // Use as a place-holder if you want to disable multi-threading but easily turn it on and off for comparing performance
-void threadedSplit_disabled(const IRect& bound, std::function<void(const IRect& bound)> task);
+void threadedSplit_disabled(const IRect& bound, Callback<void(const IRect& bound)> task);
 
 }
 

+ 6 - 6
Source/DFPSR/implementation/gui/InputEvent.h

@@ -25,7 +25,7 @@
 #define DFPSR_GUI_INPUT_EVENT
 
 #include "../../math/IVector.h"
-#include <functional>
+#include "../../base/Callback.h"
 
 namespace dsr {
 
@@ -121,11 +121,11 @@ public:
 	decltype(LAMBDA)& NAME() { return callback_##NAME; }
 
 // The callback types.
-using EmptyCallback = std::function<void()>;
-using IndexCallback = std::function<void(int32_t index)>;
-using SizeCallback = std::function<void(int32_t width, int32_t height)>;
-using KeyboardCallback = std::function<void(const KeyboardEvent& event)>;
-using MouseCallback = std::function<void(const MouseEvent& event)>;
+using EmptyCallback = Callback<void()>;
+using IndexCallback = Callback<void(int32_t index)>;
+using SizeCallback = Callback<void(int32_t width, int32_t height)>;
+using KeyboardCallback = Callback<void(const KeyboardEvent& event)>;
+using MouseCallback = Callback<void(const MouseEvent& event)>;
 
 // The default functions to call until a callback has been selected.
 static EmptyCallback emptyCallback = []() {};

+ 1 - 2
Source/DFPSR/implementation/gui/components/TextBox.cpp

@@ -22,7 +22,6 @@
 //    distribution.
 
 #include "TextBox.h"
-#include <functional>
 
 using namespace dsr;
 
@@ -75,7 +74,7 @@ static void tabJump(int64_t &x, int64_t tabWidth) {
 static int64_t monospacesPerTab = 4;
 
 // Pre-condition: text does not contain any linebreak.
-static void iterateCharactersInLine(const ReadableString& text, const RasterFont &font, std::function<void(int64_t index, DsrChar code, int64_t left, int64_t right)> characterAction) {
+static void iterateCharactersInLine(const ReadableString& text, const RasterFont &font, Callback<void(int64_t index, DsrChar code, int64_t left, int64_t right)> characterAction) {
 	int64_t right = 0;
 	int64_t monospaceWidth = font_getMonospaceWidth(font);
 	int64_t tabWidth = monospaceWidth * monospacesPerTab;