branch: externals/websocket commit ff566c4ad7539e5f220772bca1977d859cee72ef Author: Andrew Hyatt <ahy...@gmail.com> Commit: Andrew Hyatt <ahy...@gmail.com>
Fix some performance bottlenecks. Notably, `websocket-mask' was somewhat slow due to inefficient implementation, and use of `websocket-get-bytes' wasn't nearly as fast as aref for 1-byte sequences. --- websocket.el | 25 ++++++++++++++----------- 1 file changed, 14 insertions(+), 11 deletions(-) diff --git a/websocket.el b/websocket.el index ffd22f4e73..53ec1dd25c 100644 --- a/websocket.el +++ b/websocket.el @@ -217,7 +217,7 @@ approximately 537M long." "websocket-get-bytes: Unknown N: %S" n))))) s) (args-out-of-range (signal 'websocket-unparseable-frame - (list (format "Frame unexpectedly shortly: %s" s))))) + (list (format "Frame unexpectedly short: %s" s))))) :val))) (defun websocket-to-bytes (val nbytes) @@ -252,7 +252,7 @@ approximately 537M long." (defun websocket-get-opcode (s) "Retrieve the opcode from first byte of string S." (websocket-ensure-length s 1) - (let ((opcode (logand #xf (websocket-get-bytes s 1)))) + (let ((opcode (logand #xf (aref s 0)))) (cond ((= opcode 0) 'continuation) ((= opcode 1) 'text) ((= opcode 2) 'binary) @@ -265,7 +265,7 @@ approximately 537M long." We start at position 0, and return a cons of the payload length and how many bytes were consumed from the string." (websocket-ensure-length s 1) - (let* ((initial-val (logand 127 (websocket-get-bytes s 1)))) + (let* ((initial-val (logand 127 (aref s 0)))) (cond ((= initial-val 127) (websocket-ensure-length s 9) (cons (websocket-get-bytes (substring s 1) 8) 9)) @@ -289,12 +289,15 @@ This is used to both mask and unmask data." ;; string of the same length (for example, 6 multibyte chars for 你好 instead ;; of the correct 6 unibyte chars, which would convert into 2 multibyte ;; chars). - (apply - #'unibyte-string - (cl-loop for b across data - for i from 0 to (length data) - collect - (logxor (websocket-get-bytes (substring key (mod i 4)) 1) b)))) + (funcall + #'encode-coding-string + (let ((result (make-string (length data) ?x))) + (cl-loop + for i from 0 below (length data) + do + (setf (seq-elt result i) (logxor (aref key (mod i 4)) (seq-elt data i))) + finally (return result))) + 'utf-8)) (defun websocket-ensure-length (s n) "Ensure the string S has at most N bytes. @@ -351,13 +354,13 @@ the frame finishes. If the frame is not completed, return NIL." (catch 'websocket-incomplete-frame (websocket-ensure-length s 1) (let* ((opcode (websocket-get-opcode s)) - (fin (logand 128 (websocket-get-bytes s 1))) + (fin (logand 128 (aref s 0))) (payloadp (memq opcode '(continuation text binary ping pong))) (payload-len (when payloadp (websocket-get-payload-len (substring s 1)))) (maskp (and payloadp - (= 128 (logand 128 (websocket-get-bytes (substring s 1) 1))))) + (= 128 (logand 128 (aref s 1))))) (payload-start (when payloadp (+ (if maskp 5 1) (cdr payload-len)))) (payload-end (when payloadp (+ payload-start (car payload-len)))) (unmasked-payload (when payloadp