unofficial mirror of guile-devel@gnu.org 
 help / color / mirror / Atom feed
* [PATCH] Add procedures to convert alists into hash tables
@ 2013-10-20 14:14 David Thompson
  2013-10-20 14:28 ` David Thompson
  2013-10-29 12:38 ` Ludovic Courtès
  0 siblings, 2 replies; 23+ messages in thread
From: David Thompson @ 2013-10-20 14:14 UTC (permalink / raw)
  To: guile-devel

[-- Attachment #1: Type: text/plain, Size: 346 bytes --]

Hello all,

When looking through the different hash table implementations available 
(Guile, SRFI-69, and RNRS) I found a useful SRFI-69 procedure that had 
no equivalent in Guile's native hash table API: alist->hash-table.

This patch is an attempt to add that. It works for all four types of 
hash tables: equal?, eq?, eqv? and custom.

- Dave

[-- Attachment #2: 0001-Add-procedures-to-convert-alists-into-hash-tables.patch --]
[-- Type: text/x-patch, Size: 6298 bytes --]

From e303098404321cbe2b978d526ee2737137a5d5b1 Mon Sep 17 00:00:00 2001
From: David Thompson <dthompson2@worcester.edu>
Date: Sat, 19 Oct 2013 22:43:37 -0400
Subject: [PATCH] Add procedures to convert alists into hash tables.

* libguile/hashtab.c (scm_alist_to_hash_table, scm_alist_to_hashq_table,
  scm_alist_to_hashv_table, scm_alist_to_hashx_table): Add the
  equivalent of SRFI-69's alist->hash-table procedure for the native
  hash table implementation.

* test-suite/tests/hash.test ("alist->hash-table"): Add tests.

* doc/ref/api-compound.texi (alist->hash-table): Add docs.
---
 doc/ref/api-compound.texi  | 18 ++++++++++++++
 libguile/hashtab.c         | 61 ++++++++++++++++++++++++++++++++++++++++++++++
 libguile/hashtab.h         |  6 +++++
 test-suite/tests/hash.test | 27 ++++++++++++++++++++
 4 files changed, 112 insertions(+)

diff --git a/doc/ref/api-compound.texi b/doc/ref/api-compound.texi
index 94e0145..9794e28 100644
--- a/doc/ref/api-compound.texi
+++ b/doc/ref/api-compound.texi
@@ -3829,6 +3829,24 @@ then it can use @var{size} to avoid rehashing when initial entries are
 added.
 @end deffn
 
+@deffn {Scheme Procedure} alist->hash-table alist [size]
+@deffnx {Scheme Procedure} alist->hashq-table alist [size]
+@deffnx {Scheme Procedure} alist->hashv-table alist [size]
+@deffnx {Scheme Procedure} alist->hashx-table hash assoc alist [size]
+@deffnx {C Function} scm_alist_to_hash_table (alist, size)
+@deffnx {C Function} scm_alist_to_hashq_table (alist, size)
+@deffnx {C Function} scm_alist_to_hashv_table (alist, size)
+@deffnx {C Function} scm_alist_to_hashx_table (alist, size)
+Convert @var{alist} into a hash table with minimum number of buckets
+@var{n}. When keys are repeated in @var{alist}, the leftmost association
+takes precedence.
+
+@example
+(alist->hash-table '((foo . 1) (bar . 2)))
+@end example
+
+@end deffn
+
 @deffn {Scheme Procedure} hash-table? obj
 @deffnx {C Function} scm_hash_table_p (obj)
 Return @code{#t} if @var{obj} is a abstract hash table object.
diff --git a/libguile/hashtab.c b/libguile/hashtab.c
index 88cb199..c215269 100644
--- a/libguile/hashtab.c
+++ b/libguile/hashtab.c
@@ -423,6 +423,67 @@ SCM_DEFINE (scm_make_hash_table, "make-hash-table", 0, 1, 0,
 }
 #undef FUNC_NAME
 
+#define SCM_ALIST_TO_HASH_TABLE(alist, n, hash_set_fn) \
+  SCM hash_table; \
+  SCM_VALIDATE_LIST (1, alist); \
+  hash_table = scm_make_hash_table (n); \
+  while (!scm_is_null (alist)) { \
+    SCM pair = SCM_CAR (alist); \
+    hash_set_fn (hash_table, scm_car (pair), scm_cdr (pair));   \
+    alist = SCM_CDR (alist); \
+  } \
+  return hash_table;
+
+SCM_DEFINE (scm_alist_to_hash_table, "alist->hash-table", 1, 1, 0,
+	    (SCM alist, SCM n),
+            "Convert @var{alist} into a hash table with minimum number of "
+            "buckets @var{n}.")
+#define FUNC_NAME s_scm_alist_to_hash_table
+{
+  SCM_ALIST_TO_HASH_TABLE (alist, n, scm_hash_set_x);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_alist_to_hashq_table, "alist->hashq-table", 1, 1, 0,
+	    (SCM alist, SCM n),
+            "Convert @var{alist} into a hash table with minimum number of "
+            "buckets @var{n}.")
+#define FUNC_NAME s_scm_alist_to_hashq_table
+{
+  SCM_ALIST_TO_HASH_TABLE (alist, n, scm_hashq_set_x);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_alist_to_hashv_table, "alist->hashv-table", 1, 1, 0,
+	    (SCM alist, SCM n),
+            "Convert @var{alist} into a hash table with minimum number of "
+            "buckets @var{n}.")
+#define FUNC_NAME s_scm_alist_to_hashv_table
+{
+  SCM_ALIST_TO_HASH_TABLE (alist, n, scm_hashv_set_x);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_alist_to_hashx_table, "alist->hashx-table", 3, 1, 0,
+	    (SCM hash, SCM assoc, SCM alist, SCM n),
+            "Convert @var{alist} into a hash table with minimum number of "
+            "buckets @var{n}.")
+#define FUNC_NAME s_scm_alist_to_hashx_table
+{
+  SCM hash_table;
+  SCM_VALIDATE_LIST (3, alist);
+  hash_table = scm_make_hash_table (n);
+
+  while (!scm_is_null (alist)) {
+    SCM pair = SCM_CAR (alist);
+    scm_hashx_set_x (hash, assoc, hash_table, scm_car (pair), scm_cdr (pair));
+    alist = SCM_CDR (alist);
+  }
+
+  return hash_table;
+}
+#undef FUNC_NAME
+
 /* The before-gc C hook only runs if GC_set_start_callback is available,
    so if not, fall back on a finalizer-based implementation.  */
 static int
diff --git a/libguile/hashtab.h b/libguile/hashtab.h
index dcebcb8..da4f28c 100644
--- a/libguile/hashtab.h
+++ b/libguile/hashtab.h
@@ -101,6 +101,12 @@ SCM_API SCM scm_make_weak_key_hash_table (SCM k);
 SCM_API SCM scm_make_weak_value_hash_table (SCM k);
 SCM_API SCM scm_make_doubly_weak_hash_table (SCM k);
 
+SCM_API SCM scm_alist_to_hash_table (SCM alist, SCM n);
+SCM_API SCM scm_alist_to_hashq_table (SCM alist, SCM n);
+SCM_API SCM scm_alist_to_hashv_table (SCM alist, SCM n);
+SCM_API SCM scm_alist_to_hashx_table (SCM hash, SCM assoc,
+                                      SCM alist, SCM n);
+
 SCM_API SCM scm_hash_table_p (SCM h);
 SCM_API SCM scm_weak_key_hash_table_p (SCM h);
 SCM_API SCM scm_weak_value_hash_table_p (SCM h);
diff --git a/test-suite/tests/hash.test b/test-suite/tests/hash.test
index 3bd4004..b09c0b8 100644
--- a/test-suite/tests/hash.test
+++ b/test-suite/tests/hash.test
@@ -81,6 +81,33 @@
                               (write (make-hash-table 100)))))))
 
 ;;;
+;;; alist->hash-table
+;;;
+
+(with-test-prefix
+  "alist->hash-table"
+
+  ;; equal? hash table
+  (pass-if (let ((table (alist->hash-table '(("foo" . 1) ("bar" . 2)))))
+             (and (= (hash-ref table "foo") 1)
+                  (= (hash-ref table "bar") 2))))
+
+  ;; eq? hash table
+  (pass-if (let ((table (alist->hashq-table '((foo . 1) (bar . 2)))))
+             (and (= (hashq-ref table 'foo) 1)
+                  (= (hashq-ref table 'bar) 2))))
+
+  ;; eqv? hash table
+  (pass-if (let ((table (alist->hashv-table '((1 . 1) (2 . 2)))))
+             (and (= (hashv-ref table 1) 1)
+                  (= (hashv-ref table 2) 2))))
+
+  ;; custom hash table
+  (pass-if (let ((table (alist->hashx-table hash assoc '((foo . 1) (bar . 2)))))
+             (and (= (hashx-ref hash assoc table 'foo) 1)
+                  (= (hashx-ref hash assoc table 'bar) 2)))))
+
+;;;
 ;;; usual set and reference
 ;;;
 
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-10-20 14:14 [PATCH] Add procedures to convert alists into hash tables David Thompson
@ 2013-10-20 14:28 ` David Thompson
  2013-10-21 17:00   ` Mark H Weaver
  2013-10-29 12:38 ` Ludovic Courtès
  1 sibling, 1 reply; 23+ messages in thread
From: David Thompson @ 2013-10-20 14:28 UTC (permalink / raw)
  To: guile-devel

[-- Attachment #1: Type: text/plain, Size: 480 bytes --]

On 10/20/2013 10:14 AM, David Thompson wrote:
> Hello all,
>
> When looking through the different hash table implementations 
> available (Guile, SRFI-69, and RNRS) I found a useful SRFI-69 
> procedure that had no equivalent in Guile's native hash table API: 
> alist->hash-table.
>
> This patch is an attempt to add that. It works for all four types of 
> hash tables: equal?, eq?, eqv? and custom.
>
> - Dave
Found an inconsistency in the docs. Updated patch attached.

- Dave

[-- Attachment #2: 0001-Add-procedures-to-convert-alists-into-hash-tables.patch --]
[-- Type: text/x-patch, Size: 6314 bytes --]

From 46b7905727ad2efed2dc1d1aca4d4ad00d8f48c5 Mon Sep 17 00:00:00 2001
From: David Thompson <dthompson2@worcester.edu>
Date: Sat, 19 Oct 2013 22:43:37 -0400
Subject: [PATCH] Add procedures to convert alists into hash tables.

* libguile/hashtab.c (scm_alist_to_hash_table, scm_alist_to_hashq_table,
  scm_alist_to_hashv_table, scm_alist_to_hashx_table): Add the
  equivalent of SRFI-69's alist->hash-table procedure for the native
  hash table implementation.

* test-suite/tests/hash.test ("alist->hash-table"): Add tests.

* doc/ref/api-compound.texi (alist->hash-table): Add docs.
---
 doc/ref/api-compound.texi  | 18 ++++++++++++++
 libguile/hashtab.c         | 61 ++++++++++++++++++++++++++++++++++++++++++++++
 libguile/hashtab.h         |  6 +++++
 test-suite/tests/hash.test | 27 ++++++++++++++++++++
 4 files changed, 112 insertions(+)

diff --git a/doc/ref/api-compound.texi b/doc/ref/api-compound.texi
index 94e0145..06115be 100644
--- a/doc/ref/api-compound.texi
+++ b/doc/ref/api-compound.texi
@@ -3829,6 +3829,24 @@ then it can use @var{size} to avoid rehashing when initial entries are
 added.
 @end deffn
 
+@deffn {Scheme Procedure} alist->hash-table alist [size]
+@deffnx {Scheme Procedure} alist->hashq-table alist [size]
+@deffnx {Scheme Procedure} alist->hashv-table alist [size]
+@deffnx {Scheme Procedure} alist->hashx-table hash assoc alist [size]
+@deffnx {C Function} scm_alist_to_hash_table (alist, size)
+@deffnx {C Function} scm_alist_to_hashq_table (alist, size)
+@deffnx {C Function} scm_alist_to_hashv_table (alist, size)
+@deffnx {C Function} scm_alist_to_hashx_table (hash, assoc, alist, size)
+Convert @var{alist} into a hash table with minimum number of buckets
+@var{size}. When keys are repeated in @var{alist}, the leftmost
+association takes precedence.
+
+@example
+(alist->hash-table '((foo . 1) (bar . 2)))
+@end example
+
+@end deffn
+
 @deffn {Scheme Procedure} hash-table? obj
 @deffnx {C Function} scm_hash_table_p (obj)
 Return @code{#t} if @var{obj} is a abstract hash table object.
diff --git a/libguile/hashtab.c b/libguile/hashtab.c
index 88cb199..c215269 100644
--- a/libguile/hashtab.c
+++ b/libguile/hashtab.c
@@ -423,6 +423,67 @@ SCM_DEFINE (scm_make_hash_table, "make-hash-table", 0, 1, 0,
 }
 #undef FUNC_NAME
 
+#define SCM_ALIST_TO_HASH_TABLE(alist, n, hash_set_fn) \
+  SCM hash_table; \
+  SCM_VALIDATE_LIST (1, alist); \
+  hash_table = scm_make_hash_table (n); \
+  while (!scm_is_null (alist)) { \
+    SCM pair = SCM_CAR (alist); \
+    hash_set_fn (hash_table, scm_car (pair), scm_cdr (pair));   \
+    alist = SCM_CDR (alist); \
+  } \
+  return hash_table;
+
+SCM_DEFINE (scm_alist_to_hash_table, "alist->hash-table", 1, 1, 0,
+	    (SCM alist, SCM n),
+            "Convert @var{alist} into a hash table with minimum number of "
+            "buckets @var{n}.")
+#define FUNC_NAME s_scm_alist_to_hash_table
+{
+  SCM_ALIST_TO_HASH_TABLE (alist, n, scm_hash_set_x);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_alist_to_hashq_table, "alist->hashq-table", 1, 1, 0,
+	    (SCM alist, SCM n),
+            "Convert @var{alist} into a hash table with minimum number of "
+            "buckets @var{n}.")
+#define FUNC_NAME s_scm_alist_to_hashq_table
+{
+  SCM_ALIST_TO_HASH_TABLE (alist, n, scm_hashq_set_x);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_alist_to_hashv_table, "alist->hashv-table", 1, 1, 0,
+	    (SCM alist, SCM n),
+            "Convert @var{alist} into a hash table with minimum number of "
+            "buckets @var{n}.")
+#define FUNC_NAME s_scm_alist_to_hashv_table
+{
+  SCM_ALIST_TO_HASH_TABLE (alist, n, scm_hashv_set_x);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_alist_to_hashx_table, "alist->hashx-table", 3, 1, 0,
+	    (SCM hash, SCM assoc, SCM alist, SCM n),
+            "Convert @var{alist} into a hash table with minimum number of "
+            "buckets @var{n}.")
+#define FUNC_NAME s_scm_alist_to_hashx_table
+{
+  SCM hash_table;
+  SCM_VALIDATE_LIST (3, alist);
+  hash_table = scm_make_hash_table (n);
+
+  while (!scm_is_null (alist)) {
+    SCM pair = SCM_CAR (alist);
+    scm_hashx_set_x (hash, assoc, hash_table, scm_car (pair), scm_cdr (pair));
+    alist = SCM_CDR (alist);
+  }
+
+  return hash_table;
+}
+#undef FUNC_NAME
+
 /* The before-gc C hook only runs if GC_set_start_callback is available,
    so if not, fall back on a finalizer-based implementation.  */
 static int
diff --git a/libguile/hashtab.h b/libguile/hashtab.h
index dcebcb8..da4f28c 100644
--- a/libguile/hashtab.h
+++ b/libguile/hashtab.h
@@ -101,6 +101,12 @@ SCM_API SCM scm_make_weak_key_hash_table (SCM k);
 SCM_API SCM scm_make_weak_value_hash_table (SCM k);
 SCM_API SCM scm_make_doubly_weak_hash_table (SCM k);
 
+SCM_API SCM scm_alist_to_hash_table (SCM alist, SCM n);
+SCM_API SCM scm_alist_to_hashq_table (SCM alist, SCM n);
+SCM_API SCM scm_alist_to_hashv_table (SCM alist, SCM n);
+SCM_API SCM scm_alist_to_hashx_table (SCM hash, SCM assoc,
+                                      SCM alist, SCM n);
+
 SCM_API SCM scm_hash_table_p (SCM h);
 SCM_API SCM scm_weak_key_hash_table_p (SCM h);
 SCM_API SCM scm_weak_value_hash_table_p (SCM h);
diff --git a/test-suite/tests/hash.test b/test-suite/tests/hash.test
index 3bd4004..b09c0b8 100644
--- a/test-suite/tests/hash.test
+++ b/test-suite/tests/hash.test
@@ -81,6 +81,33 @@
                               (write (make-hash-table 100)))))))
 
 ;;;
+;;; alist->hash-table
+;;;
+
+(with-test-prefix
+  "alist->hash-table"
+
+  ;; equal? hash table
+  (pass-if (let ((table (alist->hash-table '(("foo" . 1) ("bar" . 2)))))
+             (and (= (hash-ref table "foo") 1)
+                  (= (hash-ref table "bar") 2))))
+
+  ;; eq? hash table
+  (pass-if (let ((table (alist->hashq-table '((foo . 1) (bar . 2)))))
+             (and (= (hashq-ref table 'foo) 1)
+                  (= (hashq-ref table 'bar) 2))))
+
+  ;; eqv? hash table
+  (pass-if (let ((table (alist->hashv-table '((1 . 1) (2 . 2)))))
+             (and (= (hashv-ref table 1) 1)
+                  (= (hashv-ref table 2) 2))))
+
+  ;; custom hash table
+  (pass-if (let ((table (alist->hashx-table hash assoc '((foo . 1) (bar . 2)))))
+             (and (= (hashx-ref hash assoc table 'foo) 1)
+                  (= (hashx-ref hash assoc table 'bar) 2)))))
+
+;;;
 ;;; usual set and reference
 ;;;
 
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-10-20 14:28 ` David Thompson
@ 2013-10-21 17:00   ` Mark H Weaver
  2013-10-22  3:03     ` David Thompson
  2013-10-26 11:41     ` David Thompson
  0 siblings, 2 replies; 23+ messages in thread
From: Mark H Weaver @ 2013-10-21 17:00 UTC (permalink / raw)
  To: David Thompson; +Cc: guile-devel

Hi David,

David Thompson <dthompson2@worcester.edu> writes:
> On 10/20/2013 10:14 AM, David Thompson wrote:
>> Hello all,
>>
>> When looking through the different hash table implementations
>> available (Guile, SRFI-69, and RNRS) I found a useful SRFI-69
>> procedure that had no equivalent in Guile's native hash table API:
>> alist->hash-table.
>>
>> This patch is an attempt to add that. It works for all four types of
>> hash tables: equal?, eq?, eqv? and custom.
>>
>> - Dave
> Found an inconsistency in the docs. Updated patch attached.

The patch mostly looks good to me, but a few minor issues remain.
See below for my comments.

> From 46b7905727ad2efed2dc1d1aca4d4ad00d8f48c5 Mon Sep 17 00:00:00 2001
> From: David Thompson <dthompson2@worcester.edu>
> Date: Sat, 19 Oct 2013 22:43:37 -0400
> Subject: [PATCH] Add procedures to convert alists into hash tables.
>
> * libguile/hashtab.c (scm_alist_to_hash_table, scm_alist_to_hashq_table,
>   scm_alist_to_hashv_table, scm_alist_to_hashx_table): Add the
>   equivalent of SRFI-69's alist->hash-table procedure for the native
>   hash table implementation.

In general, commit logs shouldn't describe what the new procedures do,
nor should they provide rationale.  Those things belong in code
comments.  Here, it is sufficient to write "New procedures."

You should also mention the new macro SCM_ALIST_TO_HASH_TABLE, as well
as the new prototypes in hashtab.h.

> * test-suite/tests/hash.test ("alist->hash-table"): Add tests.
>
> * doc/ref/api-compound.texi (alist->hash-table): Add docs.

For .texi files, the part in parentheses here should be the node name
where the changes were made.  To find it, I usually search backwards for
"@node".  In this case, the node name is "Hash Table Reference".

> ---
>  doc/ref/api-compound.texi  | 18 ++++++++++++++
>  libguile/hashtab.c         | 61 ++++++++++++++++++++++++++++++++++++++++++++++
>  libguile/hashtab.h         |  6 +++++
>  test-suite/tests/hash.test | 27 ++++++++++++++++++++
>  4 files changed, 112 insertions(+)
>
> diff --git a/doc/ref/api-compound.texi b/doc/ref/api-compound.texi
> index 94e0145..06115be 100644
> --- a/doc/ref/api-compound.texi
> +++ b/doc/ref/api-compound.texi
> @@ -3829,6 +3829,24 @@ then it can use @var{size} to avoid rehashing when initial entries are
>  added.
>  @end deffn
>  
> +@deffn {Scheme Procedure} alist->hash-table alist [size]
> +@deffnx {Scheme Procedure} alist->hashq-table alist [size]
> +@deffnx {Scheme Procedure} alist->hashv-table alist [size]
> +@deffnx {Scheme Procedure} alist->hashx-table hash assoc alist [size]
> +@deffnx {C Function} scm_alist_to_hash_table (alist, size)
> +@deffnx {C Function} scm_alist_to_hashq_table (alist, size)
> +@deffnx {C Function} scm_alist_to_hashv_table (alist, size)
> +@deffnx {C Function} scm_alist_to_hashx_table (hash, assoc, alist, size)
> +Convert @var{alist} into a hash table with minimum number of buckets
> +@var{size}. When keys are repeated in @var{alist}, the leftmost
> +association takes precedence.

A few thoughts:

* Are you sure that the leftmost association takes precedence?  From
  looking at the code, I'd expect the _rightmost_ association to take
  precedence.  In either case, since it's mentioned explicitly in the
  docs, it would be good if the test suite checked this.

* For 'alist->hashx-table' (and 'scm_alist_to_hashx_table') the 'hash'
  and 'assoc' arguments should probably be mentioned, and it would be
  good to include an example of its use.

* I'm not sure the 'size' argument is worth keeping here.  It seems to
  me that it will rarely be used.  It might be better to instead compute
  the size automatically from the alist.  What do you think?

  If you did this, you should use the internal 'scm_ilength' function,
  which is robust against improper lists and even circular lists, in
  which case it returns -1.  (In fact, SCM_VALIDATE_LIST works by simply
  calling scm_ilength and checking that the result is non-negative.)

> +@example
> +(alist->hash-table '((foo . 1) (bar . 2)))
> +@end example
> +
> +@end deffn
> +
>  @deffn {Scheme Procedure} hash-table? obj
>  @deffnx {C Function} scm_hash_table_p (obj)
>  Return @code{#t} if @var{obj} is a abstract hash table object.
> diff --git a/libguile/hashtab.c b/libguile/hashtab.c
> index 88cb199..c215269 100644
> --- a/libguile/hashtab.c
> +++ b/libguile/hashtab.c
> @@ -423,6 +423,67 @@ SCM_DEFINE (scm_make_hash_table, "make-hash-table", 0, 1, 0,
>  }
>  #undef FUNC_NAME
>  
> +#define SCM_ALIST_TO_HASH_TABLE(alist, n, hash_set_fn) \
> +  SCM hash_table; \
> +  SCM_VALIDATE_LIST (1, alist); \
> +  hash_table = scm_make_hash_table (n); \
> +  while (!scm_is_null (alist)) { \
> +    SCM pair = SCM_CAR (alist); \
> +    hash_set_fn (hash_table, scm_car (pair), scm_cdr (pair));   \
> +    alist = SCM_CDR (alist); \
> +  } \
> +  return hash_table;

This is a nitpick, but according to our usual style, the backslashes
should be lined up in a single column.

> +
> +SCM_DEFINE (scm_alist_to_hash_table, "alist->hash-table", 1, 1, 0,
> +	    (SCM alist, SCM n),

More nitpicking: there's a tab in the line above, which messes up the
indentation.

> +            "Convert @var{alist} into a hash table with minimum number of "
> +            "buckets @var{n}.")
> +#define FUNC_NAME s_scm_alist_to_hash_table
> +{
> +  SCM_ALIST_TO_HASH_TABLE (alist, n, scm_hash_set_x);
> +}
> +#undef FUNC_NAME
> +
> +SCM_DEFINE (scm_alist_to_hashq_table, "alist->hashq-table", 1, 1, 0,
> +	    (SCM alist, SCM n),

Ditto ^^

> +            "Convert @var{alist} into a hash table with minimum number of "
> +            "buckets @var{n}.")
> +#define FUNC_NAME s_scm_alist_to_hashq_table
> +{
> +  SCM_ALIST_TO_HASH_TABLE (alist, n, scm_hashq_set_x);
> +}
> +#undef FUNC_NAME
> +
> +SCM_DEFINE (scm_alist_to_hashv_table, "alist->hashv-table", 1, 1, 0,
> +	    (SCM alist, SCM n),

Ditto ^^

> +            "Convert @var{alist} into a hash table with minimum number of "
> +            "buckets @var{n}.")
> +#define FUNC_NAME s_scm_alist_to_hashv_table
> +{
> +  SCM_ALIST_TO_HASH_TABLE (alist, n, scm_hashv_set_x);
> +}
> +#undef FUNC_NAME
> +
> +SCM_DEFINE (scm_alist_to_hashx_table, "alist->hashx-table", 3, 1, 0,
> +	    (SCM hash, SCM assoc, SCM alist, SCM n),

Ditto ^^

> +            "Convert @var{alist} into a hash table with minimum number of "
> +            "buckets @var{n}.")

Please mention the 'hash' and 'assoc' arguments in the docstring.

> +#define FUNC_NAME s_scm_alist_to_hashx_table
> +{
> +  SCM hash_table;
> +  SCM_VALIDATE_LIST (3, alist);
> +  hash_table = scm_make_hash_table (n);
> +
> +  while (!scm_is_null (alist)) {
> +    SCM pair = SCM_CAR (alist);
> +    scm_hashx_set_x (hash, assoc, hash_table, scm_car (pair), scm_cdr (pair));
> +    alist = SCM_CDR (alist);
> +  }
> +
> +  return hash_table;
> +}
> +#undef FUNC_NAME
> +
>  /* The before-gc C hook only runs if GC_set_start_callback is available,
>     so if not, fall back on a finalizer-based implementation.  */
>  static int
> diff --git a/libguile/hashtab.h b/libguile/hashtab.h
> index dcebcb8..da4f28c 100644
> --- a/libguile/hashtab.h
> +++ b/libguile/hashtab.h
> @@ -101,6 +101,12 @@ SCM_API SCM scm_make_weak_key_hash_table (SCM k);
>  SCM_API SCM scm_make_weak_value_hash_table (SCM k);
>  SCM_API SCM scm_make_doubly_weak_hash_table (SCM k);
>  
> +SCM_API SCM scm_alist_to_hash_table (SCM alist, SCM n);
> +SCM_API SCM scm_alist_to_hashq_table (SCM alist, SCM n);
> +SCM_API SCM scm_alist_to_hashv_table (SCM alist, SCM n);
> +SCM_API SCM scm_alist_to_hashx_table (SCM hash, SCM assoc,
> +                                      SCM alist, SCM n);
> +
>  SCM_API SCM scm_hash_table_p (SCM h);
>  SCM_API SCM scm_weak_key_hash_table_p (SCM h);
>  SCM_API SCM scm_weak_value_hash_table_p (SCM h);
> diff --git a/test-suite/tests/hash.test b/test-suite/tests/hash.test
> index 3bd4004..b09c0b8 100644
> --- a/test-suite/tests/hash.test
> +++ b/test-suite/tests/hash.test
> @@ -81,6 +81,33 @@
>                                (write (make-hash-table 100)))))))
>  
>  ;;;
> +;;; alist->hash-table
> +;;;
> +
> +(with-test-prefix
> +  "alist->hash-table"
> +
> +  ;; equal? hash table
> +  (pass-if (let ((table (alist->hash-table '(("foo" . 1) ("bar" . 2)))))
> +             (and (= (hash-ref table "foo") 1)
> +                  (= (hash-ref table "bar") 2))))
> +
> +  ;; eq? hash table
> +  (pass-if (let ((table (alist->hashq-table '((foo . 1) (bar . 2)))))
> +             (and (= (hashq-ref table 'foo) 1)
> +                  (= (hashq-ref table 'bar) 2))))
> +
> +  ;; eqv? hash table
> +  (pass-if (let ((table (alist->hashv-table '((1 . 1) (2 . 2)))))
> +             (and (= (hashv-ref table 1) 1)
> +                  (= (hashv-ref table 2) 2))))
> +
> +  ;; custom hash table
> +  (pass-if (let ((table (alist->hashx-table hash assoc '((foo . 1) (bar . 2)))))
> +             (and (= (hashx-ref hash assoc table 'foo) 1)
> +                  (= (hashx-ref hash assoc table 'bar) 2)))))
> +
> +;;;
>  ;;; usual set and reference
>  ;;;



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-10-21 17:00   ` Mark H Weaver
@ 2013-10-22  3:03     ` David Thompson
  2013-10-28 12:17       ` Chris K. Jester-Young
  2013-10-26 11:41     ` David Thompson
  1 sibling, 1 reply; 23+ messages in thread
From: David Thompson @ 2013-10-22  3:03 UTC (permalink / raw)
  To: Mark H Weaver; +Cc: guile-devel

[-- Attachment #1: Type: text/plain, Size: 9207 bytes --]

Thank you for taking the time to give some really useful feedback, Mark 
Weaver. I appreciate it.

On 10/21/2013 01:00 PM, Mark H Weaver wrote:
> Hi David,
>
>>  From 46b7905727ad2efed2dc1d1aca4d4ad00d8f48c5 Mon Sep 17 00:00:00 2001
>> From: David Thompson <dthompson2@worcester.edu>
>> Date: Sat, 19 Oct 2013 22:43:37 -0400
>> Subject: [PATCH] Add procedures to convert alists into hash tables.
>>
>> * libguile/hashtab.c (scm_alist_to_hash_table, scm_alist_to_hashq_table,
>>    scm_alist_to_hashv_table, scm_alist_to_hashx_table): Add the
>>    equivalent of SRFI-69's alist->hash-table procedure for the native
>>    hash table implementation.
>
> In general, commit logs shouldn't describe what the new procedures do,
> nor should they provide rationale.  Those things belong in code
> comments.  Here, it is sufficient to write "New procedures."
>
> You should also mention the new macro SCM_ALIST_TO_HASH_TABLE, as well
> as the new prototypes in hashtab.h.
>
>> * test-suite/tests/hash.test ("alist->hash-table"): Add tests.
>>
>> * doc/ref/api-compound.texi (alist->hash-table): Add docs.
>
> For .texi files, the part in parentheses here should be the node name
> where the changes were made.  To find it, I usually search backwards for
> "@node".  In this case, the node name is "Hash Table Reference".

Good to know. Still trying to get used to this commit format.

>
>> ---
>>   doc/ref/api-compound.texi  | 18 ++++++++++++++
>>   libguile/hashtab.c         | 61 ++++++++++++++++++++++++++++++++++++++++++++++
>>   libguile/hashtab.h         |  6 +++++
>>   test-suite/tests/hash.test | 27 ++++++++++++++++++++
>>   4 files changed, 112 insertions(+)
>>
>> diff --git a/doc/ref/api-compound.texi b/doc/ref/api-compound.texi
>> index 94e0145..06115be 100644
>> --- a/doc/ref/api-compound.texi
>> +++ b/doc/ref/api-compound.texi
>> @@ -3829,6 +3829,24 @@ then it can use @var{size} to avoid rehashing when initial entries are
>>   added.
>>   @end deffn
>>
>> +@deffn {Scheme Procedure} alist->hash-table alist [size]
>> +@deffnx {Scheme Procedure} alist->hashq-table alist [size]
>> +@deffnx {Scheme Procedure} alist->hashv-table alist [size]
>> +@deffnx {Scheme Procedure} alist->hashx-table hash assoc alist [size]
>> +@deffnx {C Function} scm_alist_to_hash_table (alist, size)
>> +@deffnx {C Function} scm_alist_to_hashq_table (alist, size)
>> +@deffnx {C Function} scm_alist_to_hashv_table (alist, size)
>> +@deffnx {C Function} scm_alist_to_hashx_table (hash, assoc, alist, size)
>> +Convert @var{alist} into a hash table with minimum number of buckets
>> +@var{size}. When keys are repeated in @var{alist}, the leftmost
>> +association takes precedence.
>
> A few thoughts:
>
> * Are you sure that the leftmost association takes precedence?  From
>    looking at the code, I'd expect the _rightmost_ association to take
>    precedence.  In either case, since it's mentioned explicitly in the
>    docs, it would be good if the test suite checked this.

You are right. I have changed the code such that the leftmost 
association actually takes precedence and the tests check for this.
>
> * For 'alist->hashx-table' (and 'scm_alist_to_hashx_table') the 'hash'
>    and 'assoc' arguments should probably be mentioned, and it would be
>    good to include an example of its use.
>
> * I'm not sure the 'size' argument is worth keeping here.  It seems to
>    me that it will rarely be used.  It might be better to instead compute
>    the size automatically from the alist.  What do you think?
>
>    If you did this, you should use the internal 'scm_ilength' function,
>    which is robust against improper lists and even circular lists, in
>    which case it returns -1.  (In fact, SCM_VALIDATE_LIST works by simply
>    calling scm_ilength and checking that the result is non-negative.)

'size' argument is gone in favor of using 'scm_ilength'.

>
>> +@example
>> +(alist->hash-table '((foo . 1) (bar . 2)))
>> +@end example
>> +
>> +@end deffn
>> +
>>   @deffn {Scheme Procedure} hash-table? obj
>>   @deffnx {C Function} scm_hash_table_p (obj)
>>   Return @code{#t} if @var{obj} is a abstract hash table object.
>> diff --git a/libguile/hashtab.c b/libguile/hashtab.c
>> index 88cb199..c215269 100644
>> --- a/libguile/hashtab.c
>> +++ b/libguile/hashtab.c
>> @@ -423,6 +423,67 @@ SCM_DEFINE (scm_make_hash_table, "make-hash-table", 0, 1, 0,
>>   }
>>   #undef FUNC_NAME
>>
>> +#define SCM_ALIST_TO_HASH_TABLE(alist, n, hash_set_fn) \
>> +  SCM hash_table; \
>> +  SCM_VALIDATE_LIST (1, alist); \
>> +  hash_table = scm_make_hash_table (n); \
>> +  while (!scm_is_null (alist)) { \
>> +    SCM pair = SCM_CAR (alist); \
>> +    hash_set_fn (hash_table, scm_car (pair), scm_cdr (pair));   \
>> +    alist = SCM_CDR (alist); \
>> +  } \
>> +  return hash_table;
>
> This is a nitpick, but according to our usual style, the backslashes
> should be lined up in a single column.

Much prettier.

>
>> +
>> +SCM_DEFINE (scm_alist_to_hash_table, "alist->hash-table", 1, 1, 0,
>> +	    (SCM alist, SCM n),
>
> More nitpicking: there's a tab in the line above, which messes up the
> indentation.

When kill/yank goes wrong. Fixed.

>
>> +            "Convert @var{alist} into a hash table with minimum number of "
>> +            "buckets @var{n}.")
>> +#define FUNC_NAME s_scm_alist_to_hash_table
>> +{
>> +  SCM_ALIST_TO_HASH_TABLE (alist, n, scm_hash_set_x);
>> +}
>> +#undef FUNC_NAME
>> +
>> +SCM_DEFINE (scm_alist_to_hashq_table, "alist->hashq-table", 1, 1, 0,
>> +	    (SCM alist, SCM n),
>
> Ditto ^^
>
>> +            "Convert @var{alist} into a hash table with minimum number of "
>> +            "buckets @var{n}.")
>> +#define FUNC_NAME s_scm_alist_to_hashq_table
>> +{
>> +  SCM_ALIST_TO_HASH_TABLE (alist, n, scm_hashq_set_x);
>> +}
>> +#undef FUNC_NAME
>> +
>> +SCM_DEFINE (scm_alist_to_hashv_table, "alist->hashv-table", 1, 1, 0,
>> +	    (SCM alist, SCM n),
>
> Ditto ^^
>
>> +            "Convert @var{alist} into a hash table with minimum number of "
>> +            "buckets @var{n}.")
>> +#define FUNC_NAME s_scm_alist_to_hashv_table
>> +{
>> +  SCM_ALIST_TO_HASH_TABLE (alist, n, scm_hashv_set_x);
>> +}
>> +#undef FUNC_NAME
>> +
>> +SCM_DEFINE (scm_alist_to_hashx_table, "alist->hashx-table", 3, 1, 0,
>> +	    (SCM hash, SCM assoc, SCM alist, SCM n),
>
> Ditto ^^
>
>> +            "Convert @var{alist} into a hash table with minimum number of "
>> +            "buckets @var{n}.")
>
> Please mention the 'hash' and 'assoc' arguments in the docstring.

Mentioned.

>
>> +#define FUNC_NAME s_scm_alist_to_hashx_table
>> +{
>> +  SCM hash_table;
>> +  SCM_VALIDATE_LIST (3, alist);
>> +  hash_table = scm_make_hash_table (n);
>> +
>> +  while (!scm_is_null (alist)) {
>> +    SCM pair = SCM_CAR (alist);
>> +    scm_hashx_set_x (hash, assoc, hash_table, scm_car (pair), scm_cdr (pair));
>> +    alist = SCM_CDR (alist);
>> +  }
>> +
>> +  return hash_table;
>> +}
>> +#undef FUNC_NAME
>> +
>>   /* The before-gc C hook only runs if GC_set_start_callback is available,
>>      so if not, fall back on a finalizer-based implementation.  */
>>   static int
>> diff --git a/libguile/hashtab.h b/libguile/hashtab.h
>> index dcebcb8..da4f28c 100644
>> --- a/libguile/hashtab.h
>> +++ b/libguile/hashtab.h
>> @@ -101,6 +101,12 @@ SCM_API SCM scm_make_weak_key_hash_table (SCM k);
>>   SCM_API SCM scm_make_weak_value_hash_table (SCM k);
>>   SCM_API SCM scm_make_doubly_weak_hash_table (SCM k);
>>
>> +SCM_API SCM scm_alist_to_hash_table (SCM alist, SCM n);
>> +SCM_API SCM scm_alist_to_hashq_table (SCM alist, SCM n);
>> +SCM_API SCM scm_alist_to_hashv_table (SCM alist, SCM n);
>> +SCM_API SCM scm_alist_to_hashx_table (SCM hash, SCM assoc,
>> +                                      SCM alist, SCM n);
>> +
>>   SCM_API SCM scm_hash_table_p (SCM h);
>>   SCM_API SCM scm_weak_key_hash_table_p (SCM h);
>>   SCM_API SCM scm_weak_value_hash_table_p (SCM h);
>> diff --git a/test-suite/tests/hash.test b/test-suite/tests/hash.test
>> index 3bd4004..b09c0b8 100644
>> --- a/test-suite/tests/hash.test
>> +++ b/test-suite/tests/hash.test
>> @@ -81,6 +81,33 @@
>>                                 (write (make-hash-table 100)))))))
>>
>>   ;;;
>> +;;; alist->hash-table
>> +;;;
>> +
>> +(with-test-prefix
>> +  "alist->hash-table"
>> +
>> +  ;; equal? hash table
>> +  (pass-if (let ((table (alist->hash-table '(("foo" . 1) ("bar" . 2)))))
>> +             (and (= (hash-ref table "foo") 1)
>> +                  (= (hash-ref table "bar") 2))))
>> +
>> +  ;; eq? hash table
>> +  (pass-if (let ((table (alist->hashq-table '((foo . 1) (bar . 2)))))
>> +             (and (= (hashq-ref table 'foo) 1)
>> +                  (= (hashq-ref table 'bar) 2))))
>> +
>> +  ;; eqv? hash table
>> +  (pass-if (let ((table (alist->hashv-table '((1 . 1) (2 . 2)))))
>> +             (and (= (hashv-ref table 1) 1)
>> +                  (= (hashv-ref table 2) 2))))
>> +
>> +  ;; custom hash table
>> +  (pass-if (let ((table (alist->hashx-table hash assoc '((foo . 1) (bar . 2)))))
>> +             (and (= (hashx-ref hash assoc table 'foo) 1)
>> +                  (= (hashx-ref hash assoc table 'bar) 2)))))
>> +
>> +;;;
>>   ;;; usual set and reference
>>   ;;;

Updated patch attached.

- Dave

[-- Attachment #2: 0001-Add-procedures-to-convert-alists-into-hash-tables.patch --]
[-- Type: text/x-patch, Size: 7587 bytes --]

From f971e341d6ead7ee0c082030672b25fee640be2d Mon Sep 17 00:00:00 2001
From: David Thompson <dthompson2@worcester.edu>
Date: Sat, 19 Oct 2013 22:43:37 -0400
Subject: [PATCH] Add procedures to convert alists into hash tables.

* libguile/hashtab.h (scm_alist_to_hash_table, scm_alist_to_hashq_table,
  scm_alist_to_hashv_table, scm_alist_to_hashx_table): New prototypes.

* libguile/hashtab.c (scm_alist_to_hash_table, scm_alist_to_hashq_table,
  scm_alist_to_hashv_table, scm_alist_to_hashx_table): New procedures.
  (SCM_ALIST_TO_HASH_TABLE): New macro.

* test-suite/tests/hash.test ("alist->hash-table"): Add tests.

* doc/ref/api-compound.texi (Hash Table Reference): Add docs.
---
 doc/ref/api-compound.texi  | 24 +++++++++++++++++
 libguile/hashtab.c         | 67 ++++++++++++++++++++++++++++++++++++++++++++++
 libguile/hashtab.h         |  5 ++++
 test-suite/tests/hash.test | 35 ++++++++++++++++++++++++
 4 files changed, 131 insertions(+)

diff --git a/doc/ref/api-compound.texi b/doc/ref/api-compound.texi
index 94e0145..e13c9c4 100644
--- a/doc/ref/api-compound.texi
+++ b/doc/ref/api-compound.texi
@@ -3829,6 +3829,30 @@ then it can use @var{size} to avoid rehashing when initial entries are
 added.
 @end deffn
 
+@deffn {Scheme Procedure} alist->hash-table alist
+@deffnx {Scheme Procedure} alist->hashq-table alist
+@deffnx {Scheme Procedure} alist->hashv-table alist
+@deffnx {Scheme Procedure} alist->hashx-table hash assoc alist
+@deffnx {C Function} scm_alist_to_hash_table (alist)
+@deffnx {C Function} scm_alist_to_hashq_table (alist)
+@deffnx {C Function} scm_alist_to_hashv_table (alist)
+@deffnx {C Function} scm_alist_to_hashx_table (hash, assoc, alist)
+Convert @var{alist} into a hash table. When keys are repeated in
+@var{alist}, the leftmost association takes precedence.
+
+@example
+(alist->hash-table '((foo . 1) (bar . 2)))
+@end example
+
+When converting to an extended hash table, custom @var{hash} and
+@var{assoc} procedures must be provided.
+
+@example
+(alist->hash-table hash assoc '((foo . 1) (bar . 2)))
+@end example
+
+@end deffn
+
 @deffn {Scheme Procedure} hash-table? obj
 @deffnx {C Function} scm_hash_table_p (obj)
 Return @code{#t} if @var{obj} is a abstract hash table object.
diff --git a/libguile/hashtab.c b/libguile/hashtab.c
index 88cb199..8bf5230 100644
--- a/libguile/hashtab.c
+++ b/libguile/hashtab.c
@@ -423,6 +423,73 @@ SCM_DEFINE (scm_make_hash_table, "make-hash-table", 0, 1, 0,
 }
 #undef FUNC_NAME
 
+#define SCM_ALIST_TO_HASH_TABLE(alist, hash_set_fn, hash_get_handle_fn) \
+  SCM hash_table;                                                       \
+  SCM_VALIDATE_LIST (1, alist);                                         \
+  hash_table = make_hash_table (0, scm_ilength (alist), FUNC_NAME);     \
+  while (!scm_is_null (alist)) {                                        \
+    SCM pair = SCM_CAR (alist);                                         \
+    SCM key = scm_car (pair);                                           \
+    SCM value = scm_cdr (pair);                                         \
+    if (scm_is_false (hash_get_handle_fn (hash_table, key))) {          \
+      hash_set_fn (hash_table, key, value);                             \
+    }                                                                   \
+    alist = SCM_CDR (alist);                                            \
+  }                                                                     \
+  return hash_table;
+
+SCM_DEFINE (scm_alist_to_hash_table, "alist->hash-table", 1, 0, 0,
+            (SCM alist),
+            "Convert @var{alist} into a hash table.")
+#define FUNC_NAME s_scm_alist_to_hash_table
+{
+  SCM_ALIST_TO_HASH_TABLE (alist, scm_hash_set_x, scm_hash_get_handle);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_alist_to_hashq_table, "alist->hashq-table", 1, 0, 0,
+            (SCM alist),
+            "Convert @var{alist} into a hash table.")
+#define FUNC_NAME s_scm_alist_to_hashq_table
+{
+  SCM_ALIST_TO_HASH_TABLE (alist, scm_hashq_set_x, scm_hashq_get_handle);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_alist_to_hashv_table, "alist->hashv-table", 1, 0, 0,
+            (SCM alist),
+            "Convert @var{alist} into a hash table.")
+#define FUNC_NAME s_scm_alist_to_hashv_table
+{
+  SCM_ALIST_TO_HASH_TABLE (alist, scm_hashv_set_x, scm_hashv_get_handle);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_alist_to_hashx_table, "alist->hashx-table", 3, 0, 0,
+            (SCM hash, SCM assoc, SCM alist),
+            "Convert @var{alist} into a hash table with custom @var{hash} and"
+            "@var{assoc} procedures.")
+#define FUNC_NAME s_scm_alist_to_hashx_table
+{
+  SCM hash_table;
+  SCM_VALIDATE_LIST (3, alist);
+  hash_table = make_hash_table (0, scm_ilength (alist), FUNC_NAME);
+
+  while (!scm_is_null (alist)) {
+    SCM pair = SCM_CAR (alist);
+    SCM key = scm_car (pair);
+    SCM value = scm_cdr (pair);
+
+    if (scm_is_false (scm_hashx_get_handle (hash, assoc, hash_table, key))) {
+      scm_hashx_set_x (hash, assoc, hash_table, key, value);
+    }
+    alist = SCM_CDR (alist);
+  }
+
+  return hash_table;
+}
+#undef FUNC_NAME
+
 /* The before-gc C hook only runs if GC_set_start_callback is available,
    so if not, fall back on a finalizer-based implementation.  */
 static int
diff --git a/libguile/hashtab.h b/libguile/hashtab.h
index dcebcb8..270efe9 100644
--- a/libguile/hashtab.h
+++ b/libguile/hashtab.h
@@ -101,6 +101,11 @@ SCM_API SCM scm_make_weak_key_hash_table (SCM k);
 SCM_API SCM scm_make_weak_value_hash_table (SCM k);
 SCM_API SCM scm_make_doubly_weak_hash_table (SCM k);
 
+SCM_API SCM scm_alist_to_hash_table (SCM alist);
+SCM_API SCM scm_alist_to_hashq_table (SCM alist);
+SCM_API SCM scm_alist_to_hashv_table (SCM alist);
+SCM_API SCM scm_alist_to_hashx_table (SCM hash, SCM assoc, SCM alist);
+
 SCM_API SCM scm_hash_table_p (SCM h);
 SCM_API SCM scm_weak_key_hash_table_p (SCM h);
 SCM_API SCM scm_weak_value_hash_table_p (SCM h);
diff --git a/test-suite/tests/hash.test b/test-suite/tests/hash.test
index 3bd4004..820e522 100644
--- a/test-suite/tests/hash.test
+++ b/test-suite/tests/hash.test
@@ -81,6 +81,41 @@
                               (write (make-hash-table 100)))))))
 
 ;;;
+;;; alist->hash-table
+;;;
+
+(with-test-prefix
+  "alist->hash-table"
+
+  ;; equal? hash table
+  (pass-if (let ((table (alist->hash-table '(("foo" . 1)
+                                             ("bar" . 2)
+                                             ("foo" . 3)))))
+             (and (= (hash-ref table "foo") 1)
+                  (= (hash-ref table "bar") 2))))
+
+  ;; eq? hash table
+  (pass-if (let ((table (alist->hashq-table '((foo . 1)
+                                              (bar . 2)
+                                              (foo . 3)))))
+             (and (= (hashq-ref table 'foo) 1)
+                  (= (hashq-ref table 'bar) 2))))
+
+  ;; eqv? hash table
+  (pass-if (let ((table (alist->hashv-table '((1 . 1)
+                                              (2 . 2)
+                                              (1 . 3)))))
+             (and (= (hashv-ref table 1) 1)
+                  (= (hashv-ref table 2) 2))))
+
+  ;; custom hash table
+  (pass-if (let ((table (alist->hashx-table hash assoc '((foo . 1)
+                                                         (bar . 2)
+                                                         (foo . 3)))))
+             (and (= (hashx-ref hash assoc table 'foo) 1)
+                  (= (hashx-ref hash assoc table 'bar) 2)))))
+
+;;;
 ;;; usual set and reference
 ;;;
 
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-10-21 17:00   ` Mark H Weaver
  2013-10-22  3:03     ` David Thompson
@ 2013-10-26 11:41     ` David Thompson
  1 sibling, 0 replies; 23+ messages in thread
From: David Thompson @ 2013-10-26 11:41 UTC (permalink / raw)
  To: Mark H Weaver; +Cc: guile-devel

[-- Attachment #1: Type: text/plain, Size: 189 bytes --]

Here is an updated patch with the following changes:
* Fix curly braces to follow GNU coding conventions
* Use 'scm_hash_create_handle_x' and friends to reduce hash table lookups.

- Dave


[-- Attachment #2: 0001-Add-procedures-to-convert-alists-into-hash-tables.patch --]
[-- Type: text/x-patch, Size: 7787 bytes --]

From 08bacd034d3e8d606464dc162c82509f0946c6dd Mon Sep 17 00:00:00 2001
From: David Thompson <dthompson2@worcester.edu>
Date: Sat, 19 Oct 2013 22:43:37 -0400
Subject: [PATCH] Add procedures to convert alists into hash tables.

* libguile/hashtab.h (scm_alist_to_hash_table, scm_alist_to_hashq_table,
  scm_alist_to_hashv_table, scm_alist_to_hashx_table): New prototypes.

* libguile/hashtab.c (scm_alist_to_hash_table, scm_alist_to_hashq_table,
  scm_alist_to_hashv_table, scm_alist_to_hashx_table): New procedures.
  (SCM_ALIST_TO_HASH_TABLE): New macro.

* test-suite/tests/hash.test ("alist->hash-table"): Add tests.

* doc/ref/api-compound.texi (Hash Table Reference): Add docs.
---
 doc/ref/api-compound.texi  | 24 ++++++++++++++++
 libguile/hashtab.c         | 70 ++++++++++++++++++++++++++++++++++++++++++++++
 libguile/hashtab.h         |  5 ++++
 test-suite/tests/hash.test | 35 +++++++++++++++++++++++
 4 files changed, 134 insertions(+)

diff --git a/doc/ref/api-compound.texi b/doc/ref/api-compound.texi
index 94e0145..e13c9c4 100644
--- a/doc/ref/api-compound.texi
+++ b/doc/ref/api-compound.texi
@@ -3829,6 +3829,30 @@ then it can use @var{size} to avoid rehashing when initial entries are
 added.
 @end deffn
 
+@deffn {Scheme Procedure} alist->hash-table alist
+@deffnx {Scheme Procedure} alist->hashq-table alist
+@deffnx {Scheme Procedure} alist->hashv-table alist
+@deffnx {Scheme Procedure} alist->hashx-table hash assoc alist
+@deffnx {C Function} scm_alist_to_hash_table (alist)
+@deffnx {C Function} scm_alist_to_hashq_table (alist)
+@deffnx {C Function} scm_alist_to_hashv_table (alist)
+@deffnx {C Function} scm_alist_to_hashx_table (hash, assoc, alist)
+Convert @var{alist} into a hash table. When keys are repeated in
+@var{alist}, the leftmost association takes precedence.
+
+@example
+(alist->hash-table '((foo . 1) (bar . 2)))
+@end example
+
+When converting to an extended hash table, custom @var{hash} and
+@var{assoc} procedures must be provided.
+
+@example
+(alist->hash-table hash assoc '((foo . 1) (bar . 2)))
+@end example
+
+@end deffn
+
 @deffn {Scheme Procedure} hash-table? obj
 @deffnx {C Function} scm_hash_table_p (obj)
 Return @code{#t} if @var{obj} is a abstract hash table object.
diff --git a/libguile/hashtab.c b/libguile/hashtab.c
index 88cb199..a79f70f 100644
--- a/libguile/hashtab.c
+++ b/libguile/hashtab.c
@@ -423,6 +423,76 @@ SCM_DEFINE (scm_make_hash_table, "make-hash-table", 0, 1, 0,
 }
 #undef FUNC_NAME
 
+#define SCM_ALIST_TO_HASH_TABLE(alist, hash_create_handle_fn)           \
+  SCM hash_table;                                                       \
+  SCM_VALIDATE_LIST (1, alist);                                         \
+  hash_table = make_hash_table (0, scm_ilength (alist), FUNC_NAME);     \
+  while (!scm_is_null (alist))                                          \
+    {                                                                   \
+      SCM pair = SCM_CAR (alist);                                       \
+      SCM key = scm_car (pair);                                         \
+      SCM value = scm_cdr (pair);                                       \
+      SCM handle = hash_create_handle_fn (hash_table, key,              \
+                                          SCM_UNDEFINED);               \
+      if (SCM_UNBNDP (SCM_CDR (handle)))                                \
+        scm_set_cdr_x (handle, value);                                  \
+      alist = SCM_CDR (alist);                                          \
+    }                                                                   \
+  return hash_table;
+
+SCM_DEFINE (scm_alist_to_hash_table, "alist->hash-table", 1, 0, 0,
+            (SCM alist),
+            "Convert @var{alist} into a hash table.")
+#define FUNC_NAME s_scm_alist_to_hash_table
+{
+  SCM_ALIST_TO_HASH_TABLE (alist, scm_hash_create_handle_x);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_alist_to_hashq_table, "alist->hashq-table", 1, 0, 0,
+            (SCM alist),
+            "Convert @var{alist} into a hash table.")
+#define FUNC_NAME s_scm_alist_to_hashq_table
+{
+  SCM_ALIST_TO_HASH_TABLE (alist, scm_hashq_create_handle_x);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_alist_to_hashv_table, "alist->hashv-table", 1, 0, 0,
+            (SCM alist),
+            "Convert @var{alist} into a hash table.")
+#define FUNC_NAME s_scm_alist_to_hashv_table
+{
+  SCM_ALIST_TO_HASH_TABLE (alist, scm_hashv_create_handle_x);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_alist_to_hashx_table, "alist->hashx-table", 3, 0, 0,
+            (SCM hash, SCM assoc, SCM alist),
+            "Convert @var{alist} into a hash table with custom @var{hash} and"
+            "@var{assoc} procedures.")
+#define FUNC_NAME s_scm_alist_to_hashx_table
+{
+  SCM hash_table;
+  SCM_VALIDATE_LIST (3, alist);
+  hash_table = make_hash_table (0, scm_ilength (alist), FUNC_NAME);
+
+  while (!scm_is_null (alist))
+    {
+      SCM pair = SCM_CAR (alist);
+      SCM key = scm_car (pair);
+      SCM value = scm_cdr (pair);
+      SCM handle = scm_hashx_create_handle_x (hash, assoc, hash_table,
+                                              key, SCM_UNDEFINED);
+      if (SCM_UNBNDP (SCM_CDR (handle)))
+        scm_set_cdr_x (handle, value);
+      alist = SCM_CDR (alist);
+    }
+
+  return hash_table;
+}
+#undef FUNC_NAME
+
 /* The before-gc C hook only runs if GC_set_start_callback is available,
    so if not, fall back on a finalizer-based implementation.  */
 static int
diff --git a/libguile/hashtab.h b/libguile/hashtab.h
index dcebcb8..270efe9 100644
--- a/libguile/hashtab.h
+++ b/libguile/hashtab.h
@@ -101,6 +101,11 @@ SCM_API SCM scm_make_weak_key_hash_table (SCM k);
 SCM_API SCM scm_make_weak_value_hash_table (SCM k);
 SCM_API SCM scm_make_doubly_weak_hash_table (SCM k);
 
+SCM_API SCM scm_alist_to_hash_table (SCM alist);
+SCM_API SCM scm_alist_to_hashq_table (SCM alist);
+SCM_API SCM scm_alist_to_hashv_table (SCM alist);
+SCM_API SCM scm_alist_to_hashx_table (SCM hash, SCM assoc, SCM alist);
+
 SCM_API SCM scm_hash_table_p (SCM h);
 SCM_API SCM scm_weak_key_hash_table_p (SCM h);
 SCM_API SCM scm_weak_value_hash_table_p (SCM h);
diff --git a/test-suite/tests/hash.test b/test-suite/tests/hash.test
index 3bd4004..820e522 100644
--- a/test-suite/tests/hash.test
+++ b/test-suite/tests/hash.test
@@ -81,6 +81,41 @@
                               (write (make-hash-table 100)))))))
 
 ;;;
+;;; alist->hash-table
+;;;
+
+(with-test-prefix
+  "alist->hash-table"
+
+  ;; equal? hash table
+  (pass-if (let ((table (alist->hash-table '(("foo" . 1)
+                                             ("bar" . 2)
+                                             ("foo" . 3)))))
+             (and (= (hash-ref table "foo") 1)
+                  (= (hash-ref table "bar") 2))))
+
+  ;; eq? hash table
+  (pass-if (let ((table (alist->hashq-table '((foo . 1)
+                                              (bar . 2)
+                                              (foo . 3)))))
+             (and (= (hashq-ref table 'foo) 1)
+                  (= (hashq-ref table 'bar) 2))))
+
+  ;; eqv? hash table
+  (pass-if (let ((table (alist->hashv-table '((1 . 1)
+                                              (2 . 2)
+                                              (1 . 3)))))
+             (and (= (hashv-ref table 1) 1)
+                  (= (hashv-ref table 2) 2))))
+
+  ;; custom hash table
+  (pass-if (let ((table (alist->hashx-table hash assoc '((foo . 1)
+                                                         (bar . 2)
+                                                         (foo . 3)))))
+             (and (= (hashx-ref hash assoc table 'foo) 1)
+                  (= (hashx-ref hash assoc table 'bar) 2)))))
+
+;;;
 ;;; usual set and reference
 ;;;
 
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-10-22  3:03     ` David Thompson
@ 2013-10-28 12:17       ` Chris K. Jester-Young
  2013-10-28 23:51         ` David Thompson
  0 siblings, 1 reply; 23+ messages in thread
From: Chris K. Jester-Young @ 2013-10-28 12:17 UTC (permalink / raw)
  To: guile-devel

On Mon, Oct 21, 2013 at 11:03:41PM -0400, David Thompson wrote:
> Thank you for taking the time to give some really useful feedback,
> Mark Weaver. I appreciate it.

He always writes really detailed reviews, which I highly appreciate. :-)

On which note, I have an additional nitpick:

> * libguile/hashtab.h (scm_alist_to_hash_table, scm_alist_to_hashq_table,
>   scm_alist_to_hashv_table, scm_alist_to_hashx_table): New prototypes.
> 
> * libguile/hashtab.c (scm_alist_to_hash_table, scm_alist_to_hashq_table,
>   scm_alist_to_hashv_table, scm_alist_to_hashx_table): New procedures.
>   (SCM_ALIST_TO_HASH_TABLE): New macro.

In the GNU ChangeLog format, when you have a list of functions that
exceed one line, you should close parens at the end of each line and
reopen on the next. Thus:

* libguile/hahstab.c (scm_alist_to_hash_table, scm_alist_to_hashq_table)
  (scm_alist_to_hashv_table, scm_alist_to_hashx_table): New procedures.

> Good to know. Still trying to get used to this commit format.

If you're talking about the commit message format, we largely follow the
GNU ChangeLog format, which is described here:
http://www.gnu.org/prep/standards/html_node/Style-of-Change-Logs.html

Cheers,
Chris.



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-10-28 12:17       ` Chris K. Jester-Young
@ 2013-10-28 23:51         ` David Thompson
  0 siblings, 0 replies; 23+ messages in thread
From: David Thompson @ 2013-10-28 23:51 UTC (permalink / raw)
  To: guile-devel

[-- Attachment #1: Type: text/plain, Size: 1462 bytes --]

On 10/28/2013 08:17 AM, Chris K. Jester-Young wrote:
> On Mon, Oct 21, 2013 at 11:03:41PM -0400, David Thompson wrote:
>> Thank you for taking the time to give some really useful feedback,
>> Mark Weaver. I appreciate it.
> 
> He always writes really detailed reviews, which I highly appreciate. :-)
> 
> On which note, I have an additional nitpick:
> 
>> * libguile/hashtab.h (scm_alist_to_hash_table, scm_alist_to_hashq_table,
>>   scm_alist_to_hashv_table, scm_alist_to_hashx_table): New prototypes.
>>
>> * libguile/hashtab.c (scm_alist_to_hash_table, scm_alist_to_hashq_table,
>>   scm_alist_to_hashv_table, scm_alist_to_hashx_table): New procedures.
>>   (SCM_ALIST_TO_HASH_TABLE): New macro.
> 
> In the GNU ChangeLog format, when you have a list of functions that
> exceed one line, you should close parens at the end of each line and
> reopen on the next. Thus:
> 
> * libguile/hahstab.c (scm_alist_to_hash_table, scm_alist_to_hashq_table)
>   (scm_alist_to_hashv_table, scm_alist_to_hashx_table): New procedures.
> 
>> Good to know. Still trying to get used to this commit format.
> 
> If you're talking about the commit message format, we largely follow the
> GNU ChangeLog format, which is described here:
> http://www.gnu.org/prep/standards/html_node/Style-of-Change-Logs.html
> 
> Cheers,
> Chris.
> 

Thank you, Chris. I'll try my best to follow the GNU ChangeLog format in
the future.

Attached is a patch with an amended commit message.

- Dave

[-- Attachment #2: 0001-Add-procedures-to-convert-alists-into-hash-tables.patch --]
[-- Type: text/x-patch, Size: 7789 bytes --]

From f3cd6ee7fa1b87005ac0c255ec7ab1331abbc88d Mon Sep 17 00:00:00 2001
From: David Thompson <dthompson2@worcester.edu>
Date: Sat, 19 Oct 2013 22:43:37 -0400
Subject: [PATCH] Add procedures to convert alists into hash tables.

* libguile/hashtab.h (scm_alist_to_hash_table, scm_alist_to_hashq_table)
  (scm_alist_to_hashv_table, scm_alist_to_hashx_table): New prototypes.

* libguile/hashtab.c (scm_alist_to_hash_table, scm_alist_to_hashq_table)
  (scm_alist_to_hashv_table, scm_alist_to_hashx_table): New procedures.
  (SCM_ALIST_TO_HASH_TABLE): New macro.

* test-suite/tests/hash.test ("alist->hash-table"): Add tests.

* doc/ref/api-compound.texi (Hash Table Reference): Add docs.
---
 doc/ref/api-compound.texi  | 24 ++++++++++++++++
 libguile/hashtab.c         | 70 ++++++++++++++++++++++++++++++++++++++++++++++
 libguile/hashtab.h         |  5 ++++
 test-suite/tests/hash.test | 35 +++++++++++++++++++++++
 4 files changed, 134 insertions(+)

diff --git a/doc/ref/api-compound.texi b/doc/ref/api-compound.texi
index 94e0145..e13c9c4 100644
--- a/doc/ref/api-compound.texi
+++ b/doc/ref/api-compound.texi
@@ -3829,6 +3829,30 @@ then it can use @var{size} to avoid rehashing when initial entries are
 added.
 @end deffn
 
+@deffn {Scheme Procedure} alist->hash-table alist
+@deffnx {Scheme Procedure} alist->hashq-table alist
+@deffnx {Scheme Procedure} alist->hashv-table alist
+@deffnx {Scheme Procedure} alist->hashx-table hash assoc alist
+@deffnx {C Function} scm_alist_to_hash_table (alist)
+@deffnx {C Function} scm_alist_to_hashq_table (alist)
+@deffnx {C Function} scm_alist_to_hashv_table (alist)
+@deffnx {C Function} scm_alist_to_hashx_table (hash, assoc, alist)
+Convert @var{alist} into a hash table. When keys are repeated in
+@var{alist}, the leftmost association takes precedence.
+
+@example
+(alist->hash-table '((foo . 1) (bar . 2)))
+@end example
+
+When converting to an extended hash table, custom @var{hash} and
+@var{assoc} procedures must be provided.
+
+@example
+(alist->hash-table hash assoc '((foo . 1) (bar . 2)))
+@end example
+
+@end deffn
+
 @deffn {Scheme Procedure} hash-table? obj
 @deffnx {C Function} scm_hash_table_p (obj)
 Return @code{#t} if @var{obj} is a abstract hash table object.
diff --git a/libguile/hashtab.c b/libguile/hashtab.c
index 88cb199..a79f70f 100644
--- a/libguile/hashtab.c
+++ b/libguile/hashtab.c
@@ -423,6 +423,76 @@ SCM_DEFINE (scm_make_hash_table, "make-hash-table", 0, 1, 0,
 }
 #undef FUNC_NAME
 
+#define SCM_ALIST_TO_HASH_TABLE(alist, hash_create_handle_fn)           \
+  SCM hash_table;                                                       \
+  SCM_VALIDATE_LIST (1, alist);                                         \
+  hash_table = make_hash_table (0, scm_ilength (alist), FUNC_NAME);     \
+  while (!scm_is_null (alist))                                          \
+    {                                                                   \
+      SCM pair = SCM_CAR (alist);                                       \
+      SCM key = scm_car (pair);                                         \
+      SCM value = scm_cdr (pair);                                       \
+      SCM handle = hash_create_handle_fn (hash_table, key,              \
+                                          SCM_UNDEFINED);               \
+      if (SCM_UNBNDP (SCM_CDR (handle)))                                \
+        scm_set_cdr_x (handle, value);                                  \
+      alist = SCM_CDR (alist);                                          \
+    }                                                                   \
+  return hash_table;
+
+SCM_DEFINE (scm_alist_to_hash_table, "alist->hash-table", 1, 0, 0,
+            (SCM alist),
+            "Convert @var{alist} into a hash table.")
+#define FUNC_NAME s_scm_alist_to_hash_table
+{
+  SCM_ALIST_TO_HASH_TABLE (alist, scm_hash_create_handle_x);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_alist_to_hashq_table, "alist->hashq-table", 1, 0, 0,
+            (SCM alist),
+            "Convert @var{alist} into a hash table.")
+#define FUNC_NAME s_scm_alist_to_hashq_table
+{
+  SCM_ALIST_TO_HASH_TABLE (alist, scm_hashq_create_handle_x);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_alist_to_hashv_table, "alist->hashv-table", 1, 0, 0,
+            (SCM alist),
+            "Convert @var{alist} into a hash table.")
+#define FUNC_NAME s_scm_alist_to_hashv_table
+{
+  SCM_ALIST_TO_HASH_TABLE (alist, scm_hashv_create_handle_x);
+}
+#undef FUNC_NAME
+
+SCM_DEFINE (scm_alist_to_hashx_table, "alist->hashx-table", 3, 0, 0,
+            (SCM hash, SCM assoc, SCM alist),
+            "Convert @var{alist} into a hash table with custom @var{hash} and"
+            "@var{assoc} procedures.")
+#define FUNC_NAME s_scm_alist_to_hashx_table
+{
+  SCM hash_table;
+  SCM_VALIDATE_LIST (3, alist);
+  hash_table = make_hash_table (0, scm_ilength (alist), FUNC_NAME);
+
+  while (!scm_is_null (alist))
+    {
+      SCM pair = SCM_CAR (alist);
+      SCM key = scm_car (pair);
+      SCM value = scm_cdr (pair);
+      SCM handle = scm_hashx_create_handle_x (hash, assoc, hash_table,
+                                              key, SCM_UNDEFINED);
+      if (SCM_UNBNDP (SCM_CDR (handle)))
+        scm_set_cdr_x (handle, value);
+      alist = SCM_CDR (alist);
+    }
+
+  return hash_table;
+}
+#undef FUNC_NAME
+
 /* The before-gc C hook only runs if GC_set_start_callback is available,
    so if not, fall back on a finalizer-based implementation.  */
 static int
diff --git a/libguile/hashtab.h b/libguile/hashtab.h
index dcebcb8..270efe9 100644
--- a/libguile/hashtab.h
+++ b/libguile/hashtab.h
@@ -101,6 +101,11 @@ SCM_API SCM scm_make_weak_key_hash_table (SCM k);
 SCM_API SCM scm_make_weak_value_hash_table (SCM k);
 SCM_API SCM scm_make_doubly_weak_hash_table (SCM k);
 
+SCM_API SCM scm_alist_to_hash_table (SCM alist);
+SCM_API SCM scm_alist_to_hashq_table (SCM alist);
+SCM_API SCM scm_alist_to_hashv_table (SCM alist);
+SCM_API SCM scm_alist_to_hashx_table (SCM hash, SCM assoc, SCM alist);
+
 SCM_API SCM scm_hash_table_p (SCM h);
 SCM_API SCM scm_weak_key_hash_table_p (SCM h);
 SCM_API SCM scm_weak_value_hash_table_p (SCM h);
diff --git a/test-suite/tests/hash.test b/test-suite/tests/hash.test
index 3bd4004..820e522 100644
--- a/test-suite/tests/hash.test
+++ b/test-suite/tests/hash.test
@@ -81,6 +81,41 @@
                               (write (make-hash-table 100)))))))
 
 ;;;
+;;; alist->hash-table
+;;;
+
+(with-test-prefix
+  "alist->hash-table"
+
+  ;; equal? hash table
+  (pass-if (let ((table (alist->hash-table '(("foo" . 1)
+                                             ("bar" . 2)
+                                             ("foo" . 3)))))
+             (and (= (hash-ref table "foo") 1)
+                  (= (hash-ref table "bar") 2))))
+
+  ;; eq? hash table
+  (pass-if (let ((table (alist->hashq-table '((foo . 1)
+                                              (bar . 2)
+                                              (foo . 3)))))
+             (and (= (hashq-ref table 'foo) 1)
+                  (= (hashq-ref table 'bar) 2))))
+
+  ;; eqv? hash table
+  (pass-if (let ((table (alist->hashv-table '((1 . 1)
+                                              (2 . 2)
+                                              (1 . 3)))))
+             (and (= (hashv-ref table 1) 1)
+                  (= (hashv-ref table 2) 2))))
+
+  ;; custom hash table
+  (pass-if (let ((table (alist->hashx-table hash assoc '((foo . 1)
+                                                         (bar . 2)
+                                                         (foo . 3)))))
+             (and (= (hashx-ref hash assoc table 'foo) 1)
+                  (= (hashx-ref hash assoc table 'bar) 2)))))
+
+;;;
 ;;; usual set and reference
 ;;;
 
-- 
1.8.4.rc3


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-10-20 14:14 [PATCH] Add procedures to convert alists into hash tables David Thompson
  2013-10-20 14:28 ` David Thompson
@ 2013-10-29 12:38 ` Ludovic Courtès
  2013-10-30 20:19   ` Thompson, David
  1 sibling, 1 reply; 23+ messages in thread
From: Ludovic Courtès @ 2013-10-29 12:38 UTC (permalink / raw)
  To: guile-devel

Hi!

David Thompson <dthompson2@worcester.edu> skribis:

> When looking through the different hash table implementations
> available (Guile, SRFI-69, and RNRS) I found a useful SRFI-69
> procedure that had no equivalent in Guile's native hash table API:
> alist->hash-table.

I think it would make sense to implement them in Scheme, say in
ice-9/hash-table.scm, which could be either a separate module or a file
included from boot-9.scm.

WDYT?

Ludo’.




^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-10-29 12:38 ` Ludovic Courtès
@ 2013-10-30 20:19   ` Thompson, David
  2013-11-03 12:43     ` Thien-Thi Nguyen
  2013-11-05 19:57     ` Mark H Weaver
  0 siblings, 2 replies; 23+ messages in thread
From: Thompson, David @ 2013-10-30 20:19 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: guile-devel

On Tue, Oct 29, 2013 at 8:38 AM, Ludovic Courtès <ludo@gnu.org> wrote:
> I think it would make sense to implement them in Scheme, say in
> ice-9/hash-table.scm, which could be either a separate module or a file
> included from boot-9.scm.
>
> WDYT?

Does anyone else feel that this is a better approach?

My patch has already gone through a few revisions, but I suppose I can
rewrite it again.

- Dave



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-10-30 20:19   ` Thompson, David
@ 2013-11-03 12:43     ` Thien-Thi Nguyen
  2013-11-05 19:57     ` Mark H Weaver
  1 sibling, 0 replies; 23+ messages in thread
From: Thien-Thi Nguyen @ 2013-11-03 12:43 UTC (permalink / raw)
  To: Thompson, David; +Cc: Ludovic Courtès, guile-devel

[-- Attachment #1: Type: text/plain, Size: 494 bytes --]

() "Thompson, David" <dthompson2@worcester.edu>
() Wed, 30 Oct 2013 16:19:16 -0400

   Does anyone else feel that this is a better approach?

I concur w/ ludo -- better in Scheme -- and would go even
further and urge adding to the guile-lib project, instead.

-- 
Thien-Thi Nguyen
   GPG key: 4C807502
   (if you're human and you know it)
      read my lisp: (responsep (questions 'technical)
                               (not (via 'mailing-list)))
                     => nil

[-- Attachment #2: Type: application/pgp-signature, Size: 197 bytes --]

^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-10-30 20:19   ` Thompson, David
  2013-11-03 12:43     ` Thien-Thi Nguyen
@ 2013-11-05 19:57     ` Mark H Weaver
  2013-11-06 12:54       ` Ludovic Courtès
  1 sibling, 1 reply; 23+ messages in thread
From: Mark H Weaver @ 2013-11-05 19:57 UTC (permalink / raw)
  To: Thompson, David; +Cc: Ludovic Courtès, guile-devel

"Thompson, David" <dthompson2@worcester.edu> writes:

> On Tue, Oct 29, 2013 at 8:38 AM, Ludovic Courtès <ludo@gnu.org> wrote:
>> I think it would make sense to implement them in Scheme, say in
>> ice-9/hash-table.scm, which could be either a separate module or a file
>> included from boot-9.scm.
>>
>> WDYT?
>
> Does anyone else feel that this is a better approach?

FWIW, I think Ludovic is right.  There's no compelling reason to write
these procedures in C, and it would be good to reduce the amount of C
code for several reasons.  However, unlike ttn, I think it would be good
to have these procedures in core Guile.

      Mark



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-11-05 19:57     ` Mark H Weaver
@ 2013-11-06 12:54       ` Ludovic Courtès
  2013-11-06 13:14         ` Thompson, David
  2013-11-18  1:50         ` David Thompson
  0 siblings, 2 replies; 23+ messages in thread
From: Ludovic Courtès @ 2013-11-06 12:54 UTC (permalink / raw)
  To: Mark H Weaver; +Cc: guile-devel

Mark H Weaver <mhw@netris.org> skribis:

> "Thompson, David" <dthompson2@worcester.edu> writes:
>
>> On Tue, Oct 29, 2013 at 8:38 AM, Ludovic Courtès <ludo@gnu.org> wrote:
>>> I think it would make sense to implement them in Scheme, say in
>>> ice-9/hash-table.scm, which could be either a separate module or a file
>>> included from boot-9.scm.
>>>
>>> WDYT?
>>
>> Does anyone else feel that this is a better approach?
>
> FWIW, I think Ludovic is right.  There's no compelling reason to write
> these procedures in C, and it would be good to reduce the amount of C
> code for several reasons.  However, unlike ttn, I think it would be good
> to have these procedures in core Guile.

Agreed.

David: would you be willing to do that?  Apologies for my late comment,
and for the extra work involved.  Your contributions are appreciated!

Thanks,
Ludo’.



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-11-06 12:54       ` Ludovic Courtès
@ 2013-11-06 13:14         ` Thompson, David
  2013-11-18  1:50         ` David Thompson
  1 sibling, 0 replies; 23+ messages in thread
From: Thompson, David @ 2013-11-06 13:14 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: Mark H Weaver, guile-devel

On Wed, Nov 6, 2013 at 7:54 AM, Ludovic Courtès <ludo@gnu.org> wrote:
> David: would you be willing to do that?  Apologies for my late comment,
> and for the extra work involved.  Your contributions are appreciated!

Yes, I will do that. I agree that it would be for the best.

Thanks,
- Dave



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-11-06 12:54       ` Ludovic Courtès
  2013-11-06 13:14         ` Thompson, David
@ 2013-11-18  1:50         ` David Thompson
  2013-11-18  2:42           ` David Thompson
  1 sibling, 1 reply; 23+ messages in thread
From: David Thompson @ 2013-11-18  1:50 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: Mark H Weaver, guile-devel

[-- Attachment #1: Type: text/plain, Size: 1110 bytes --]

On 11/06/2013 07:54 AM, Ludovic Courtès wrote:
> Mark H Weaver <mhw@netris.org> skribis:
> 
>> "Thompson, David" <dthompson2@worcester.edu> writes:
>>
>>> On Tue, Oct 29, 2013 at 8:38 AM, Ludovic Courtès <ludo@gnu.org> wrote:
>>>> I think it would make sense to implement them in Scheme, say in
>>>> ice-9/hash-table.scm, which could be either a separate module or a file
>>>> included from boot-9.scm.
>>>>
>>>> WDYT?
>>>
>>> Does anyone else feel that this is a better approach?
>>
>> FWIW, I think Ludovic is right.  There's no compelling reason to write
>> these procedures in C, and it would be good to reduce the amount of C
>> code for several reasons.  However, unlike ttn, I think it would be good
>> to have these procedures in core Guile.
> 
> Agreed.
> 
> David: would you be willing to do that?  Apologies for my late comment,
> and for the extra work involved.  Your contributions are appreciated!
> 
> Thanks,
> Ludo’.
> 

Finally got around to updating this patch. I opted for adding a
standalone module named (ice-9 hash-table) rather than including it from
boot-9.

How did I do?

- Dave

[-- Attachment #2: 0001-Add-procedures-to-convert-alists-into-hash-tables.patch --]
[-- Type: text/x-patch, Size: 5605 bytes --]

From 30b122a2638689e919f8b6722905ed5fa51e2138 Mon Sep 17 00:00:00 2001
From: David Thompson <dthompson2@worcester.edu>
Date: Sat, 19 Oct 2013 22:43:37 -0400
Subject: [PATCH] Add procedures to convert alists into hash tables.

* module/ice-9/hash-table.scm: New module.

* test-suite/tests/hash.test ("alist conversion"): Add tests.

* doc/ref/api-compound.texi (Hash Table Reference): Add docs.
---
 doc/ref/api-compound.texi   | 21 +++++++++++++++++++++
 module/ice-9/hash-table.scm | 45 +++++++++++++++++++++++++++++++++++++++++++++
 test-suite/tests/hash.test  | 38 +++++++++++++++++++++++++++++++++++++-
 3 files changed, 103 insertions(+), 1 deletion(-)
 create mode 100644 module/ice-9/hash-table.scm

diff --git a/doc/ref/api-compound.texi b/doc/ref/api-compound.texi
index 94e0145..9e5e649 100644
--- a/doc/ref/api-compound.texi
+++ b/doc/ref/api-compound.texi
@@ -3829,6 +3829,27 @@ then it can use @var{size} to avoid rehashing when initial entries are
 added.
 @end deffn
 
+@deffn {Scheme Procedure} alist->hash-table alist
+@deffnx {Scheme Procedure} alist->hashq-table alist
+@deffnx {Scheme Procedure} alist->hashv-table alist
+@deffnx {Scheme Procedure} alist->hashx-table hash assoc alist
+Convert @var{alist} into a hash table. When keys are repeated in
+@var{alist}, the leftmost association takes precedence.
+
+@example
+(use-modules (ice-9 hash-table))
+(alist->hash-table '((foo . 1) (bar . 2)))
+@end example
+
+When converting to an extended hash table, custom @var{hash} and
+@var{assoc} procedures must be provided.
+
+@example
+(alist->hash-table hash assoc '((foo . 1) (bar . 2)))
+@end example
+
+@end deffn
+
 @deffn {Scheme Procedure} hash-table? obj
 @deffnx {C Function} scm_hash_table_p (obj)
 Return @code{#t} if @var{obj} is a abstract hash table object.
diff --git a/module/ice-9/hash-table.scm b/module/ice-9/hash-table.scm
new file mode 100644
index 0000000..6b0fa04
--- /dev/null
+++ b/module/ice-9/hash-table.scm
@@ -0,0 +1,45 @@
+;;;; hash-table.scm --- Additional hash table procedures
+;;;; Copyright (C) 2013 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 as published by the Free Software Foundation; either
+;;;; version 3 of the License, or (at your option) any later version.
+;;;;
+;;;; This library 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
+;;;; Lesser General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;;;;
+
+(define-module (ice-9 hash-table)
+  #:export (alist->hash-table
+            alist->hashq-table
+            alist->hashv-table
+            alist->hashx-table))
+
+(define-syntax-rule (define-alist-converter name hash-set-proc)
+  (define (name alist)
+    "Convert @var{alist} into a hash table."
+    (let ((table (make-hash-table)))
+      (for-each (lambda (pair)
+                  (hash-set-proc table (car pair) (cdr pair)))
+                (reverse alist))
+      table)))
+
+(define-alist-converter alist->hash-table hash-set!)
+(define-alist-converter alist->hashq-table hashq-set!)
+(define-alist-converter alist->hashv-table hashv-set!)
+
+(define (alist->hashx-table hash assoc alist)
+  "Convert @var{alist} into a hash table with custom @var{hash} and
+@var{assoc} procedures."
+  (let ((table (make-hash-table)))
+    (for-each (lambda (pair)
+                (hashx-set! hash assoc table (car pair) (cdr pair)))
+              (reverse alist))
+    table))
diff --git a/test-suite/tests/hash.test b/test-suite/tests/hash.test
index 3bd4004..ad247f5 100644
--- a/test-suite/tests/hash.test
+++ b/test-suite/tests/hash.test
@@ -18,7 +18,8 @@
 
 (define-module (test-suite test-numbers)
   #:use-module (test-suite lib)
-  #:use-module (ice-9 documentation))
+  #:use-module (ice-9 documentation)
+  #:use-module (ice-9 hash-table))
 
 ;;;
 ;;; hash
@@ -81,6 +82,41 @@
                               (write (make-hash-table 100)))))))
 
 ;;;
+;;; alist->hash-table
+;;;
+
+(with-test-prefix
+  "alist conversion"
+
+  (pass-if "alist->hash-table"
+    (let ((table (alist->hash-table '(("foo" . 1)
+                                      ("bar" . 2)
+                                      ("foo" . 3)))))
+      (and (= (hash-ref table "foo") 1)
+           (= (hash-ref table "bar") 2))))
+
+  (pass-if "alist->hashq-table"
+    (let ((table (alist->hashq-table '((foo . 1)
+                                       (bar . 2)
+                                       (foo . 3)))))
+      (and (= (hashq-ref table 'foo) 1)
+           (= (hashq-ref table 'bar) 2))))
+
+  (pass-if "alist->hashv-table"
+    (let ((table (alist->hashv-table '((1 . 1)
+                                       (2 . 2)
+                                       (1 . 3)))))
+      (and (= (hashv-ref table 1) 1)
+           (= (hashv-ref table 2) 2))))
+
+  (pass-if "alist->hashx-table"
+    (let ((table (alist->hashx-table hash assoc '((foo . 1)
+                                                  (bar . 2)
+                                                  (foo . 3)))))
+      (and (= (hashx-ref hash assoc table 'foo) 1)
+           (= (hashx-ref hash assoc table 'bar) 2)))))
+
+;;;
 ;;; usual set and reference
 ;;;
 
-- 
1.8.4.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-11-18  1:50         ` David Thompson
@ 2013-11-18  2:42           ` David Thompson
  2013-11-18  3:22             ` Mark H Weaver
  2013-11-18 20:32             ` Ludovic Courtès
  0 siblings, 2 replies; 23+ messages in thread
From: David Thompson @ 2013-11-18  2:42 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: Mark H Weaver, guile-devel

[-- Attachment #1: Type: text/plain, Size: 315 bytes --]

On 11/17/2013 08:50 PM, David Thompson wrote:
> Finally got around to updating this patch. I opted for adding a
> standalone module named (ice-9 hash-table) rather than including it from
> boot-9.
> 
> How did I do?
> 
> - Dave
> 

Forgot to add the new module file to Makefile.am.

Updated patch attached.

- Dave

[-- Attachment #2: 0001-Add-procedures-to-convert-alists-into-hash-tables.patch --]
[-- Type: text/x-patch, Size: 5972 bytes --]

From 03f604cc3dfffb816cfe66a355e36ede337749f1 Mon Sep 17 00:00:00 2001
From: David Thompson <dthompson2@worcester.edu>
Date: Sat, 19 Oct 2013 22:43:37 -0400
Subject: [PATCH] Add procedures to convert alists into hash tables.

* module/ice-9/hash-table.scm: New module.

* test-suite/tests/hash.test ("alist conversion"): Add tests.

* doc/ref/api-compound.texi (Hash Table Reference): Add docs.
---
 doc/ref/api-compound.texi   | 21 +++++++++++++++++++++
 module/Makefile.am          |  1 +
 module/ice-9/hash-table.scm | 45 +++++++++++++++++++++++++++++++++++++++++++++
 test-suite/tests/hash.test  | 38 +++++++++++++++++++++++++++++++++++++-
 4 files changed, 104 insertions(+), 1 deletion(-)
 create mode 100644 module/ice-9/hash-table.scm

diff --git a/doc/ref/api-compound.texi b/doc/ref/api-compound.texi
index 94e0145..9e5e649 100644
--- a/doc/ref/api-compound.texi
+++ b/doc/ref/api-compound.texi
@@ -3829,6 +3829,27 @@ then it can use @var{size} to avoid rehashing when initial entries are
 added.
 @end deffn
 
+@deffn {Scheme Procedure} alist->hash-table alist
+@deffnx {Scheme Procedure} alist->hashq-table alist
+@deffnx {Scheme Procedure} alist->hashv-table alist
+@deffnx {Scheme Procedure} alist->hashx-table hash assoc alist
+Convert @var{alist} into a hash table. When keys are repeated in
+@var{alist}, the leftmost association takes precedence.
+
+@example
+(use-modules (ice-9 hash-table))
+(alist->hash-table '((foo . 1) (bar . 2)))
+@end example
+
+When converting to an extended hash table, custom @var{hash} and
+@var{assoc} procedures must be provided.
+
+@example
+(alist->hash-table hash assoc '((foo . 1) (bar . 2)))
+@end example
+
+@end deffn
+
 @deffn {Scheme Procedure} hash-table? obj
 @deffnx {C Function} scm_hash_table_p (obj)
 Return @code{#t} if @var{obj} is a abstract hash table object.
diff --git a/module/Makefile.am b/module/Makefile.am
index e8dcd4a..8a7befd 100644
--- a/module/Makefile.am
+++ b/module/Makefile.am
@@ -207,6 +207,7 @@ ICE_9_SOURCES = \
   ice-9/format.scm \
   ice-9/futures.scm \
   ice-9/getopt-long.scm \
+  ice-9/hash-table.scm \
   ice-9/hcons.scm \
   ice-9/i18n.scm \
   ice-9/iconv.scm \
diff --git a/module/ice-9/hash-table.scm b/module/ice-9/hash-table.scm
new file mode 100644
index 0000000..6b0fa04
--- /dev/null
+++ b/module/ice-9/hash-table.scm
@@ -0,0 +1,45 @@
+;;;; hash-table.scm --- Additional hash table procedures
+;;;; Copyright (C) 2013 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 as published by the Free Software Foundation; either
+;;;; version 3 of the License, or (at your option) any later version.
+;;;;
+;;;; This library 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
+;;;; Lesser General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;;;;
+
+(define-module (ice-9 hash-table)
+  #:export (alist->hash-table
+            alist->hashq-table
+            alist->hashv-table
+            alist->hashx-table))
+
+(define-syntax-rule (define-alist-converter name hash-set-proc)
+  (define (name alist)
+    "Convert @var{alist} into a hash table."
+    (let ((table (make-hash-table)))
+      (for-each (lambda (pair)
+                  (hash-set-proc table (car pair) (cdr pair)))
+                (reverse alist))
+      table)))
+
+(define-alist-converter alist->hash-table hash-set!)
+(define-alist-converter alist->hashq-table hashq-set!)
+(define-alist-converter alist->hashv-table hashv-set!)
+
+(define (alist->hashx-table hash assoc alist)
+  "Convert @var{alist} into a hash table with custom @var{hash} and
+@var{assoc} procedures."
+  (let ((table (make-hash-table)))
+    (for-each (lambda (pair)
+                (hashx-set! hash assoc table (car pair) (cdr pair)))
+              (reverse alist))
+    table))
diff --git a/test-suite/tests/hash.test b/test-suite/tests/hash.test
index 3bd4004..ad247f5 100644
--- a/test-suite/tests/hash.test
+++ b/test-suite/tests/hash.test
@@ -18,7 +18,8 @@
 
 (define-module (test-suite test-numbers)
   #:use-module (test-suite lib)
-  #:use-module (ice-9 documentation))
+  #:use-module (ice-9 documentation)
+  #:use-module (ice-9 hash-table))
 
 ;;;
 ;;; hash
@@ -81,6 +82,41 @@
                               (write (make-hash-table 100)))))))
 
 ;;;
+;;; alist->hash-table
+;;;
+
+(with-test-prefix
+  "alist conversion"
+
+  (pass-if "alist->hash-table"
+    (let ((table (alist->hash-table '(("foo" . 1)
+                                      ("bar" . 2)
+                                      ("foo" . 3)))))
+      (and (= (hash-ref table "foo") 1)
+           (= (hash-ref table "bar") 2))))
+
+  (pass-if "alist->hashq-table"
+    (let ((table (alist->hashq-table '((foo . 1)
+                                       (bar . 2)
+                                       (foo . 3)))))
+      (and (= (hashq-ref table 'foo) 1)
+           (= (hashq-ref table 'bar) 2))))
+
+  (pass-if "alist->hashv-table"
+    (let ((table (alist->hashv-table '((1 . 1)
+                                       (2 . 2)
+                                       (1 . 3)))))
+      (and (= (hashv-ref table 1) 1)
+           (= (hashv-ref table 2) 2))))
+
+  (pass-if "alist->hashx-table"
+    (let ((table (alist->hashx-table hash assoc '((foo . 1)
+                                                  (bar . 2)
+                                                  (foo . 3)))))
+      (and (= (hashx-ref hash assoc table 'foo) 1)
+           (= (hashx-ref hash assoc table 'bar) 2)))))
+
+;;;
 ;;; usual set and reference
 ;;;
 
-- 
1.8.4.2


^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-11-18  2:42           ` David Thompson
@ 2013-11-18  3:22             ` Mark H Weaver
  2013-11-18 20:32             ` Ludovic Courtès
  1 sibling, 0 replies; 23+ messages in thread
From: Mark H Weaver @ 2013-11-18  3:22 UTC (permalink / raw)
  To: David Thompson; +Cc: Ludovic Courtès, guile-devel

Hi David,

David Thompson <dthompson2@worcester.edu> writes:

> +@deffn {Scheme Procedure} alist->hash-table alist
> +@deffnx {Scheme Procedure} alist->hashq-table alist
> +@deffnx {Scheme Procedure} alist->hashv-table alist
> +@deffnx {Scheme Procedure} alist->hashx-table hash assoc alist
> +Convert @var{alist} into a hash table. When keys are repeated in
> +@var{alist}, the leftmost association takes precedence.
> +
> +@example
> +(use-modules (ice-9 hash-table))
> +(alist->hash-table '((foo . 1) (bar . 2)))
> +@end example
> +
> +When converting to an extended hash table, custom @var{hash} and
> +@var{assoc} procedures must be provided.
> +
> +@example
> +(alist->hash-table hash assoc '((foo . 1) (bar . 2)))

This should be 'alist->hashx-table'.
Other than that, the patch looks good to me!

     Mark



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-11-18  2:42           ` David Thompson
  2013-11-18  3:22             ` Mark H Weaver
@ 2013-11-18 20:32             ` Ludovic Courtès
  2013-11-19  2:00               ` David Thompson
  2014-03-24 21:06               ` Andy Wingo
  1 sibling, 2 replies; 23+ messages in thread
From: Ludovic Courtès @ 2013-11-18 20:32 UTC (permalink / raw)
  To: David Thompson; +Cc: Mark H Weaver, guile-devel

David Thompson <dthompson2@worcester.edu> skribis:

> From 03f604cc3dfffb816cfe66a355e36ede337749f1 Mon Sep 17 00:00:00 2001
> From: David Thompson <dthompson2@worcester.edu>
> Date: Sat, 19 Oct 2013 22:43:37 -0400
> Subject: [PATCH] Add procedures to convert alists into hash tables.
>
> * module/ice-9/hash-table.scm: New module.
>
> * test-suite/tests/hash.test ("alist conversion"): Add tests.
>
> * doc/ref/api-compound.texi (Hash Table Reference): Add docs.

Agreed with Mark’s comment, but otherwise looks good to me.

> +(define-syntax-rule (define-alist-converter name hash-set-proc)
> +  (define (name alist)

[...]

> +(define (alist->hashx-table hash assoc alist)
> +  "Convert @var{alist} into a hash table with custom @var{hash} and
> +@var{assoc} procedures."

Currently Texinfo markup in docstrings is left uninterpreted so it
can/should be avoided (it may change in the future, but the future’s not
now ;-)).

Thanks!

Ludo’.



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-11-18 20:32             ` Ludovic Courtès
@ 2013-11-19  2:00               ` David Thompson
  2013-11-19  4:06                 ` Mark H Weaver
  2014-03-24 21:06               ` Andy Wingo
  1 sibling, 1 reply; 23+ messages in thread
From: David Thompson @ 2013-11-19  2:00 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: Mark H Weaver, guile-devel

[-- Attachment #1: Type: text/plain, Size: 1088 bytes --]

On 11/18/2013 03:32 PM, Ludovic Courtès wrote:
> David Thompson <dthompson2@worcester.edu> skribis:
> 
>> From 03f604cc3dfffb816cfe66a355e36ede337749f1 Mon Sep 17 00:00:00 2001
>> From: David Thompson <dthompson2@worcester.edu>
>> Date: Sat, 19 Oct 2013 22:43:37 -0400
>> Subject: [PATCH] Add procedures to convert alists into hash tables.
>>
>> * module/ice-9/hash-table.scm: New module.
>>
>> * test-suite/tests/hash.test ("alist conversion"): Add tests.
>>
>> * doc/ref/api-compound.texi (Hash Table Reference): Add docs.
> 
> Agreed with Mark’s comment, but otherwise looks good to me.
> 
>> +(define-syntax-rule (define-alist-converter name hash-set-proc)
>> +  (define (name alist)
> 
> [...]
> 
>> +(define (alist->hashx-table hash assoc alist)
>> +  "Convert @var{alist} into a hash table with custom @var{hash} and
>> +@var{assoc} procedures."
> 
> Currently Texinfo markup in docstrings is left uninterpreted so it
> can/should be avoided (it may change in the future, but the future’s not
> now ;-)).
> 
> Thanks!
> 
> Ludo’.
> 

Fixed texi docs and docstrings.

- Dave

[-- Attachment #2: 0001-Add-procedures-to-convert-alists-into-hash-tables.patch --]
[-- Type: text/x-patch, Size: 5943 bytes --]

From 37571c1a11d53cee176bf93ddd539f0dd91f3669 Mon Sep 17 00:00:00 2001
From: David Thompson <dthompson2@worcester.edu>
Date: Sat, 19 Oct 2013 22:43:37 -0400
Subject: [PATCH] Add procedures to convert alists into hash tables.

* module/ice-9/hash-table.scm: New module.

* test-suite/tests/hash.test ("alist conversion"): Add tests.

* doc/ref/api-compound.texi (Hash Table Reference): Add docs.

---
 doc/ref/api-compound.texi   | 21 +++++++++++++++++++++
 module/Makefile.am          |  1 +
 module/ice-9/hash-table.scm | 45 +++++++++++++++++++++++++++++++++++++++++++++
 test-suite/tests/hash.test  | 38 +++++++++++++++++++++++++++++++++++++-
 4 files changed, 104 insertions(+), 1 deletion(-)
 create mode 100644 module/ice-9/hash-table.scm

diff --git a/doc/ref/api-compound.texi b/doc/ref/api-compound.texi
index 94e0145..0b14c48 100644
--- a/doc/ref/api-compound.texi
+++ b/doc/ref/api-compound.texi
@@ -3829,6 +3829,27 @@ then it can use @var{size} to avoid rehashing when initial entries are
 added.
 @end deffn

+@deffn {Scheme Procedure} alist->hash-table alist
+@deffnx {Scheme Procedure} alist->hashq-table alist
+@deffnx {Scheme Procedure} alist->hashv-table alist
+@deffnx {Scheme Procedure} alist->hashx-table hash assoc alist
+Convert @var{alist} into a hash table. When keys are repeated in
+@var{alist}, the leftmost association takes precedence.
+
+@example
+(use-modules (ice-9 hash-table))
+(alist->hash-table '((foo . 1) (bar . 2)))
+@end example
+
+When converting to an extended hash table, custom @var{hash} and
+@var{assoc} procedures must be provided.
+
+@example
+(alist->hashx-table hash assoc '((foo . 1) (bar . 2)))
+@end example
+
+@end deffn
+
 @deffn {Scheme Procedure} hash-table? obj
 @deffnx {C Function} scm_hash_table_p (obj)
 Return @code{#t} if @var{obj} is a abstract hash table object.
diff --git a/module/Makefile.am b/module/Makefile.am
index e8dcd4a..8a7befd 100644
--- a/module/Makefile.am
+++ b/module/Makefile.am
@@ -207,6 +207,7 @@ ICE_9_SOURCES = \
   ice-9/format.scm \
   ice-9/futures.scm \
   ice-9/getopt-long.scm \
+  ice-9/hash-table.scm \
   ice-9/hcons.scm \
   ice-9/i18n.scm \
   ice-9/iconv.scm \
diff --git a/module/ice-9/hash-table.scm b/module/ice-9/hash-table.scm
new file mode 100644
index 0000000..ca9d2fd
--- /dev/null
+++ b/module/ice-9/hash-table.scm
@@ -0,0 +1,45 @@
+;;;; hash-table.scm --- Additional hash table procedures
+;;;; Copyright (C) 2013 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 as published by the Free Software Foundation; either
+;;;; version 3 of the License, or (at your option) any later version.
+;;;;
+;;;; This library 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
+;;;; Lesser General Public License for more details.
+;;;;
+;;;; You should have received a copy of the GNU Lesser General Public
+;;;; License along with this library; if not, write to the Free Software
+;;;; Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+;;;;
+
+(define-module (ice-9 hash-table)
+  #:export (alist->hash-table
+            alist->hashq-table
+            alist->hashv-table
+            alist->hashx-table))
+
+(define-syntax-rule (define-alist-converter name hash-set-proc)
+  (define (name alist)
+    "Convert ALIST into a hash table."
+    (let ((table (make-hash-table)))
+      (for-each (lambda (pair)
+                  (hash-set-proc table (car pair) (cdr pair)))
+                (reverse alist))
+      table)))
+
+(define-alist-converter alist->hash-table hash-set!)
+(define-alist-converter alist->hashq-table hashq-set!)
+(define-alist-converter alist->hashv-table hashv-set!)
+
+(define (alist->hashx-table hash assoc alist)
+  "Convert ALIST into a hash table with custom HASH and ASSOC
+procedures."
+  (let ((table (make-hash-table)))
+    (for-each (lambda (pair)
+                (hashx-set! hash assoc table (car pair) (cdr pair)))
+              (reverse alist))
+    table))
diff --git a/test-suite/tests/hash.test b/test-suite/tests/hash.test
index 3bd4004..ad247f5 100644
--- a/test-suite/tests/hash.test
+++ b/test-suite/tests/hash.test
@@ -18,7 +18,8 @@

 (define-module (test-suite test-numbers)
   #:use-module (test-suite lib)
-  #:use-module (ice-9 documentation))
+  #:use-module (ice-9 documentation)
+  #:use-module (ice-9 hash-table))

 ;;;
 ;;; hash
@@ -81,6 +82,41 @@
                               (write (make-hash-table 100)))))))

 ;;;
+;;; alist->hash-table
+;;;
+
+(with-test-prefix
+  "alist conversion"
+
+  (pass-if "alist->hash-table"
+    (let ((table (alist->hash-table '(("foo" . 1)
+                                      ("bar" . 2)
+                                      ("foo" . 3)))))
+      (and (= (hash-ref table "foo") 1)
+           (= (hash-ref table "bar") 2))))
+
+  (pass-if "alist->hashq-table"
+    (let ((table (alist->hashq-table '((foo . 1)
+                                       (bar . 2)
+                                       (foo . 3)))))
+      (and (= (hashq-ref table 'foo) 1)
+           (= (hashq-ref table 'bar) 2))))
+
+  (pass-if "alist->hashv-table"
+    (let ((table (alist->hashv-table '((1 . 1)
+                                       (2 . 2)
+                                       (1 . 3)))))
+      (and (= (hashv-ref table 1) 1)
+           (= (hashv-ref table 2) 2))))
+
+  (pass-if "alist->hashx-table"
+    (let ((table (alist->hashx-table hash assoc '((foo . 1)
+                                                  (bar . 2)
+                                                  (foo . 3)))))
+      (and (= (hashx-ref hash assoc table 'foo) 1)
+           (= (hashx-ref hash assoc table 'bar) 2)))))
+
+;;;
 ;;; usual set and reference
 ;;;

--
1.8.4.2

^ permalink raw reply related	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-11-19  2:00               ` David Thompson
@ 2013-11-19  4:06                 ` Mark H Weaver
  2013-11-19 13:14                   ` Thompson, David
  0 siblings, 1 reply; 23+ messages in thread
From: Mark H Weaver @ 2013-11-19  4:06 UTC (permalink / raw)
  To: David Thompson; +Cc: Ludovic Courtès, guile-devel

David Thompson <dthompson2@worcester.edu> writes:
> Fixed texi docs and docstrings.

Pushed to stable-2.0.  Many thanks! :)

     Mark



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-11-19  4:06                 ` Mark H Weaver
@ 2013-11-19 13:14                   ` Thompson, David
  0 siblings, 0 replies; 23+ messages in thread
From: Thompson, David @ 2013-11-19 13:14 UTC (permalink / raw)
  To: Mark H Weaver; +Cc: Ludovic Courtès, guile-devel

On Mon, Nov 18, 2013 at 11:06 PM, Mark H Weaver <mhw@netris.org> wrote:
> David Thompson <dthompson2@worcester.edu> writes:
>> Fixed texi docs and docstrings.
>
> Pushed to stable-2.0.  Many thanks! :)
>
>      Mark

Yay! Thanks for reviewing.



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2013-11-18 20:32             ` Ludovic Courtès
  2013-11-19  2:00               ` David Thompson
@ 2014-03-24 21:06               ` Andy Wingo
  2014-03-24 22:15                 ` Ludovic Courtès
  1 sibling, 1 reply; 23+ messages in thread
From: Andy Wingo @ 2014-03-24 21:06 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: Mark H Weaver, guile-devel

Another late comment :)

On Mon 18 Nov 2013 21:32, ludo@gnu.org (Ludovic Courtès) writes:

>> +(define (alist->hashx-table hash assoc alist)
>> +  "Convert @var{alist} into a hash table with custom @var{hash} and
>> +@var{assoc} procedures."
>
> Currently Texinfo markup in docstrings is left uninterpreted so it
> can/should be avoided (it may change in the future, but the future’s not
> now ;-)).

Actually the future has always been now, but just not everywhere :)

If you add this to your .guile:

  (use-modules (texinfo reflection))

then all docstrings will be parsed and rendered using Guile's texinfo
toolchain.  Also modules get nice help too; see e.g. (help (ice-9
popen)).  We should probably fix whatever small bugs are out there
regarding the output and just enable it by default.

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2014-03-24 21:06               ` Andy Wingo
@ 2014-03-24 22:15                 ` Ludovic Courtès
  2014-03-24 22:26                   ` Andy Wingo
  0 siblings, 1 reply; 23+ messages in thread
From: Ludovic Courtès @ 2014-03-24 22:15 UTC (permalink / raw)
  To: Andy Wingo; +Cc: Mark H Weaver, guile-devel

Andy Wingo <wingo@pobox.com> skribis:

> On Mon 18 Nov 2013 21:32, ludo@gnu.org (Ludovic Courtès) writes:
>
>>> +(define (alist->hashx-table hash assoc alist)
>>> +  "Convert @var{alist} into a hash table with custom @var{hash} and
>>> +@var{assoc} procedures."
>>
>> Currently Texinfo markup in docstrings is left uninterpreted so it
>> can/should be avoided (it may change in the future, but the future’s not
>> now ;-)).
>
> Actually the future has always been now, but just not everywhere :)
>
> If you add this to your .guile:
>
>   (use-modules (texinfo reflection))
>
> then all docstrings will be parsed and rendered using Guile's texinfo
> toolchain.

Yep, I discovered that in the meantime.  :-)

> Also modules get nice help too; see e.g. (help (ice-9 popen)).  We
> should probably fix whatever small bugs are out there regarding the
> output and just enable it by default.

Yes, agreed.  The output appears to be “good enough”, AFAICS.

What would be the right way to enable it?  Should (ice-9 session)
#:autoload (texinfo reflection), and do the ‘add-value-help-handler!’
itself?

Ludo’.



^ permalink raw reply	[flat|nested] 23+ messages in thread

* Re: [PATCH] Add procedures to convert alists into hash tables
  2014-03-24 22:15                 ` Ludovic Courtès
@ 2014-03-24 22:26                   ` Andy Wingo
  0 siblings, 0 replies; 23+ messages in thread
From: Andy Wingo @ 2014-03-24 22:26 UTC (permalink / raw)
  To: Ludovic Courtès; +Cc: Mark H Weaver, guile-devel

On Mon 24 Mar 2014 23:15, ludo@gnu.org (Ludovic Courtès) writes:

> What would be the right way to enable it?  Should (ice-9 session)
> #:autoload (texinfo reflection), and do the ‘add-value-help-handler!’
> itself?

That wouldn't work so well with autoloads AFAIU.  I would think you'd
have to inline the cases into (ice-9 session) to make autoloads work
correctly.  Dunno tho.

Andy
-- 
http://wingolog.org/



^ permalink raw reply	[flat|nested] 23+ messages in thread

end of thread, other threads:[~2014-03-24 22:26 UTC | newest]

Thread overview: 23+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2013-10-20 14:14 [PATCH] Add procedures to convert alists into hash tables David Thompson
2013-10-20 14:28 ` David Thompson
2013-10-21 17:00   ` Mark H Weaver
2013-10-22  3:03     ` David Thompson
2013-10-28 12:17       ` Chris K. Jester-Young
2013-10-28 23:51         ` David Thompson
2013-10-26 11:41     ` David Thompson
2013-10-29 12:38 ` Ludovic Courtès
2013-10-30 20:19   ` Thompson, David
2013-11-03 12:43     ` Thien-Thi Nguyen
2013-11-05 19:57     ` Mark H Weaver
2013-11-06 12:54       ` Ludovic Courtès
2013-11-06 13:14         ` Thompson, David
2013-11-18  1:50         ` David Thompson
2013-11-18  2:42           ` David Thompson
2013-11-18  3:22             ` Mark H Weaver
2013-11-18 20:32             ` Ludovic Courtès
2013-11-19  2:00               ` David Thompson
2013-11-19  4:06                 ` Mark H Weaver
2013-11-19 13:14                   ` Thompson, David
2014-03-24 21:06               ` Andy Wingo
2014-03-24 22:15                 ` Ludovic Courtès
2014-03-24 22:26                   ` Andy Wingo

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).