From 3f36d054f6290d277d105d7e40bd0402ecab8120 Mon Sep 17 00:00:00 2001 From: Eli Barzilay Date: Wed, 23 Jun 2010 16:10:14 -0400 Subject: [PATCH] Turn contracts on `enqueue!' and `dequeue!' into the usual error checks. On a simple benchmark of: (let ([N 100000] [M 20] [q (make-queue)]) (time (for ([i (in-range M)]) (for ([i (in-range (* i N))]) (enqueue! q i)) (unless (for/and ([i (in-range (* i N))]) (list i (dequeue! q))) (error "poof"))))) I get these timings: original version: cpu time: 24438 real time: 24439 gc time: 8164 single-links: cpu time: 17848 real time: 17849 gc time: 4859 this version: cpu time: 6519 real time: 6519 gc time: 3032 In addition, cleaned up the documentation a little, and mention the fact that it is not thread safe. --- collects/tests/unstable/queue.rkt | 8 ++- collects/unstable/queue.rkt | 11 ++-- collects/unstable/scribblings/queue.scrbl | 66 +++++++++++------------ 3 files changed, 43 insertions(+), 42 deletions(-) diff --git a/collects/tests/unstable/queue.rkt b/collects/tests/unstable/queue.rkt index 4219832fb6..a9727e80b5 100644 --- a/collects/tests/unstable/queue.rkt +++ b/collects/tests/unstable/queue.rkt @@ -36,18 +36,16 @@ (check-true (queue-empty? q))))) (test-suite "dequeue!" (test-case "make-queue" - (check-exn exn:fail:contract? (lambda () (dequeue! (make-queue))))) + (check-exn exn:fail? (lambda () (dequeue! (make-queue))))) (test-case "enqueue! once" (let* ([q (make-queue)]) (enqueue! q 1) (check-equal? (dequeue! q) 1) - (check-exn exn:fail:contract? - (lambda () (dequeue! q))))) + (check-exn exn:fail? (lambda () (dequeue! q))))) (test-case "enqueue! twice" (let* ([q (make-queue)]) (enqueue! q 1) (enqueue! q 2) (check-equal? (dequeue! q) 1) (check-equal? (dequeue! q) 2) - (check-exn exn:fail:contract? - (lambda () (dequeue! q)))))))) + (check-exn exn:fail? (lambda () (dequeue! q)))))))) diff --git a/collects/unstable/queue.rkt b/collects/unstable/queue.rkt index a7a3e6ea16..8121ee84b1 100644 --- a/collects/unstable/queue.rkt +++ b/collects/unstable/queue.rkt @@ -17,6 +17,7 @@ (define (nonempty-queue? v) (and (queue? v) (queue-head v) #t)) (define (enqueue! q v) + (unless (queue? q) (raise-type-error enqueue! "queue" 0 q)) (let ([new (link v #f)]) (if (queue-head q) (set-link-tail! (queue-tail q) new) @@ -24,7 +25,9 @@ (set-queue-tail! q new))) (define (dequeue! q) + (unless (queue? q) (raise-type-error dequeue! "queue" 0 q)) (let ([old (queue-head q)]) + (unless old (error 'dequeue! "empty queue")) (set-queue-head! q (link-tail old)) (link-value old))) @@ -38,11 +41,13 @@ (define nonempty-queue/c (flat-named-contract "nonempty-queue" nonempty-queue?)) +;; ELI: Are these needed? (vs just providing `queue?', `make-queue' and +;; `queue-empty?'.) (provide/contract [queue/c flat-contract?] [nonempty-queue/c flat-contract?] [queue? (-> any/c boolean?)] [make-queue (-> queue/c)] - [queue-empty? (-> queue/c boolean?)] - [enqueue! (-> queue/c any/c void?)] - [dequeue! (-> nonempty-queue/c any/c)]) + [queue-empty? (-> queue/c boolean?)]) + +(provide enqueue! dequeue!) diff --git a/collects/unstable/scribblings/queue.scrbl b/collects/unstable/scribblings/queue.scrbl index 180912a0fe..011a8442f3 100644 --- a/collects/unstable/scribblings/queue.scrbl +++ b/collects/unstable/scribblings/queue.scrbl @@ -1,5 +1,6 @@ #lang scribble/manual @(require scribble/eval "utils.rkt" (for-label racket unstable/queue)) +@(define qeval (eval/require 'unstable/queue)) @title{Imperative Queues} @@ -7,59 +8,56 @@ @unstable[@author+email["Carl Eastlund" "cce@racket-lang.org"]] -This module provides a mutable queue representation. +This module provides a simple mutable queue representation, +first-in/first-out only. Operations on queues mutate it in a +thread-unsafe way. @defproc[(make-queue) queue/c]{ -Produces an empty queue. + Produces an empty queue. } @defproc[(enqueue! [q queue/c] [v any/c]) void?]{ -Adds an element to the back of a queue. + Adds an element to the back of a queue. } @defproc[(dequeue! [q nonempty-queue/c]) any/c]{ -Removes an element from the front of a nonempty queue, and returns that element. + Removes an element from the front of a nonempty queue, and returns that + element. -@defexamples[ -#:eval (eval/require 'unstable/queue) -(define q (make-queue)) -(enqueue! q 1) -(dequeue! q) -(enqueue! q 2) -(enqueue! q 3) -(dequeue! q) -(dequeue! q) -] + @defexamples[#:eval qeval + (define q (make-queue)) + (enqueue! q 1) + (dequeue! q) + (enqueue! q 2) + (enqueue! q 3) + (dequeue! q) + (dequeue! q)] } @defproc[(queue-empty? [q queue/c]) boolean?]{ -Recognizes whether a queue is empty or not. + Recognizes whether a queue is empty or not. -@defexamples[ -#:eval (eval/require 'unstable/queue) -(define q (make-queue)) -(queue-empty? q) -(enqueue! q 1) -(queue-empty? q) -(dequeue! q) -(queue-empty? q) -] + @defexamples[#:eval qeval + (define q (make-queue)) + (queue-empty? q) + (enqueue! q 1) + (queue-empty? q) + (dequeue! q) + (queue-empty? q)] } @defproc[(queue? [v any/c]) boolean?]{ -This predicate recognizes queues. + This predicate recognizes queues. -@defexamples[ -#:eval (eval/require 'unstable/queue) -(queue? (make-queue)) -(queue? 'not-a-queue) -] + @defexamples[#:eval qeval + (queue? (make-queue)) + (queue? 'not-a-queue)] } @deftogether[( -@defthing[queue/c flat-contract?] -@defthing[nonempty-queue/c flat-contract?] + @defthing[queue/c flat-contract?] + @defthing[nonempty-queue/c flat-contract?] )]{ -These contracts recognize queues; the latter requires the queue to contain at -least one value. + These contracts recognize queues; the latter requires the queue to + contain at least one value. }