From mboxrd@z Thu Jan 1 00:00:00 1970 Path: news.gmane.io!.POSTED.blaine.gmane.org!not-for-mail From: Arthur Miller Newsgroups: gmane.emacs.devel Subject: Re: empty-directory predicate, native implementation Date: Wed, 14 Oct 2020 03:52:42 +0200 Message-ID: References: <83y2ka18t7.fsf@gnu.org> <87y2kaj799.fsf@gmx.de> <83blh60wgr.fsf@gnu.org> Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-=-=" Injection-Info: ciao.gmane.io; posting-host="blaine.gmane.org:116.202.254.214"; logging-data="24348"; mail-complaints-to="usenet@ciao.gmane.io" User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/28.0.50 (gnu/linux) Cc: Michael Albinus , emacs-devel@gnu.org To: Eli Zaretskii Original-X-From: emacs-devel-bounces+ged-emacs-devel=m.gmane-mx.org@gnu.org Wed Oct 14 03:53:43 2020 Return-path: Envelope-to: ged-emacs-devel@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 1kSVz5-0006FR-Gk for ged-emacs-devel@m.gmane-mx.org; Wed, 14 Oct 2020 03:53:43 +0200 Original-Received: from localhost ([::1]:49972 helo=lists1p.gnu.org) by lists.gnu.org with esmtp (Exim 4.90_1) (envelope-from ) id 1kSVz4-0000vK-IH for ged-emacs-devel@m.gmane-mx.org; Tue, 13 Oct 2020 21:53:42 -0400 Original-Received: from eggs.gnu.org ([2001:470:142:3::10]:36712) by lists.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kSVyF-0000SX-FF for emacs-devel@gnu.org; Tue, 13 Oct 2020 21:52:52 -0400 Original-Received: from mail-oln040092075094.outbound.protection.outlook.com ([40.92.75.94]:54766 helo=EUR04-VI1-obe.outbound.protection.outlook.com) by eggs.gnu.org with esmtps (TLS1.2:ECDHE_RSA_AES_256_GCM_SHA384:256) (Exim 4.90_1) (envelope-from ) id 1kSVyB-0004o1-AW; Tue, 13 Oct 2020 21:52:51 -0400 ARC-Seal: i=1; a=rsa-sha256; s=arcselector9901; d=microsoft.com; cv=none; b=hrPy7zPOzxhu0tO5KF1obTlk2EdRu+pSQFURmjEyhyLQLAHTwLIzuIsPJnsq0fsOY//kYlRmmUrEIrB7rXJNLHMTKIlW2uKTB7G5vj3lQ5xKXTTBj3pyS/esmYRSFqJpVBAh4y1ProGBD+XElVeGiwtbL+wcJutYu9qdGF6jlhVFZJRsWltoxJ8u6bgUhHfjmhb7r6hBeV+WlasWd18bU03v/kmQPCUpY+zHk7pYc8vtCTaNggdm1CIWA/3SnpzE1zakQ2BrTn+6bjQzWOtLTaB84qWDIOZ5YhrFzqKdI+3A6z7vI8qNHDjBGmV6ad/QZBcaf1bAMv9GHAer72PVvA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=microsoft.com; s=arcselector9901; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=P7Jay0rGO/JthugHExQ4HQDm0WEOa2XxY2BYtLFIR1Q=; b=EcntgSWl9N58GWpYAInkkuKWdLGcR93MCuOhRE6khNgSnVP3f8g+7v/o5NAQsEpnTs8c31i0TTQMelxAn1ehUwNoEtJYfUJm6CuZagkaEoNAKT6KKU0dCDlkf7X/cDKeL+iUMiOqhoWV6uLqlj/pDbtkE0bkJQcYB/UuZQHnCYODSk67XwbRFvG1bnlonesHQPq3eloI0HGtDtp1IdYwMdDj6putBHgeQByIQ4NOizBw1d5rWd4zCsP/Ekyw/1f+30Ytp6XclEiDr1U2yOOiXZkhuxeyEK19aGcKNBhSjXHafDWJ97mVJ8EHOhdM3QLbMpktkwIJE+FSXGVuux5RmQ== ARC-Authentication-Results: i=1; mx.microsoft.com 1; spf=none; dmarc=none; dkim=none; arc=none DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=live.com; s=selector1; h=From:Date:Subject:Message-ID:Content-Type:MIME-Version:X-MS-Exchange-SenderADCheck; bh=P7Jay0rGO/JthugHExQ4HQDm0WEOa2XxY2BYtLFIR1Q=; b=OP7NTOekvoYLKvm/ziccccZLlXyWsXQzVtkjoVVn+6T1R05I0nYSTmuKPTelUBNLAc3LxhAWAd1KsyCxoy5LDx8C/cSSWdmDTfB9NFStcVxbkey1bMYOuLnmZHnCxCJ4MNisT+JCdJoW3I8U9KNGpSnnvjvW01NTU9dSozbfGA0rBV5jLZFHFI/zdlHeiku11MnU6niPpyjrJNd+0nMrpTsR2/f7LTo1FWI2yrcsJurNjZGd693KQyWiLLchwCWPnl/Us+eQGGG0F0pzlgEbQBexrdmF4pcl3ZKYF1gIEjXYtn/Dw+w8i4jK9YM9n/I+uQOQRDqb2T41E5i1EPZoxQ== Original-Received: from DB3EUR04FT012.eop-eur04.prod.protection.outlook.com (2a01:111:e400:7e0c::4c) by DB3EUR04HT177.eop-eur04.prod.protection.outlook.com (2a01:111:e400:7e0c::168) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3455.23; Wed, 14 Oct 2020 01:52:44 +0000 Original-Received: from VI1PR06MB4526.eurprd06.prod.outlook.com (2a01:111:e400:7e0c::4f) by DB3EUR04FT012.mail.protection.outlook.com (2a01:111:e400:7e0c::465) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3455.23 via Frontend Transport; Wed, 14 Oct 2020 01:52:44 +0000 X-IncomingTopHeaderMarker: OriginalChecksum:917F21124E821EFBADE5CAE88F4F6F14CE6D88C66803E3057248B56A003DEBAD; UpperCasedChecksum:D5043B43E467FC7F6BCE2872756807EB6BB37F9BDFDD3A2FEC8F2117228B2773; SizeAsReceived:7572; Count:46 Original-Received: from VI1PR06MB4526.eurprd06.prod.outlook.com ([fe80::b547:51cd:16c5:4487]) by VI1PR06MB4526.eurprd06.prod.outlook.com ([fe80::b547:51cd:16c5:4487%7]) with mapi id 15.20.3455.031; Wed, 14 Oct 2020 01:52:44 +0000 In-Reply-To: <83blh60wgr.fsf@gnu.org> (Eli Zaretskii's message of "Tue, 13 Oct 2020 22:14:44 +0300") X-TMN: [bp+8a2ZxH3+QbgFilo24NtfMJRtHm3oQ] X-ClientProxiedBy: BE0P281CA0035.DEUP281.PROD.OUTLOOK.COM (2603:10a6:b10:14::22) To VI1PR06MB4526.eurprd06.prod.outlook.com (2603:10a6:803:ac::17) X-Microsoft-Original-Message-ID: <87o8l5bml1.fsf@live.com> X-MS-Exchange-MessageSentRepresentingType: 1 Original-Received: from pascal.homepc (90.230.29.56) by BE0P281CA0035.DEUP281.PROD.OUTLOOK.COM (2603:10a6:b10:14::22) with Microsoft SMTP Server (version=TLS1_2, cipher=TLS_ECDHE_RSA_WITH_AES_256_GCM_SHA384) id 15.20.3477.11 via Frontend Transport; Wed, 14 Oct 2020 01:52:43 +0000 X-MS-PublicTrafficType: Email X-IncomingHeaderCount: 46 X-EOPAttributedMessage: 0 X-MS-Office365-Filtering-Correlation-Id: a7e457f0-8ff5-4a98-fc8c-08d86fe3d74d X-MS-TrafficTypeDiagnostic: DB3EUR04HT177: X-Microsoft-Antispam: BCL:0; X-Microsoft-Antispam-Message-Info: bN7MosaaUUht1IXJhK8FhtflUGMPNAVyExNdRB2pe556RYhWczEHfvWHKdJY3U4OKVqYYqvsK8EDAcm/cbXtx12oc6pAL1RlC9StFqeHqaS2ngc8MG9X1jFXsI5LcMDw/u0IfgWAgmvikzq5mTf0KqTpMjebf4w+eJhjz+aDeif8ApCvxCbwcS2ufHCI4wkGsPskFo2Q5TcJj1FUvG+7DA== X-MS-Exchange-AntiSpam-MessageData: cy4edQPwc+hHkVIQDAlJtrFRPR5pWyAaqtsTEyXn9eRg75dxx/qJ2UyaAjy46rIwxkksOM+7Y0+2lOeur1wfgC746aL18HBHEmgO62Oss9jSeT+X+Ceyqfpm3BseGpqOkJust4k+Eh4L6B5djSgfvw== X-OriginatorOrg: live.com X-MS-Exchange-CrossTenant-Network-Message-Id: a7e457f0-8ff5-4a98-fc8c-08d86fe3d74d X-MS-Exchange-CrossTenant-OriginalArrivalTime: 14 Oct 2020 01:52:44.1472 (UTC) X-MS-Exchange-CrossTenant-FromEntityHeader: Hosted X-MS-Exchange-CrossTenant-Id: 84df9e7f-e9f6-40af-b435-aaaaaaaaaaaa X-MS-Exchange-CrossTenant-AuthSource: DB3EUR04FT012.eop-eur04.prod.protection.outlook.com X-MS-Exchange-CrossTenant-AuthAs: Anonymous X-MS-Exchange-CrossTenant-FromEntityHeader: Internet X-MS-Exchange-CrossTenant-RMS-PersistedConsumerOrg: 00000000-0000-0000-0000-000000000000 X-MS-Exchange-Transport-CrossTenantHeadersStamped: DB3EUR04HT177 Received-SPF: pass client-ip=40.92.75.94; envelope-from=arthur.miller@live.com; helo=EUR04-VI1-obe.outbound.protection.outlook.com X-detected-operating-system: by eggs.gnu.org: First seen = 2020/10/13 21:52:44 X-ACL-Warn: Detected OS = Windows NT kernel [generic] [fuzzy] X-Spam_score_int: -20 X-Spam_score: -2.1 X-Spam_bar: -- X-Spam_report: (-2.1 / 5.0 requ) BAYES_00=-1.9, DKIM_SIGNED=0.1, DKIM_VALID=-0.1, DKIM_VALID_AU=-0.1, DKIM_VALID_EF=-0.1, FREEMAIL_FROM=0.001, MSGID_FROM_MTA_HEADER=0.001, RCVD_IN_DNSWL_NONE=-0.0001, RCVD_IN_MSPIKE_H2=-0.001, SPF_HELO_PASS=-0.001, SPF_PASS=-0.001 autolearn=ham autolearn_force=no X-Spam_action: no action X-BeenThere: emacs-devel@gnu.org X-Mailman-Version: 2.1.23 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-mx.org@gnu.org Original-Sender: "Emacs-devel" Xref: news.gmane.io gmane.emacs.devel:257603 Archived-At: --=-=-= Content-Type: text/plain Eli Zaretskii writes: >> From: Michael Albinus >> Cc: Arthur Miller , emacs-devel@gnu.org >> Date: Tue, 13 Oct 2020 20:44:18 +0200 >> >> > As a bonus, we will be able to return the file names we read, not just >> > ignore them. >> >> I agree with your proposal. However, I don't see why it is a bonus to >> know which file names have read already, because they are taken in >> random order. > > The order depends on the filesystem. For example, MS-Windows > filesystems always report in alphabetic order. > >> I fail to see how does it help, whether a file name is returned >> under the first N matches, or not. > > Well, it is easy to disregard the names if they aren't needed. Your idea was definitely much simpler to implement, rather trivial :-). I just tested for myself, and it seems to work well. The only thing I am not sure about is how to deal with 0 count; I mean if user explicitly ask for 0 count; the case when count is not NILP. I have chosen not to deal with it all, I check for zer set explicit limit for count to be [1,COUNT]. I am not sure if that is best thing to do; maybe just to return Qnil? I am probably doing something else wrong, advice apprecaiated. I had some problems until I realized i used wrong number converter; I used fixnum, seems like I need fixnat. I am still not sure if I am correct but it seems to work now. I tested this compared to my old "native" predicate, on GNU/Linux only and just to run naked predicate on a big number of dirs, and it seems to be just very slight difference; ~0.002 vs ~0.004 definitely not dramatic as entire decimal place. I needed to "touch" 2 other files due to chagned signature of directory_files: lisp.h and sysdep.c. In attached .el file are two small tests (I run them with M-:). --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=dired.c.patch Content-Description: dired.c.patch --- src/dired.c 2020-10-14 03:35:16.781786426 +0200 +++ ../dired2.c 2020-10-14 03:35:05.271568190 +0200 @@ -20,6 +20,7 @@ #include +#include #include #ifdef HAVE_PWD_H @@ -165,7 +166,7 @@ Lisp_Object directory_files_internal (Lisp_Object directory, Lisp_Object full, Lisp_Object match, Lisp_Object nosort, bool attrs, - Lisp_Object id_format) + Lisp_Object id_format, Lisp_Object count_to_return) { if (!NILP (match)) CHECK_STRING (match); @@ -223,7 +224,14 @@ #ifdef WINDOWSNT case_table = BVAR (&buffer_defaults, case_canon_table); #endif - + + ptrdiff_t ind = 0, last = 0; + if(!NILP(count_to_return) && FIXNATP(count_to_return)) + last = XFIXNAT(count_to_return); + + if(!last) + last = 1; + /* Read directory entries and accumulate them into LIST. */ Lisp_Object list = Qnil; for (struct dirent *dp; (dp = read_dirent (d, directory)); ) @@ -267,6 +275,13 @@ else finalname = name; + if(!NILP(count_to_return) && FIXNATP(count_to_return)) + { + if(ind == last) + break; + ind ++; + } + list = Fcons (attrs ? Fcons (finalname, fileattrs) : finalname, list); } @@ -282,13 +297,13 @@ if (NILP (nosort)) list = Fsort (Fnreverse (list), attrs ? Qfile_attributes_lessp : Qstring_lessp); - + (void) directory_volatile; return list; } -DEFUN ("directory-files", Fdirectory_files, Sdirectory_files, 1, 4, 0, +DEFUN ("directory-files", Fdirectory_files, Sdirectory_files, 1, 5, 0, doc: /* Return a list of names of files in DIRECTORY. There are three optional arguments: If FULL is non-nil, return absolute file names. Otherwise return names @@ -296,9 +311,14 @@ If MATCH is non-nil, mention only file names that match the regexp MATCH. If NOSORT is non-nil, the list is not sorted--its order is unpredictable. Otherwise, the list returned is sorted with `string-lessp'. - NOSORT is useful if you plan to sort the result yourself. */) + NOSORT is useful if you plan to sort the result yourself. +If COUNT is non-nil, the function will return max (COUNT,length) + files, where length means number of files in directory. Order + in which files are returned is not guaranteed and is file system and + OS dependent. COUNT has to be an integral number in interval + [1,COUNT]. */) (Lisp_Object directory, Lisp_Object full, Lisp_Object match, - Lisp_Object nosort) + Lisp_Object nosort, Lisp_Object count) { directory = Fexpand_file_name (directory, Qnil); @@ -306,14 +326,15 @@ call the corresponding file name handler. */ Lisp_Object handler = Ffind_file_name_handler (directory, Qdirectory_files); if (!NILP (handler)) - return call5 (handler, Qdirectory_files, directory, - full, match, nosort); + return call6 (handler, Qdirectory_files, directory, + full, match, nosort, count); - return directory_files_internal (directory, full, match, nosort, false, Qnil); + return directory_files_internal (directory, full, match, nosort, + false, Qnil, count); } DEFUN ("directory-files-and-attributes", Fdirectory_files_and_attributes, - Sdirectory_files_and_attributes, 1, 5, 0, + Sdirectory_files_and_attributes, 1, 6, 0, doc: /* Return a list of names of files and their attributes in DIRECTORY. Value is a list of the form: @@ -331,9 +352,14 @@ ID-FORMAT specifies the preferred format of attributes uid and gid, see `file-attributes' for further documentation. On MS-Windows, performance depends on `w32-get-true-file-attributes', -which see. */) - (Lisp_Object directory, Lisp_Object full, Lisp_Object match, - Lisp_Object nosort, Lisp_Object id_format) +which see. +If COUNT is non-nil, the function will return max (COUNT,length) + files, where length means number of files in directory. Order + in which files are returned is not guaranteed and is file system and + OS dependent. COUNT has to be an integral number in interval + [1,COUNT]. */) +(Lisp_Object directory, Lisp_Object full, Lisp_Object match, + Lisp_Object nosort, Lisp_Object id_format, Lisp_Object count) { directory = Fexpand_file_name (directory, Qnil); @@ -342,11 +368,11 @@ Lisp_Object handler = Ffind_file_name_handler (directory, Qdirectory_files_and_attributes); if (!NILP (handler)) - return call6 (handler, Qdirectory_files_and_attributes, - directory, full, match, nosort, id_format); + return call7 (handler, Qdirectory_files_and_attributes, + directory, full, match, nosort, id_format, count); return directory_files_internal (directory, full, match, nosort, - true, id_format); + true, id_format, count); } @@ -929,7 +955,7 @@ struct stat s; /* An array to hold the mode string generated by filemodestring, - including its terminating space and null byte. */ + including its terminating space and NUL byte. */ char modes[sizeof "-rwxr-xr-x "]; char *uname = NULL, *gname = NULL; --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=sysdep.c.patch Content-Description: sysdep.c.patch --- src/sysdep.c 2020-10-13 23:22:37.521367461 +0200 +++ ../sysdep.c 2020-10-13 22:53:04.272682143 +0200 @@ -2892,7 +2892,8 @@ process. */ procdir = build_string ("/proc"); match = build_string ("[0-9]+"); - proclist = directory_files_internal (procdir, Qnil, match, Qt, false, Qnil); + proclist = directory_files_internal (procdir, Qnil, match, Qt, + false, Qnil, Qnil); /* `proclist' gives process IDs as strings. Destructively convert each string into a number. */ --=-=-= Content-Type: text/x-patch Content-Disposition: attachment; filename=lisp.h.patch Content-Description: lisp.h.patch --- src/lisp.h 2020-10-13 23:20:23.555386699 +0200 +++ ../lisp.h 2020-10-13 22:47:04.192203245 +0200 @@ -4633,7 +4633,7 @@ extern void syms_of_dired (void); extern Lisp_Object directory_files_internal (Lisp_Object, Lisp_Object, Lisp_Object, Lisp_Object, - bool, Lisp_Object); + bool, Lisp_Object, Lisp_Object); /* Defined in term.c. */ extern int *char_ins_del_vector; --=-=-= Content-Type: text/plain Content-Disposition: attachment; filename=dired-mark-empty.el Content-Description: dired-mark-empty.el (require 'dired) (defvar nodots "^\\([^.]\\|\\.\\([^.]\\|\\..\\)\\).*") (defun dired-go-to-first () (interactive) (goto-char (point-min)) (dired-next-line 1) (skip-chars-forward " \n\t")) (defun dired-is-empty-p (directory-name) (null (directory-files directory-name nil nodots t 1))) (defun directory-number-files (directory-name &optional omit-filter) (length (directory-files directory-name nil omit-filter t))) (defun dired-mark-empty-dirs () (interactive) (when (equal major-mode 'dired-mode) (let ((curr-dir)) (save-excursion (dired-go-to-first) (while (not (eobp)) (setq curr-dir (dired-file-name-at-point)) (cond ((or (null curr-dir) (string= curr-dir ".") (string= curr-dir "..")) ;; do nothing here ) ((file-directory-p curr-dir) (when (dired-is-empty-p curr-dir) (dired-mark 1) (dired-previous-line 1)))) (dired-next-line 1)))))) (defun test-1 (dir-name count) "Ask for COUNT number of files from directory DIR-NAME." (let ((max (length (directory-files dir-name nil nil t))) (res (length (directory-files dir-name nil nil t count)))) (cond ((>= max count) (if (= res count) (message "passed: asked: %d get: %d number files in dir: %d" count res max) (message "not-passed: asked: %s get: %s number files in dir: %s" count res max))) ((< max count) (if (< res count) (message "passed: asked: %d get: %d number files in dir: %d" count res max) (message "not-passed: asked: %s get: %s number files in dir: %s" count res max))) (t (message "Invalid case!"))))) (defun test-2 (dir-name count) "Ask for random number of files in interval [1,COUNT] files from every subdir of directory DIR-NAME." (let ((dirs (directory-files dir-name t nodots t))) (dolist (curr-dir dirs) (when (file-directory-p curr-dir) (test-1 curr-dir (+ 1 (random count))))))) ;;(benchmark-run-compiled 10 (dired-is-empty-p "/some/path")) ;; must be in some dired buffer for this ;;(benchmark-run-compiled 10 (dired-mark-empty-dirs)) --=-=-=--