From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: David Ponce via "Bug reports for GNU Emacs, the Swiss army knife of text editors" Newsgroups: gmane.emacs.bugs Subject: bug#72689: 31.0.50; Proposal to improve string-pixel-width Date: Tue, 20 Aug 2024 17:12:45 +0200 Message-ID: <35119d55-c582-4f4b-b80d-d94fc6b8886c@orange.fr> References: <54d1d667-55d0-41fc-9eec-38b3881d799b@orange.fr> <86bk1q1m0l.fsf@gnu.org> <8634n219b1.fsf@gnu.org> Reply-To: David Ponce Mime-Version: 1.0 Content-Type: text/plain; charset=UTF-8; format=flowed Content-Transfer-Encoding: 7bit Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="13712"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Mozilla Thunderbird Cc: 72689@debbugs.gnu.org To: Eli Zaretskii Original-X-From: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Tue Aug 20 17:13:43 2024 Return-path: Envelope-to: geb-bug-gnu-emacs@m.gmane-mx.org Original-Received: from lists.gnu.org ([209.51.188.17]) by ciao.gmane.io with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.92) (envelope-from ) id 1sgQYI-0003NP-Ta for geb-bug-gnu-emacs@m.gmane-mx.org; Tue, 20 Aug 2024 17:13:43 +0200 Original-Received: from localhost ([::1] helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1sgQXz-0001EX-LW; Tue, 20 Aug 2024 11:13:23 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1sgQXw-0001E2-Pr for bug-gnu-emacs@gnu.org; Tue, 20 Aug 2024 11:13:20 -0400 Original-Received: from debbugs.gnu.org ([2001:470:142:5::43]) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_128_GCM_SHA256:128) (Exim 4.90_1) (envelope-from ) id 1sgQXv-0000wD-EN for bug-gnu-emacs@gnu.org; Tue, 20 Aug 2024 11:13:19 -0400 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=debbugs.gnu.org; s=debbugs-gnu-org; h=In-Reply-To:From:References:MIME-Version:Date:To:Subject; bh=BqLNqPIrkwrZYSjlUyf216nIG0vtUFrGsnIqYMCL0zY=; b=hJY+/7t9gZKHX+6cxtSVTrJmhpLhyWtgP8SGl2viWMJbagV2WzgwXB1XMfnnDTqb1En/v/9q6WCJ6YmAlwiboX/95F4LSeYMv1dAurqzOgREdLKAuB40iaOz7YLrQx0tSvlVlmDd+Zh3WyzRpdFPlpxqYCSB2Qec0icC7YJ5v1lNHhbAF8Nw13sgXz/AI7O9ymmFVHtI5cC1f8LtQQDTpnfgb1R6KBBDplC0zZAN7OmpxncsSCYjBduP4a9+v4W1t7xMabfSfDWJmTVF8miPYRxgjJY85uxWes2xcr1SyCncvGD1rILhBP/hvUWIAynCmV7Bb/iXyusQBOyu41SPuA==; Original-Received: from Debian-debbugs by debbugs.gnu.org with local (Exim 4.84_2) (envelope-from ) id 1sgQYc-0005Tg-6k for bug-gnu-emacs@gnu.org; Tue, 20 Aug 2024 11:14:02 -0400 X-Loop: help-debbugs@gnu.org Resent-From: David Ponce Original-Sender: "Debbugs-submit" Resent-CC: bug-gnu-emacs@gnu.org Resent-Date: Tue, 20 Aug 2024 15:14:02 +0000 Resent-Message-ID: Resent-Sender: help-debbugs@gnu.org X-GNU-PR-Message: followup 72689 X-GNU-PR-Package: emacs Original-Received: via spool by 72689-submit@debbugs.gnu.org id=B72689.172416681721012 (code B ref 72689); Tue, 20 Aug 2024 15:14:02 +0000 Original-Received: (at 72689) by debbugs.gnu.org; 20 Aug 2024 15:13:37 +0000 Original-Received: from localhost ([127.0.0.1]:33564 helo=debbugs.gnu.org) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sgQYC-0005Sq-6K for submit@debbugs.gnu.org; Tue, 20 Aug 2024 11:13:36 -0400 Original-Received: from smtp-18.smtpout.orange.fr ([80.12.242.18]:51712 helo=smtp.smtpout.orange.fr) by debbugs.gnu.org with esmtp (Exim 4.84_2) (envelope-from ) id 1sgQY8-0005Se-UW for 72689@debbugs.gnu.org; Tue, 20 Aug 2024 11:13:34 -0400 Original-Received: from [192.168.1.21] ([2.7.225.247]) by smtp.orange.fr with ESMTPA id gQXNs1ov4oIRNgQXNsRZnT; Tue, 20 Aug 2024 17:12:48 +0200 DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=orange.fr; s=t20230301; t=1724166768; bh=BqLNqPIrkwrZYSjlUyf216nIG0vtUFrGsnIqYMCL0zY=; h=Message-ID:Date:MIME-Version:Subject:To:From; b=Jg5iWvOQ1ncqg8R40G4XCN+q2ulZA6pr8RtSmT+w9XBJRR7PC/zZNbM8vtM5TNjcp b7E1qhXW4O5DK2xeDhTAoOBEQ00MDn4hVQA5qhXorfYggRDwZ3R7UCLbBZ+ovWpt9V 0BGfG4CwaqNYSPIZWbvwxyoIGZHbndd3yH/Dkou8E8FZY5p2vH713Bgfw+7hsVEQh0 uRIJ+ulaK0PrfGQgbvBuiTc9+1tBzFHwhBR3qCzmRASY29wNvnjLeaLqAdY9uwOX45 32PamESSV/2DeoWiq9JiBViVzm0gthjyKrWo5zocbxhrFGbaP+Koh632nBxyEpUcVm EoUrnKMC6jK/A== X-ME-Helo: [192.168.1.21] X-ME-Auth: ZGFfdmlkQHdhbmFkb28uZnI= X-ME-Date: Tue, 20 Aug 2024 17:12:48 +0200 X-ME-IP: 2.7.225.247 Content-Language: fr, en-US In-Reply-To: <8634n219b1.fsf@gnu.org> X-BeenThere: debbugs-submit@debbugs.gnu.org X-Mailman-Version: 2.1.18 Precedence: list X-BeenThere: bug-gnu-emacs@gnu.org List-Id: "Bug reports for GNU Emacs, the Swiss army knife of text editors" List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Original-Sender: bug-gnu-emacs-bounces+geb-bug-gnu-emacs=m.gmane-mx.org@gnu.org Xref: news.gmane.io gmane.emacs.bugs:290453 Archived-At: On 18/08/2024 11:15 AM, Eli Zaretskii wrote: [...] >>> Thanks. The idea SGTM, but I think the implementation needs to cater >>> for the case where more than one execution thread performs this job >>> "in parallel" (however improbable this could sound), so we need to be >>> able to detect when this buffer is "busy". The simplest way is to use >>> some boolean buffer-local variable, which will be set non-nil when the >>> function starts using the buffer and reset to nil when the function is >>> done with its job. I've been thinking more about the parallelism issue when a function reuses a temporary buffer for its activity, and I wonder if we could use a simple API like the one below to safely get an exclusive working buffer without having to create a new one on each call? ;; --------------------------------------------------------------- (defvar work-buffer--list nil) (defvar work-buffer--lock (make-mutex)) (defsubst work-buffer--get () "Get a work buffer." (let ((buffer (with-mutex work-buffer--lock (pop work-buffer--list)))) (if (buffer-live-p buffer) buffer (generate-new-buffer " *work*" t)))) (defsubst work-buffer--release (buffer) "Release work BUFFER." (if (buffer-live-p buffer) (with-current-buffer buffer ;; Flush BUFFER before making it available again, i.e. clear ;; its contents, remove all overlays and buffer-local ;; variables. Is it enough to safely reuse the buffer? (erase-buffer) (delete-all-overlays) (let (change-major-mode-hook) (kill-all-local-variables t)) ;; Make the buffer available again. (with-mutex work-buffer--lock (push buffer work-buffer--list))))) ;;;###autoload (defmacro with-work-buffer (&rest body) "Create a work buffer, and evaluate BODY there like `progn'. Like `with-temp-buffer', but reuse an already created temporary buffer when possible, instead of creating a new one on each call." (declare (indent 0) (debug t)) (let ((work-buffer (make-symbol "work-buffer"))) `(let ((,work-buffer (work-buffer--get))) (with-current-buffer ,work-buffer (unwind-protect (progn ,@body) (work-buffer--release ,work-buffer)))))) ;; --------------------------------------------------------------- Here is how string-pixel-width could be implemented to use the above API: (defun string-pixel-W (string &optional buffer) "Return the width of STRING in pixels. If BUFFER is non-nil, use the face remappings from that buffer when determining the width." (declare (important-return-value t)) (if (zerop (length string)) 0 ;; Keeping a work buffer around is more efficient than creating a ;; new temporary buffer. (with-work-buffer ;; If `display-line-numbers' is enabled in internal ;; buffers (e.g. globally), it breaks width calculation ;; (bug#59311). Disable `line-prefix' and `wrap-prefix', ;; for the same reason. (setq display-line-numbers nil line-prefix nil wrap-prefix nil) (if buffer (setq-local face-remapping-alist (with-current-buffer buffer face-remapping-alist)) (kill-local-variable 'face-remapping-alist)) (erase-buffer) (insert string) ;; Prefer `remove-text-properties' to `propertize' to avoid ;; creating a new string on each call. (remove-text-properties (point-min) (point-max) '(line-prefix nil wrap-prefix nil)) (car (buffer-text-pixel-size nil nil t))))) ;; Quick benchmarck (let* ((text1 (make-string 1000 ?x)) (text2 (propertize text1 'line-prefix "XXXX ")) (runs 1000)) (list (progn (garbage-collect) (benchmark-run runs (string-pixel-width text2))) (progn (garbage-collect) (benchmark-run runs (string-pixel-W text2))) )) Compared to my previous proposal the quick benchmark above shows similar results for both performance and memory usage, but the new implementation is simpler, and the API might be useful in other similar cases. WDYT?