guile-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[PATCH] Avoid GOOPS in (system foreign-object)?


From: Ludovic Courtès
Subject: [PATCH] Avoid GOOPS in (system foreign-object)?
Date: Thu, 21 May 2015 17:28:16 +0200
User-agent: Gnus/5.13 (Gnus v5.13) Emacs/24.5 (gnu/linux)

Hello!

I would like to have foreign object types based on structs rather than
GOOPS classes.

The rationale is that GOOPS is normally not loaded unless the user
explicitly asks for it; having (system foreign-objects) load it would
add overhead even for users who just want SMOB-like functionality.

WDYT?

The preliminary patch attached is an attempt to do that.  Somehow, the
creation of GOOPS classes for vtables doesn’t work as I thought, which
means that ‘test-foreign-object-scm’ cannot define methods and so on
(which I agree is useful functionality.)  What am I missing?

Thanks!

Ludo’.

PS: The reason I’m looking at it is that I would really want us to
    release 2.0.12 ASAP, so any changes to this API must be settled.

6fb47e8e1977e6aed9a3f636c463365a8e7cf7b9 HEAD wip-foreign-objects
Author: Ludovic Courtès <address@hidden>
Date:   Thu May 21 17:03:40 2015 +0200

    foreign-object: Rebase on top of structs instead of GOOPS.

3 files changed, 75 insertions(+), 92 deletions(-)
 libguile/foreign-object.c                     |  6 +-
 module/system/foreign-object.scm              | 99 +++++++++++++++------------
 test-suite/standalone/test-foreign-object-scm | 62 +++++------------

        Modified   libguile/foreign-object.c
diff --git a/libguile/foreign-object.c b/libguile/foreign-object.c
index 830f73f..e631f17 100644
--- a/libguile/foreign-object.c
+++ b/libguile/foreign-object.c
@@ -1,4 +1,4 @@
-/* Copyright (C) 2014 Free Software Foundation, Inc.
+/* Copyright (C) 2014, 2015 Free Software Foundation, Inc.
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public License
@@ -23,7 +23,6 @@
 #endif
 
 #include "libguile/_scm.h"
-#include "libguile/goops.h"
 #include "libguile/foreign-object.h"
 
 
@@ -58,7 +57,8 @@ scm_make_foreign_object_type (SCM name, SCM slot_names,
 void
 scm_assert_foreign_object_type (SCM type, SCM val)
 {
-  if (!SCM_IS_A_P (val, type))
+  if (!SCM_STRUCTP (val)
+      || !scm_is_eq (SCM_STRUCT_VTABLE (val), type))
     scm_error (scm_arg_type_key, NULL, "Wrong type (expecting ~A): ~S",
                scm_list_2 (scm_class_name (type), val), scm_list_1 (val));
 }
        Modified   module/system/foreign-object.scm
diff --git a/module/system/foreign-object.scm b/module/system/foreign-object.scm
index f7bfc94..cde9664 100644
--- a/module/system/foreign-object.scm
+++ b/module/system/foreign-object.scm
@@ -23,7 +23,7 @@
 ;;; Code:
 
 (define-module (system foreign-object)
-  #:use-module (oop goops)
+  #:use-module (system foreign)
   #:export     (make-foreign-object-type
                 define-foreign-object-type))
 
@@ -31,59 +31,70 @@
   (load-extension (string-append "libguile-" (effective-version))
                   "scm_init_foreign_object"))
 
-(define-class <foreign-class> (<class>))
+;; Constant from struct.h.
+(define vtable-index-finalizer 3)
 
-(define-class <foreign-class-with-finalizer> (<foreign-class>)
-  (finalizer #:init-keyword #:finalizer #:init-value #f
-             #:getter finalizer))
+(define <foreign-vtable>
+  ;; The meta-vtable for foreign structs.
+  (make-struct/no-tail <standard-vtable>
+                       (make-struct-layout standard-vtable-fields)
+                       (lambda (obj port)
+                         (format port "#<foreign-vtable ~a ~a>"
+                                 (struct-vtable-name obj)
+                                 (number->string (object-address obj) 16)))))
+
+(define* (make-foreign-vtable name layout
+                              #:key finalizer printer)
+  "Return a vtable called NAME for foreign objects with the given
+LAYOUT, PRINTER, and FINALIZER."
+  (let ((vtable (make-struct/no-tail <foreign-vtable>
+                                     (make-struct-layout layout)
+                                     printer)))
+    ;; Note: as a side-effect, this defines a GOOPS class for VTABLE.
+    (set-struct-vtable-name! vtable name)
 
-(define-method (allocate-instance (class <foreign-class-with-finalizer>)
-                                  initargs)
-  (let ((instance (next-method))
-        (finalizer (finalizer class)))
     (when finalizer
-      (%add-finalizer! instance finalizer))
-    instance))
+      (let ((c-finalizer (procedure->pointer void
+                                             (compose finalizer pointer->scm)
+                                             '(*))))
+        (struct-set! vtable vtable-index-finalizer
+                     (pointer-address c-finalizer))))
+    vtable))
 
-(define* (make-foreign-object-type name slots #:key finalizer
-                                   (getters (map (const #f) slots)))
+(define* (make-foreign-object-type name slots #:key finalizer printer)
   (unless (symbol? name)
     (error "type name should be a symbol" name))
   (unless (or (not finalizer) (procedure? finalizer))
     (error "finalizer should be a procedure" finalizer))
-  (let ((dslots (map (lambda (slot getter)
-                       (unless (symbol? slot)
-                         (error "slot name should be a symbol" slot))
-                       (cons* slot #:class <foreign-slot>
-                              #:init-keyword (symbol->keyword slot)
-                              #:init-value 0
-                              (if getter (list #:getter getter) '())))
-                     slots
-                     getters)))
-    (if finalizer
-        (make-class '() dslots #:name name
-                    #:finalizer finalizer
-                    #:metaclass <foreign-class-with-finalizer>)
-        (make-class '() dslots #:name name
-                    #:metaclass <foreign-class>))))
+  (unless (or (not printer) (procedure? printer))
+    (error "printer should be a procedure" printer))
+  (make-foreign-vtable name
+                       (string-concatenate (map (const "uw") slots))
+                       #:finalizer finalizer
+                       #:printer printer))
+
+(define (wrong-type-error s who)
+  (throw 'wrong-type-arg who
+         "Wrong type argument: ~S" (list s)
+         (list s)))
+
+(define-syntax-rule (assert-valid-struct type obj proc)
+  (unless (eq? type (struct-vtable obj))
+    (wrong-type-error obj proc)))
 
 (define-syntax define-foreign-object-type
   (lambda (x)
-    (define (kw-apply slots)
-      (syntax-case slots ()
-        (() #'())
-        ((slot . slots)
-         (let ((kw (symbol->keyword (syntax->datum #'slot))))
-           #`(#,kw slot . #,(kw-apply #'slots))))))
-
     (syntax-case x ()
       ((_ name constructor (slot ...) kwarg ...)
-       #`(begin
-           (define slot (ensure-generic 'slot (and (defined? 'slot) slot)))
-           ...
-           (define name
-             (make-foreign-object-type 'name '(slot ...) kwarg ...
-                                       #:getters (list slot ...)))
-           (define constructor
-             (lambda (slot ...)
-               (make name #,@(kw-apply #'(slot ...))))))))))
+       (with-syntax (((index ...) (iota (length #'(slot ...)))))
+         #`(begin
+             (define-inlinable (slot obj)
+               (assert-valid-struct name obj 'slot)
+               (struct-ref obj index))
+             ...
+             (define name
+               (make-foreign-object-type 'name '(slot ...) kwarg ...))
+             (define constructor
+               (lambda (slot ...)
+                 (make-struct/no-tail name slot ...)))))))))
+
        Modified   test-suite/standalone/test-foreign-object-scm
diff --git a/test-suite/standalone/test-foreign-object-scm 
b/test-suite/standalone/test-foreign-object-scm
index 7e4bd85..8e6de39 100755
--- a/test-suite/standalone/test-foreign-object-scm
+++ b/test-suite/standalone/test-foreign-object-scm
@@ -3,7 +3,7 @@ exec guile -q -s "$0" "$@"
 !#
 ;;; test-foreign-object-scm --- Foreign object interface.     -*- Scheme -*-
 ;;;
-;;; Copyright (C) 2014 Free Software Foundation, Inc.
+;;; Copyright (C) 2014, 2015 Free Software Foundation, Inc.
 ;;;
 ;;; This library is free software; you can redistribute it and/or
 ;;; modify it under the terms of the GNU Lesser General Public
@@ -21,8 +21,7 @@ exec guile -q -s "$0" "$@"
 
 (use-modules (system foreign)
              (system foreign-object)
-             (rnrs bytevectors)
-             (oop goops))
+             (rnrs bytevectors))
 
 (define (libc-ptr name)
   (catch #t
@@ -36,14 +35,18 @@ exec guile -q -s "$0" "$@"
 (define memcpy (pointer->procedure void (libc-ptr "memcpy") (list '* '* 
size_t)))
 (define free (pointer->procedure void (libc-ptr "free") '(*)))
 
-(define (finalize-cstr cstr)
-  (free (make-pointer (addr cstr))))
-
-(define-foreign-object-type <cstr> make-cstr (addr len)
-  #:finalizer finalize-cstr)
+(define-foreign-object-type <cstr>
+  make-cstr
+  (cstr-addr cstr-len)
+  #:finalizer (lambda (cstr)
+                (free (make-pointer (cstr-addr cstr))))
+  #:printer (lambda (cstr port)
+              (format port "<<cstr> ~s>" (cstr->string cstr))))
 
 (define (cstr->string cstr)
-  (pointer->string (make-pointer (addr cstr)) (len cstr) "UTF-8"))
+  (pointer->string (make-pointer (cstr-addr cstr))
+                   (cstr-len cstr)
+                   "UTF-8"))
 
 (define* (string->cstr str #:optional (k make-cstr))
   (let* ((bv (string->utf8 str))
@@ -54,18 +57,9 @@ exec guile -q -s "$0" "$@"
     (memcpy mem (bytevector->pointer bv) len)
     (k (pointer-address mem) len)))
 
-(define-method (write (cstr <cstr>) port)
-  (format port "<<cstr> ~s>" (cstr->string cstr)))
-
-(define-method (display (cstr <cstr>) port)
-  (display (cstr->string cstr) port))
-
-(define-method (+ (a <cstr>) (b <cstr>))
+(define (cstr-append a b)
   (string->cstr (string-append (cstr->string a) (cstr->string b))))
 
-(define-method (equal? (a <cstr>) (b <cstr>))
-  (equal? (cstr->string a) (cstr->string b)))
-
 (define failed? #f)
 (define-syntax test
   (syntax-rules ()
@@ -76,34 +70,12 @@ exec guile -q -s "$0" "$@"
            (begin
              (set! failed? #t)
              (format (current-error-port)
-                     "bad return from expression `~a': expected ~A; got ~A~%"
+                     "bad return from expression `~a': expected ~s; got ~s~%"
                      'exp expected actual)))))))
 
-(test (string->cstr "Hello, world!")
-      (+ (string->cstr "Hello, ") (string->cstr "world!")))
-
-;; GOOPS construction syntax instead of make-cstr.
-(test (string->cstr "Hello, world!")
-      (string->cstr "Hello, world!"
-                    (lambda (addr len)
-                      (make <cstr> #:addr addr #:len len))))
-
-;; Subclassing.
-(define-class <wrapped-cstr> (<cstr>)
-  (wrapped-string #:init-keyword #:wrapped-string
-                  #:getter wrapped-string
-                  #:init-form (error "missing #:wrapped-string")))
-
-(define (string->wrapped-cstr string)
-  (string->cstr string (lambda (addr len)
-                         (make <wrapped-cstr> #:addr addr #:len len
-                               #:wrapped-string string))))
-
-(let ((wrapped-cstr (string->wrapped-cstr "Hello, world!")))
-  ;; Tests that <cst> methods work on <wrapped-cstr>.
-  (test "Hello, world!" (cstr->string wrapped-cstr))
-  ;; Test the additional #:wrapped-string slot.
-  (test "Hello, world!" (wrapped-string wrapped-cstr)))
+(test "Hello, world!"
+      (cstr->string
+       (cstr-append (string->cstr "Hello, ") (string->cstr "world!"))))
 
 (gc) (gc) (gc)

reply via email to

[Prev in Thread] Current Thread [Next in Thread]