diff options
| author | Eric Abrahamsen | 2020-08-27 17:17:19 -0700 |
|---|---|---|
| committer | Eric Abrahamsen | 2020-08-28 08:20:28 -0700 |
| commit | 4d741e577fbab8adf444c6c1930525bb7e8fc08d (patch) | |
| tree | e526dc264c9a510b7cbfbfe394e23144a506fa92 | |
| parent | 649a52822f207e1d302f0e089010b84d5e882281 (diff) | |
| download | emacs-4d741e577fbab8adf444c6c1930525bb7e8fc08d.tar.gz emacs-4d741e577fbab8adf444c6c1930525bb7e8fc08d.zip | |
Remove redundant slot validation in eieio-persistent-read
Actual object creation (in `make-instance') will later run all slot
values through cl-typep, which does a better job of validation. This
validation is redundant, and slows the read process down.
* lisp/emacs-lisp/eieio-base.el (eieio-persistent-fix-value): Rename
from `eieio-persistent-validate/fix-slot-value', as we no longer
validate, and we don't care about the slot definition.
(eieio-persistent-slot-type-is-class-p): Delete function.
(eieio-persistent-convert-list-to-object): Still call
`eieio--full-class-object', to trigger an autoload if necessary, but
discard the return value.
| -rw-r--r-- | lisp/emacs-lisp/eieio-base.el | 211 |
1 files changed, 63 insertions, 148 deletions
diff --git a/lisp/emacs-lisp/eieio-base.el b/lisp/emacs-lisp/eieio-base.el index 2cb1f614ce3..f09d1997eee 100644 --- a/lisp/emacs-lisp/eieio-base.el +++ b/lisp/emacs-lisp/eieio-base.el | |||
| @@ -266,105 +266,75 @@ malicious code. | |||
| 266 | 266 | ||
| 267 | Note: This function recurses when a slot of :type of some object is | 267 | Note: This function recurses when a slot of :type of some object is |
| 268 | identified, and needing more object creation." | 268 | identified, and needing more object creation." |
| 269 | (let* ((objclass (nth 0 inputlist)) | 269 | (let ((objclass (nth 0 inputlist)) |
| 270 | ;; Earlier versions of `object-write' added a string name for | 270 | ;; Earlier versions of `object-write' added a string name for |
| 271 | ;; the object, now obsolete. | 271 | ;; the object, now obsolete. |
| 272 | (slots (nthcdr | 272 | (slots (nthcdr |
| 273 | (if (stringp (nth 1 inputlist)) 2 1) | 273 | (if (stringp (nth 1 inputlist)) 2 1) |
| 274 | inputlist)) | 274 | inputlist)) |
| 275 | (createslots nil) | 275 | (createslots nil)) |
| 276 | (class | 276 | ;; If OBJCLASS is an eieio autoload object, then we need to |
| 277 | (progn | 277 | ;; load it (we don't need the return value). |
| 278 | ;; If OBJCLASS is an eieio autoload object, then we need to | 278 | (eieio--full-class-object objclass) |
| 279 | ;; load it. | ||
| 280 | (eieio--full-class-object objclass)))) | ||
| 281 | |||
| 282 | (while slots | 279 | (while slots |
| 283 | (let ((initarg (car slots)) | 280 | (let ((initarg (car slots)) |
| 284 | (value (car (cdr slots)))) | 281 | (value (car (cdr slots)))) |
| 285 | 282 | ||
| 286 | ;; Make sure that the value proposed for SLOT is valid. | 283 | ;; Strip out quotes, list functions, and update object |
| 287 | ;; In addition, strip out quotes, list functions, and update | 284 | ;; constructors as needed. |
| 288 | ;; object constructors as needed. | 285 | (setq value (eieio-persistent-fix-value value)) |
| 289 | (setq value (eieio-persistent-validate/fix-slot-value | ||
| 290 | class (eieio--initarg-to-attribute class initarg) value)) | ||
| 291 | 286 | ||
| 292 | (push initarg createslots) | 287 | (push initarg createslots) |
| 293 | (push value createslots) | 288 | (push value createslots)) |
| 294 | ) | ||
| 295 | 289 | ||
| 296 | (setq slots (cdr (cdr slots)))) | 290 | (setq slots (cdr (cdr slots)))) |
| 297 | 291 | ||
| 298 | (apply #'make-instance objclass (nreverse createslots)) | 292 | (apply #'make-instance objclass (nreverse createslots)))) |
| 299 | 293 | ||
| 300 | ;;(eval inputlist) | 294 | (defun eieio-persistent-fix-value (proposed-value) |
| 301 | )) | 295 | "Fix PROPOSED-VALUE. |
| 296 | Remove leading quotes from lists, and the symbol `list' from the | ||
| 297 | head of lists. Explicitly construct any objects found, and strip | ||
| 298 | any text properties from string values. | ||
| 302 | 299 | ||
| 303 | (defun eieio-persistent-validate/fix-slot-value (class slot proposed-value) | 300 | This function will descend into the contents of lists, hash |
| 304 | "Validate that in CLASS, the SLOT with PROPOSED-VALUE is good, then fix. | 301 | tables, and vectors." |
| 305 | A limited number of functions, such as quote, list, and valid object | ||
| 306 | constructor functions are considered valid. | ||
| 307 | Second, any text properties will be stripped from strings." | ||
| 308 | (cond ((consp proposed-value) | 302 | (cond ((consp proposed-value) |
| 309 | ;; Lists with something in them need special treatment. | 303 | ;; Lists with something in them need special treatment. |
| 310 | (let* ((slot-idx (- (eieio--slot-name-index class slot) | 304 | (cond ((eq (car proposed-value) 'quote) |
| 311 | (eval-when-compile eieio--object-num-slots))) | 305 | (while (eq (car-safe proposed-value) 'quote) |
| 312 | (type (cl--slot-descriptor-type (aref (eieio--class-slots class) | 306 | (setq proposed-value (car (cdr proposed-value)))) |
| 313 | slot-idx))) | 307 | proposed-value) |
| 314 | (classtype (eieio-persistent-slot-type-is-class-p type))) | 308 | |
| 315 | 309 | ;; An empty list sometimes shows up as (list), which is dumb, but | |
| 316 | (cond ((eq (car proposed-value) 'quote) | 310 | ;; we need to support it for backward compar. |
| 317 | (car (cdr proposed-value))) | 311 | ((and (eq (car proposed-value) 'list) |
| 318 | 312 | (= (length proposed-value) 1)) | |
| 319 | ;; An empty list sometimes shows up as (list), which is dumb, but | 313 | nil) |
| 320 | ;; we need to support it for backward compat. | 314 | |
| 321 | ((and (eq (car proposed-value) 'list) | 315 | ;; List of object constructors. |
| 322 | (= (length proposed-value) 1)) | 316 | ((and (eq (car proposed-value) 'list) |
| 323 | nil) | 317 | ;; 2nd item is a list. |
| 324 | 318 | (consp (car (cdr proposed-value))) | |
| 325 | ;; List of object constructors. | 319 | ;; 1st elt of 2nd item is a class name. |
| 326 | ((and (eq (car proposed-value) 'list) | 320 | (class-p (car (car (cdr proposed-value))))) |
| 327 | ;; 2nd item is a list. | 321 | |
| 328 | (consp (car (cdr proposed-value))) | 322 | ;; We have a list of objects here. Lets load them |
| 329 | ;; 1st elt of 2nd item is a class name. | 323 | ;; in. |
| 330 | (class-p (car (car (cdr proposed-value)))) | 324 | (let ((objlist nil)) |
| 331 | ) | 325 | (dolist (subobj (cdr proposed-value)) |
| 332 | 326 | (push (eieio-persistent-convert-list-to-object subobj) | |
| 333 | ;; Check the value against the input class type. | 327 | objlist)) |
| 334 | ;; If something goes wrong, issue a smart warning | 328 | ;; return the list of objects ... reversed. |
| 335 | ;; about how a :type is needed for this to work. | 329 | (nreverse objlist))) |
| 336 | (unless (and | 330 | ;; We have a slot with a single object that can be |
| 337 | ;; Do we have a type? | 331 | ;; saved here. Recurse and evaluate that |
| 338 | (consp classtype) (class-p (car classtype))) | 332 | ;; sub-object. |
| 339 | (error "In save file, list of object constructors found, but no :type specified for slot %S of type %S" | 333 | ((class-p (car proposed-value)) |
| 340 | slot classtype)) | 334 | (eieio-persistent-convert-list-to-object |
| 341 | 335 | proposed-value)) | |
| 342 | ;; We have a predicate, but it doesn't satisfy the predicate? | 336 | (t |
| 343 | (dolist (PV (cdr proposed-value)) | 337 | proposed-value))) |
| 344 | (unless (child-of-class-p (car PV) (car classtype)) | ||
| 345 | (error "Invalid object: slot member %s does not match class %s" | ||
| 346 | (car PV) (car classtype)))) | ||
| 347 | |||
| 348 | ;; We have a list of objects here. Lets load them | ||
| 349 | ;; in. | ||
| 350 | (let ((objlist nil)) | ||
| 351 | (dolist (subobj (cdr proposed-value)) | ||
| 352 | (push (eieio-persistent-convert-list-to-object subobj) | ||
| 353 | objlist)) | ||
| 354 | ;; return the list of objects ... reversed. | ||
| 355 | (nreverse objlist))) | ||
| 356 | ;; We have a slot with a single object that can be | ||
| 357 | ;; saved here. Recurse and evaluate that | ||
| 358 | ;; sub-object. | ||
| 359 | ((and classtype | ||
| 360 | (seq-some | ||
| 361 | (lambda (elt) | ||
| 362 | (child-of-class-p (car proposed-value) elt)) | ||
| 363 | (if (listp classtype) classtype (list classtype)))) | ||
| 364 | (eieio-persistent-convert-list-to-object | ||
| 365 | proposed-value)) | ||
| 366 | (t | ||
| 367 | proposed-value)))) | ||
| 368 | ;; For hash-tables and vectors, the top-level `read' will not | 338 | ;; For hash-tables and vectors, the top-level `read' will not |
| 369 | ;; "look inside" member values, so we need to do that | 339 | ;; "look inside" member values, so we need to do that |
| 370 | ;; explicitly. Because `eieio-override-prin1' is recursive in | 340 | ;; explicitly. Because `eieio-override-prin1' is recursive in |
| @@ -377,8 +347,7 @@ Second, any text properties will be stripped from strings." | |||
| 377 | (if (class-p (car-safe value)) | 347 | (if (class-p (car-safe value)) |
| 378 | (eieio-persistent-convert-list-to-object | 348 | (eieio-persistent-convert-list-to-object |
| 379 | value) | 349 | value) |
| 380 | (eieio-persistent-validate/fix-slot-value | 350 | (eieio-persistent-fix-value value)))) |
| 381 | class slot value)))) | ||
| 382 | proposed-value) | 351 | proposed-value) |
| 383 | proposed-value) | 352 | proposed-value) |
| 384 | 353 | ||
| @@ -389,70 +358,16 @@ Second, any text properties will be stripped from strings." | |||
| 389 | (if (class-p (car-safe val)) | 358 | (if (class-p (car-safe val)) |
| 390 | (eieio-persistent-convert-list-to-object | 359 | (eieio-persistent-convert-list-to-object |
| 391 | val) | 360 | val) |
| 392 | (eieio-persistent-validate/fix-slot-value | 361 | (eieio-persistent-fix-value val))))) |
| 393 | class slot val))))) | ||
| 394 | proposed-value) | 362 | proposed-value) |
| 395 | 363 | ||
| 396 | ((stringp proposed-value) | 364 | ((stringp proposed-value) |
| 397 | ;; Else, check for strings, remove properties. | 365 | ;; Else, check for strings, remove properties. |
| 398 | (substring-no-properties proposed-value)) | 366 | (substring-no-properties proposed-value)) |
| 399 | |||
| 400 | (t | ||
| 401 | ;; Else, just return whatever the constant was. | ||
| 402 | proposed-value)) | ||
| 403 | ) | ||
| 404 | |||
| 405 | (defun eieio-persistent-slot-type-is-class-p (type) | ||
| 406 | "Return the class referred to in TYPE. | ||
| 407 | If no class is referenced there, then return nil." | ||
| 408 | (cond ((class-p type) | ||
| 409 | ;; If the type is a class, then return it. | ||
| 410 | type) | ||
| 411 | ((and (eq 'list-of (car-safe type)) (class-p (cadr type))) | ||
| 412 | ;; If it is the type of a list of a class, then return that class and | ||
| 413 | ;; the type. | ||
| 414 | (cons (cadr type) type)) | ||
| 415 | |||
| 416 | ((and (symbolp type) (get type 'cl-deftype-handler)) | ||
| 417 | ;; Macro-expand the type according to cl-deftype definitions. | ||
| 418 | (eieio-persistent-slot-type-is-class-p | ||
| 419 | (funcall (get type 'cl-deftype-handler)))) | ||
| 420 | |||
| 421 | ;; FIXME: foo-child should not be a valid type! | ||
| 422 | ((and (symbolp type) (string-match "-child\\'" (symbol-name type)) | ||
| 423 | (class-p (intern-soft (substring (symbol-name type) 0 | ||
| 424 | (match-beginning 0))))) | ||
| 425 | (unless eieio-backward-compatibility | ||
| 426 | (error "Use of bogus %S type instead of %S" | ||
| 427 | type (intern-soft (substring (symbol-name type) 0 | ||
| 428 | (match-beginning 0))))) | ||
| 429 | ;; If it is the predicate ending with -child, then return | ||
| 430 | ;; that class. Unfortunately, in EIEIO, typep of just the | ||
| 431 | ;; class is the same as if we used -child, so no further work needed. | ||
| 432 | (intern-soft (substring (symbol-name type) 0 | ||
| 433 | (match-beginning 0)))) | ||
| 434 | ;; FIXME: foo-list should not be a valid type! | ||
| 435 | ((and (symbolp type) (string-match "-list\\'" (symbol-name type)) | ||
| 436 | (class-p (intern-soft (substring (symbol-name type) 0 | ||
| 437 | (match-beginning 0))))) | ||
| 438 | (unless eieio-backward-compatibility | ||
| 439 | (error "Use of bogus %S type instead of (list-of %S)" | ||
| 440 | type (intern-soft (substring (symbol-name type) 0 | ||
| 441 | (match-beginning 0))))) | ||
| 442 | ;; If it is the predicate ending with -list, then return | ||
| 443 | ;; that class and the predicate to use. | ||
| 444 | (cons (intern-soft (substring (symbol-name type) 0 | ||
| 445 | (match-beginning 0))) | ||
| 446 | type)) | ||
| 447 | |||
| 448 | ((eq (car-safe type) 'or) | ||
| 449 | ;; If type is a list, and is an `or', return all valid class | ||
| 450 | ;; types within the `or' statement. | ||
| 451 | (seq-filter #'eieio-persistent-slot-type-is-class-p (cdr type))) | ||
| 452 | 367 | ||
| 453 | (t | 368 | (t |
| 454 | ;; No match, not a class. | 369 | ;; Else, just return whatever the constant was. |
| 455 | nil))) | 370 | proposed-value))) |
| 456 | 371 | ||
| 457 | (cl-defmethod object-write ((this eieio-persistent) &optional comment) | 372 | (cl-defmethod object-write ((this eieio-persistent) &optional comment) |
| 458 | "Write persistent object THIS out to the current stream. | 373 | "Write persistent object THIS out to the current stream. |