git » sdk » commit 55b3031

findFast

author Stephen Paul Weber
2025-06-24 18:07:34 UTC
committer Stephen Paul Weber
2025-06-24 18:07:34 UTC
parent 761604c70c958911b0c6427ca1e58d874cc7c34f

findFast

Profiling showed some of these calls were hot and the reflection made
them slower, so switch to specialized version.

snikket/Client.hx +1 -1
snikket/Message.hx +2 -1
snikket/Util.hx +12 -0
snikket/persistence/Sqlite.hx +2 -2

diff --git a/snikket/Client.hx b/snikket/Client.hx
index 9ce8e0b..18675b4 100644
--- a/snikket/Client.hx
+++ b/snikket/Client.hx
@@ -921,7 +921,7 @@ class Client extends EventEmitter {
 		@returns the chat if known, or NULL
 	**/
 	public function getChat(chatId:String):Null<Chat> {
-		return chats.find((chat) -> chat.chatId == chatId);
+		return Util.findFast(chats, (chat) -> chat.chatId == chatId);
 	}
 
 	@:allow(snikket)
diff --git a/snikket/Message.hx b/snikket/Message.hx
index 14c4731..39916ca 100644
--- a/snikket/Message.hx
+++ b/snikket/Message.hx
@@ -154,7 +154,8 @@ class Message {
 		msg.replyTo.sort((x, y) -> Reflect.compare(x.asString(), y.asString()));
 
 		final msgFrom = msg.from;
-		if (msg.direction == MessageReceived && msgFrom != null && msg.replyTo.find((r) -> r.asBare().equals(msgFrom.asBare())) == null) {
+		// Not sure why the compiler things we need to use Null<JID> with findFast
+		if (msg.direction == MessageReceived && msgFrom != null && Util.findFast(msg.replyTo, @:nullSafety(Off) (r: Null<JID>) -> r.asBare().equals(msgFrom.asBare())) == null) {
 			trace("Don't know what chat message without from in replyTo belongs in", stanza);
 			return new Message(msg.chatId(), msg.senderId, msg.threadId, UnknownMessageStanza(stanza));
 		}
diff --git a/snikket/Util.hx b/snikket/Util.hx
index 9f293c7..6c9f7eb 100644
--- a/snikket/Util.hx
+++ b/snikket/Util.hx
@@ -28,6 +28,18 @@ inline function existsFast<A>(it:Array<A>, f:(item:A) -> Bool) {
 	return result;
 }
 
+@:nullSafety(Strict)
+inline function findFast<T>(it:Array<T>, f:(item:T) -> Bool):Null<T> {
+	var result = null;
+	for (v in it) {
+		if (f(v)) {
+			result = v;
+			break;
+		}
+	}
+	return result;
+}
+
 // Std.downcast doesn't play well with null safety
 function downcast<T, S>(value: T, c: Class<S>): Null<S> {
 	return cast Std.downcast(cast value, cast c);
diff --git a/snikket/persistence/Sqlite.hx b/snikket/persistence/Sqlite.hx
index 28a6f1a..c483e3a 100644
--- a/snikket/persistence/Sqlite.hx
+++ b/snikket/persistence/Sqlite.hx
@@ -692,7 +692,7 @@ class Sqlite implements Persistence implements KeyValueStore {
 	private function hydrateReactions(accountId: String, messages: Array<ChatMessage>) {
 		return fetchReactions(accountId, messages.map(m -> ({ chatId: m.chatId(), serverId: m.serverId, serverIdBy: m.serverIdBy, localId: m.localId }))).then(result -> {
 			for (id => reactions in result) {
-				final m = messages.find(m ->
+				final m = Util.findFast(messages, m ->
 					((m.serverId == null ? m.localId : m.serverId + "\n" + m.serverIdBy) + "\n" + m.chatId()) == id ||
 					((m.localId == null ? m.serverId + "\n" + m.serverIdBy : m.localId) + "\n" + m.chatId()) == id
 				);
@@ -780,7 +780,7 @@ class Sqlite implements Persistence implements KeyValueStore {
 				final parents = { iterator: () -> iter }.array();
 				for (message in messages) {
 					if (message.replyToMessage != null) {
-						final found: Dynamic = parents.find(p -> p.chat_id == message.chatId() && (message.replyToMessage.serverId == null || p.mam_id == message.replyToMessage.serverId) && (message.replyToMessage.localId == null || p.stanza_id == message.replyToMessage.localId));
+						final found: Dynamic = Util.findFast(parents, p -> p.chat_id == message.chatId() && (message.replyToMessage.serverId == null || p.mam_id == message.replyToMessage.serverId) && (message.replyToMessage.localId == null || p.stanza_id == message.replyToMessage.localId));
 						if (found != null) message.set_replyToMessage(hydrateMessages(accountId, [found].iterator())[0]);
 					}
 				}