]> git.bundesbrandschatzamt.de Git - emacsconfig.git/commitdiff
add pcache
authorAndreas Gerler <baronNOSPAMbundesbrandschatzamt.de>
Thu, 11 May 2023 16:13:45 +0000 (18:13 +0200)
committerAndreas Gerler <baronNOSPAMbundesbrandschatzamt.de>
Thu, 11 May 2023 16:13:45 +0000 (18:13 +0200)
Signed-off-by: Andreas Gerler <baronNOSPAMbundesbrandschatzamt.de>
elpa/pcache-20220724.1841/pcache-autoloads.el [new file with mode: 0644]
elpa/pcache-20220724.1841/pcache-pkg.el [new file with mode: 0644]
elpa/pcache-20220724.1841/pcache.el [new file with mode: 0644]

diff --git a/elpa/pcache-20220724.1841/pcache-autoloads.el b/elpa/pcache-20220724.1841/pcache-autoloads.el
new file mode 100644 (file)
index 0000000..b72fed2
--- /dev/null
@@ -0,0 +1,22 @@
+;;; pcache-autoloads.el --- automatically extracted autoloads  -*- lexical-binding: t -*-
+;;
+;;; Code:
+
+(add-to-list 'load-path (directory-file-name
+                         (or (file-name-directory #$) (car load-path))))
+
+\f
+;;;### (autoloads nil "pcache" "pcache.el" (0 0 0 0))
+;;; Generated autoloads from pcache.el
+
+(register-definition-prefixes "pcache" '("*pcache-repositor" "pcache-"))
+
+;;;***
+\f
+;; Local Variables:
+;; version-control: never
+;; no-byte-compile: t
+;; no-update-autoloads: t
+;; coding: utf-8
+;; End:
+;;; pcache-autoloads.el ends here
diff --git a/elpa/pcache-20220724.1841/pcache-pkg.el b/elpa/pcache-20220724.1841/pcache-pkg.el
new file mode 100644 (file)
index 0000000..691ed0e
--- /dev/null
@@ -0,0 +1,2 @@
+;;; Generated package description from pcache.el  -*- no-byte-compile: t -*-
+(define-package "pcache" "20220724.1841" "persistent caching for Emacs." '((emacs "25.1")) :commit "cae29ddbc3d12fac18ab5cfc26fa3ef13eb97dad" :authors '(("Yann Hodique" . "yann.hodiqueNOSPAMgmail.com")) :maintainer '("Yann Hodique" . "yann.hodiqueNOSPAMgmail.com") :keywords '("extensions"))
diff --git a/elpa/pcache-20220724.1841/pcache.el b/elpa/pcache-20220724.1841/pcache.el
new file mode 100644 (file)
index 0000000..209cdb1
--- /dev/null
@@ -0,0 +1,262 @@
+;;; pcache.el --- persistent caching for Emacs. -*- lexical-binding: t; -*-
+
+;; Copyright (C) 2011-2020  Yann Hodique
+
+;; Author: Yann Hodique <yann.hodiqueNOSPAMgmail.com>
+;; Keywords: extensions
+;; Package-Version: 20220724.1841
+;; Package-Commit: cae29ddbc3d12fac18ab5cfc26fa3ef13eb97dad
+;; Version: 0.5.1
+;; Package-Requires: ((emacs "25.1"))
+
+;; This file is free software; you can redistribute it and/or modify
+;; it under the terms of the GNU General Public License as published by
+;; the Free Software Foundation; either version 2, or (at your option)
+;; any later version.
+
+;; This file is distributed in the hope that it will be useful,
+;; but WITHOUT ANY WARRANTY; without even the implied warranty of
+;; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+;; GNU General Public License for more details.
+
+;; You should have received a copy of the GNU General Public License
+;; along with GNU Emacs; see the file COPYING.  If not, write to
+;; the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+;; Boston, MA 02111-1307, USA.
+
+;;; Commentary:
+
+;; pcache provides a persistent way of caching data, in a hashtable-like
+;; structure. It relies on `eieio-persistent' in the backend, so that any
+;; object that can be serialized by EIEIO can be stored with pcache.
+
+;; pcache handles objects called "repositories" (`pcache-repository') and
+;; "entries" (`pcache-entry'). Each repository is identified by a unique name,
+;; that defines an entry in `pcache-directory'. Subdirectories are allowed, by
+;; the use of a directory separator in the repository name.
+
+;; Example:
+;; (let ((repo (pcache-repository "plop")))
+;;   (pcache-put repo 'foo 42) ; store value 42 with key 'foo
+;;   (pcache-get repo 'foo) ; => 42
+;; )
+
+;; Keys can be pretty much any Lisp object, and are compared for equality using
+;; `eql'
+
+;; Optionally, cache entries can expire:
+;; (let ((repo (pcache-repository "plop")))
+;;   (pcache-put repo 'foo 42 1) ; store value 42 with key 'foo for 1 second
+;;   (sleep-for 1)
+;;   (pcache-get repo 'foo) ; => nil
+;; )
+
+;;; Code:
+
+(require 'cl-lib)
+(require 'cl-extra)
+(require 'eieio)
+(require 'eieio-base)
+
+(defvar pcache-directory (concat user-emacs-directory "var/pcache/"))
+
+(defvar *pcache-repositories* (make-hash-table :test 'equal))
+
+(defvar pcache-avoid-recursion nil)
+
+(defconst pcache-default-save-delay 300)
+
+(defconst pcache-internal-version-constant "0.5")
+
+(defconst pcache-version-constant
+  (format "%s/%s" emacs-version pcache-internal-version-constant))
+
+(defclass pcache-repository (eieio-persistent eieio-named)
+  ((version :initarg :version :initform nil)
+   (version-constant :allocation :class)
+   (entries :initarg :entries :initform (make-hash-table))
+   (entry-cls :initarg :entry-cls :initform pcache-entry)
+   (timestamp :initarg :timestamp :initform (float-time (current-time)))
+   (save-delay :initarg :save-delay)))
+
+(oset-default 'pcache-repository :save-delay pcache-default-save-delay)
+(oset-default 'pcache-repository version-constant pcache-version-constant)
+
+(defvar *pcache-repository-name* nil)
+
+(cl-defmethod make-instance ((cls (subclass pcache-repository)) &rest args)
+  (let* ((newname (or (and (stringp (car args)) (car args))
+                      (plist-get args :object-name)
+                      *pcache-repository-name*
+                      (symbol-name cls)))
+         (e (gethash newname *pcache-repositories*))
+         (path (concat pcache-directory newname)))
+    (setq args (append args (list :object-name newname)))
+    (or e
+        (and (not pcache-avoid-recursion)
+             (file-exists-p path)
+             (condition-case nil
+                 (let* ((pcache-avoid-recursion t)
+                        (*pcache-repository-name* newname)
+                        (obj (eieio-persistent-read path 'pcache-repository t)))
+                   (and (or (pcache-validate-repo obj)
+                            (error "wrong version"))
+                        (puthash newname obj *pcache-repositories*)
+                        obj))
+               (error nil)))
+        (let ((obj (cl-call-next-method))
+              (dir (file-name-directory path)))
+          (unless (file-exists-p dir)
+            (make-directory dir t))
+          (oset obj :file path)
+          (oset obj :version (oref-default obj version-constant))
+          (puthash newname obj *pcache-repositories*)
+          obj))))
+
+(defun pcache-hash-table-values (h)
+  (let (values)
+    (maphash (lambda (k v) (push v values)) h)
+    values))
+
+;; force custom implementation.
+(cl-defmethod pcache-validate-repo ((cache t))
+  nil)
+
+(cl-defmethod pcache-validate-repo ((cache pcache-repository))
+  (and
+   (equal (oref cache version)
+          (oref-default (eieio-object-class cache) version-constant))
+   (hash-table-p (oref cache entries))
+   (cl-every
+    (function
+     (lambda (entry)
+       (and (object-of-class-p entry (oref cache entry-cls))
+            (pcache-validate-entry entry))))
+    (pcache-hash-table-values (oref cache entries)))))
+
+(defclass pcache-entry ()
+  ((timestamp :initarg :timestamp
+              :initform (float-time (current-time)))
+   (ttl :initarg :ttl :initform nil)
+   (value :initarg :value :initform nil)
+   (value-cls :initarg :value-cls :initform nil)))
+
+;; force custom implementation.
+(cl-defmethod pcache-validate-entry ((entry t))
+  nil)
+
+(cl-defmethod pcache-validate-entry ((entry pcache-entry))
+  (or (null (oref entry value-cls))
+      (object-of-class-p
+       (oref entry value) (oref entry value-cls))))
+
+(cl-defmethod pcache-entry-valid-p ((entry pcache-entry))
+  (let ((ttl (oref entry ttl)))
+    (or (null ttl)
+        (let ((time (float-time (current-time))))
+          (< time (+ ttl (oref entry timestamp)))))))
+
+(cl-defmethod pcache-get ((cache pcache-repository) key &optional default)
+  (let* ((table (oref cache entries))
+         (entry (gethash key table)))
+    (if entry
+        (if (pcache-entry-valid-p entry)
+            (oref entry value)
+          (remhash key table)
+          default)
+      default)))
+
+(cl-defmethod pcache-has ((cache pcache-repository) key)
+  (let* ((default (make-symbol ":nil"))
+         (table (oref cache entries))
+         (entry (gethash key table default)))
+    (if (eq entry default) nil
+      (if (pcache-entry-valid-p entry)
+          t nil))))
+
+(cl-defmethod pcache-put ((cache pcache-repository) key value &optional ttl)
+  (let ((table (oref cache entries))
+        (entry (or (and (eieio-object-p value)
+                        (object-of-class-p value 'pcache-entry)
+                        value)
+                   (make-instance
+                    (oref cache entry-cls)
+                    :value value
+                    :value-cls (and (eieio-object-p value) (eieio-object-class value))))))
+    (when ttl
+      (oset entry :ttl ttl))
+    (prog1
+        (puthash key entry table)
+      (pcache-save cache))))
+
+(cl-defmethod pcache-invalidate ((cache pcache-repository) key)
+  (let ((table (oref cache entries)))
+    (remhash key table)
+    (pcache-save cache)))
+
+(cl-defmethod pcache-clear ((cache pcache-repository))
+  (let* ((entries (oref cache entries))
+         (test (hash-table-test entries))
+         (resize (hash-table-rehash-size entries))
+         (threshold (hash-table-rehash-threshold entries))
+         (weakness (hash-table-weakness entries)))
+    (oset cache :entries (make-hash-table :test test :rehash-size resize
+                                          :rehash-threshold threshold
+                                          :weakness weakness)))
+  (pcache-save cache))
+
+(cl-defmethod pcache-purge-invalid ((cache pcache-repository))
+  (let ((table (oref cache entries)))
+    (maphash (lambda (k e)
+                 (unless (pcache-entry-valid-p e)
+                   (remhash k table)))
+             table)
+    (pcache-save cache)))
+
+(cl-defmethod pcache-save ((cache pcache-repository) &optional force)
+  (let ((timestamp (oref cache timestamp))
+        (delay (oref cache save-delay))
+        (time (float-time (current-time))))
+    (when (or force (> time (+ timestamp delay)))
+      (oset cache :timestamp time)
+      ;; make sure version is saved to file
+      (oset cache :version (oref-default (eieio-object-class cache) version-constant))
+      (eieio-persistent-save cache))))
+
+(cl-defmethod pcache-map ((cache pcache-repository) func)
+  (let ((table (oref cache entries)))
+    (maphash func table)))
+
+(defun pcache-kill-emacs-hook ()
+  (maphash (lambda (k v)
+               (condition-case nil
+                   (pcache-purge-invalid v)
+                 (error nil))
+              (condition-case nil
+                  (pcache-save v t)
+                (error nil)))
+           *pcache-repositories*))
+
+(defun pcache-destroy-repository (name)
+  (remhash name *pcache-repositories*)
+  (let ((fname (concat pcache-directory name)))
+    (when (file-exists-p fname)
+      (delete-file fname))))
+
+(add-hook 'kill-emacs-hook #'pcache-kill-emacs-hook)
+
+;; in case we reload in place, clean all repositories with invalid version
+(let (to-clean)
+  (maphash (lambda (k v)
+               (condition-case nil
+                   (unless (eql (oref v version)
+                                pcache-version-constant)
+                     (signal 'error nil))
+                 (error
+                  (setq to-clean (cons k to-clean)))))
+           *pcache-repositories*)
+  (dolist (k to-clean)
+    (remhash k *pcache-repositories*)))
+
+(provide 'pcache)
+;;; pcache.el ends here