From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.org!.POSTED!not-for-mail From: Eli Zaretskii Newsgroups: gmane.emacs.devel Subject: Re: Minor optimization in json.c Date: Sun, 23 Sep 2018 16:06:32 +0300 Message-ID: <83worcbbxj.fsf@gnu.org> References: <83efdld3no.fsf@gnu.org> <83zhw8bn1d.fsf@gnu.org> NNTP-Posting-Host: blaine.gmane.org X-Trace: blaine.gmane.org 1537707891 7812 195.159.176.226 (23 Sep 2018 13:04:51 GMT) X-Complaints-To: usenet@blaine.gmane.org NNTP-Posting-Date: Sun, 23 Sep 2018 13:04:51 +0000 (UTC) Cc: emacs-devel@gnu.org To: p.stephani2@gmail.com Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Sun Sep 23 15:04:46 2018 Return-path: Envelope-to: ged-emacs-devel@m.gmane.org Original-Received: from lists.gnu.org ([208.118.235.17]) by blaine.gmane.org with esmtp (Exim 4.84_2) (envelope-from ) id 1g4446-0001wN-48 for ged-emacs-devel@m.gmane.org; Sun, 23 Sep 2018 15:04:46 +0200 Original-Received: from localhost ([::1]:40560 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1g446C-0005M2-Qv for ged-emacs-devel@m.gmane.org; Sun, 23 Sep 2018 09:06:56 -0400 Original-Received: from eggs.gnu.org ([2001:4830:134:3::10]:43036) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1g4466-0005Li-FR for emacs-devel@gnu.org; Sun, 23 Sep 2018 09:06:51 -0400 Original-Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1g4462-00023f-Dd for emacs-devel@gnu.org; Sun, 23 Sep 2018 09:06:50 -0400 Original-Received: from fencepost.gnu.org ([2001:4830:134:3::e]:44347) by eggs.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1g4462-00023X-9w; Sun, 23 Sep 2018 09:06:46 -0400 Original-Received: from [176.228.60.248] (port=4307 helo=home-c4e4a596f7) by fencepost.gnu.org with esmtpsa (TLS1.2:RSA_AES_256_CBC_SHA1:256) (Exim 4.82) (envelope-from ) id 1g4461-0007aW-Lc; Sun, 23 Sep 2018 09:06:46 -0400 In-reply-to: <83zhw8bn1d.fsf@gnu.org> (message from Eli Zaretskii on Sun, 23 Sep 2018 12:06:38 +0300) X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] X-Received-From: 2001:4830:134:3::e X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: "Emacs development discussions." List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: emacs-devel-bounces+ged-emacs-devel=m.gmane.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.org gmane.emacs.devel:230007 Archived-At: > Date: Sun, 23 Sep 2018 12:06:38 +0300 > From: Eli Zaretskii > Cc: emacs-devel@gnu.org > > Actually, I think an even better idea is to do this like > insert-file-contents does: insert the raw string into the gap, then > decode it in one go with decode_coding_gap. I will publish a proposed > patch along these lines soon. Here it is. Comments are welcome. (I needed to make a change in one of the tests, because it not longer matches the code: where previously after-change-functions were invoked after each chunk of JSON was inserted, and thus were protected by internal_catch_all, they are now invoked only once at the end of the insertion, and are no longer protected. Which means the effect of that protection cannot be easily tested from Lisp, AFAICT.) diff --git a/src/json.c b/src/json.c index 17cc096..7bef80f 100644 --- a/src/json.c +++ b/src/json.c @@ -626,15 +626,25 @@ struct json_buffer_and_size ptrdiff_t size; }; +/* This tracks how many bytes were inserted by the callback since + json_dump_callback was called. */ +static ptrdiff_t json_inserted_bytes; + static Lisp_Object json_insert (void *data) { + ptrdiff_t gap_size = GAP_SIZE - json_inserted_bytes; struct json_buffer_and_size *buffer_and_size = data; - /* FIXME: This should be possible without creating an intermediate - string object. */ - Lisp_Object string - = json_make_string (buffer_and_size->buffer, buffer_and_size->size); - insert1 (string); + ptrdiff_t len = buffer_and_size->size; + + /* Enlarge the gap if necessary. */ + if (gap_size < len) + make_gap (len - gap_size); + + /* Copy this chunk of data into the gap. */ + memcpy ((char *) BEG_ADDR + PT_BYTE - BEG_BYTE + json_inserted_bytes, + buffer_and_size->buffer, len); + json_inserted_bytes += len; return Qnil; } @@ -695,10 +705,15 @@ usage: (json-insert OBJECT &rest ARGS) */) json_t *json = lisp_to_json (args[0], &conf); record_unwind_protect_ptr (json_release_object, json); + prepare_to_modify_buffer (PT, PT, NULL); + move_gap_both (PT, PT_BYTE); + json_inserted_bytes = 0; struct json_insert_data data; /* If desired, we might want to add the following flags: JSON_DECODE_ANY, JSON_ALLOW_NUL. */ int status + /* Could have used json_dumpb, but that became available only in + Jansson 2.10, whereas we want to support 2.7 and upward. */ = json_dump_callback (json, json_insert_callback, &data, JSON_COMPACT); if (status == -1) { @@ -708,6 +723,61 @@ usage: (json-insert OBJECT &rest ARGS) */) json_out_of_memory (); } + if (json_inserted_bytes > 0) + { + ptrdiff_t inserted = 0; + + /* Make the inserted text part of the buffer, as unibyte text. */ + GAP_SIZE -= json_inserted_bytes; + GPT += json_inserted_bytes; + GPT_BYTE += json_inserted_bytes; + ZV += json_inserted_bytes; + ZV_BYTE += json_inserted_bytes; + Z += json_inserted_bytes; + Z_BYTE += json_inserted_bytes; + + if (GAP_SIZE > 0) + /* Put an anchor to ensure multi-byte form ends at gap. */ + *GPT_ADDR = 0; + + /* Decode the stuff we've read into the gap. */ + struct coding_system coding; + memset (&coding, 0, sizeof (coding)); + setup_coding_system (Qutf_8_unix, &coding); + coding.dst_multibyte = + !NILP (BVAR (current_buffer, enable_multibyte_characters)); + if (CODING_MAY_REQUIRE_DECODING (&coding)) + { + move_gap_both (PT, PT_BYTE); + GAP_SIZE += json_inserted_bytes; + ZV_BYTE -= json_inserted_bytes; + Z_BYTE -= json_inserted_bytes; + ZV -= json_inserted_bytes; + Z -= json_inserted_bytes; + decode_coding_gap (&coding, json_inserted_bytes, json_inserted_bytes); + inserted = coding.produced_char; + } + else + { + invalidate_buffer_caches (current_buffer, + PT, PT + json_inserted_bytes); + adjust_after_insert (PT, PT_BYTE, + PT + json_inserted_bytes, + PT_BYTE + json_inserted_bytes, + json_inserted_bytes); + inserted = json_inserted_bytes; + } + + /* Call after-change hooks if necessary. */ + if (inserted > 0) + { + signal_after_change (PT, 0, inserted); + update_compositions (PT, PT, CHECK_BORDER); + } + + /* Move point to after the inserted text. */ + SET_PT_BOTH (PT + inserted, PT_BYTE + json_inserted_bytes); + } return unbind_to (count, Qnil); } diff --git a/test/src/json-tests.el b/test/src/json-tests.el index 911bc49..bffee8f 100644 --- a/test/src/json-tests.el +++ b/test/src/json-tests.el @@ -272,10 +272,11 @@ 'json-tests--error (cl-incf calls) (throw 'test-tag 'throw-value)) :local) - (should-error - (catch 'test-tag - (json-insert '((a . "b") (c . 123) (d . [1 2 t :false])))) - :type 'no-catch) + (should + (equal + (catch 'test-tag + (json-insert '((a . "b") (c . 123) (d . [1 2 t :false])))) + 'throw-value)) (should (equal calls 1))))) (ert-deftest json-serialize/bignum ()