Module: streams-internals Synopsis: Definition of buffer class and methods for buffered streams Author: Toby Weinberg, Scott McKay, Marc Ferguson, Eliot Miranda Copyright: Original Code is Copyright (c) 1995-2004 Functional Objects, Inc. All rights reserved. License: Functional Objects Library Public License Version 1.0 Dual-license: GNU Lesser General Public License Warranty: Distributed WITHOUT WARRANTY OF ANY KIND /// Buffers // TODO: EVENTUALLY WANT // define constant = ; // define constant = ; // define constant $byte-representation-fill = 0; // BUT CURRENTLY TYPIST IS NOT UP TO IT define constant = ; define constant = ; define constant $byte-representation-fill = ' '; define sealed primary class () slot buffer-next :: = 0, init-keyword: buffer-next:; slot buffer-end :: = 0, init-keyword: buffer-end:; slot buffer-position :: = 0, init-keyword: buffer-position:; slot buffer-dirty? :: = #f, init-keyword: buffer-dirty?:; // Stuff for slot buffer-start :: = 0, init-keyword: buffer-start:; slot buffer-on-page-bits :: ; slot buffer-off-page-bits :: ; // Stuff for slot buffer-use-count :: = 0, init-keyword: use-count:; slot buffer-owning-stream :: false-or() = #f, init-keyword: stream-id:; // DA DATA repeated slot buffer-element :: , init-value: $byte-representation-fill, init-keyword: fill:, size-init-value: 0, size-init-keyword: size:, size-getter: size; end class; define sealed domain size (); define sealed domain make (singleton()); define sealed domain initialize (); define inline sealed method make (class :: subclass(), #rest all-keys, #key fill = $byte-representation-fill, #all-keys) => (buffer :: ) apply(next-method, class, fill: as(, fill), all-keys) end method; define inline sealed method buffer-size (buffer :: ) => (start :: ) buffer.size end method buffer-size; // // ELEMENT // define /* inline */ sealed method element (buffer :: , index :: , #key default = unsupplied()) => (result :: ) if (element-range-check(index, size(buffer))) element-no-bounds-check(buffer, index) else if (unsupplied?(default)) element-range-error(buffer, index) else default end if end if end method; // // buffer-element returns a // // // buffer-element returns a not an // define inline sealed method element-no-bounds-check (buffer :: , index :: , #key default) => (res :: ) as(, buffer-element(buffer, index)) end method; // // ELEMENT-SETTER // define /* inline */ sealed method element-setter (new-value :: , vector :: , index :: ) => (value) if (element-range-check(index, size(vector))) buffer-element(vector, index) := as(, new-value); else element-range-error(vector, index); end if end method; define /* inline */ sealed method element-setter (new-value :: , vector :: , index :: ) => (value) if (element-range-check(index, size(vector))) buffer-element(vector, index) := as(, new-value) else element-range-error(vector, index) end if end method; // // ELEMENT-NO-BOUNDS-CHECK-SETTER // define inline sealed method element-no-bounds-check-setter (new-value :: , buffer :: , index :: ) => (value) buffer-element(buffer, index) := as(, new-value); end method; define inline sealed method element-no-bounds-check-setter (new-value :: , buffer :: , index :: ) => (value) buffer-element(buffer, index) := as(, new-value); end method; // // EMPTY? // define inline sealed method empty? (buffer :: ) => (result :: ) size(buffer) = 0 end method; /// Special <-> coercions define sealed method as (bsc == , buffer :: ) => (bs :: ) let bs :: = make(, size: buffer.size); without-bounds-checks for (i :: from 0 below buffer.size) // buffer-element returns a character element(bs, i) := as(, element(buffer, i)); end for; end without-bounds-checks; bs end method; define sealed method as (buffer-class == , bs :: ) => (buffer :: ) let buffer :: = make(, size: bs.size); without-bounds-checks for (i :: from 0 below bs.size) element(buffer, i) := as(, element(bs, i)); end for; end without-bounds-checks; buffer end method; // already is a vector. Maybe want method for simple object vector? define sealed method as (class == , x :: ) => (vector :: ) x end method; //// ITERATION define inline function buffer-current-element (buffer :: , state :: ) => (result :: ) element-no-bounds-check(buffer, state); end function; define inline function buffer-current-element-setter (new-value :: , buffer :: , state :: ) => () element-no-bounds-check(buffer, state) := new-value; end function; define inline method forward-iteration-protocol (buffer :: ) => (initial-state :: , limit :: , next-state :: , finished-state? :: , current-key :: , current-element :: , current-element-setter :: , copy-state :: ); let (initial-state, limit, next-state, finished-state?, current-key, current-element, current-element-setter, copy-state) = next-method(); ignore(current-element, current-element-setter); values (initial-state, limit, next-state, finished-state?, current-key, buffer-current-element, buffer-current-element-setter, copy-state) end method forward-iteration-protocol; /// Fast buffer copying define inline function buffer-ref (buffer :: , index :: ) => (result :: ) element-no-bounds-check(buffer, index) end function buffer-ref; define inline function buffer-ref-setter (value :: , buffer :: , index :: ) element-no-bounds-check(buffer, index) := value; end function buffer-ref-setter; /*---*** andrewa: not currently used define open generic breakpoint (amount) => (res); define method breakpoint (amount :: ) => (res) amount * 4; end; */ /* **** Temporarily commented out ***** // This is the "real" version - but it's currently broken // because the native back end doesn't implement primitive-fill-bytes! // properly define inline-only function fill-bytes! (target :: , value :: , start :: , last :: ) => () primitive-fill-bytes! (target, primitive-repeated-slot-offset(target), integer-as-raw(start), integer-as-raw(last - start), integer-as-raw(value)) end; */ /* Here's the temporary work-around */ define /* inline-only */ function fill-bytes! (target :: , value :: , start :: , last :: ) => () let amount = last - start; // First check to see if the conditions are correct for the // primitive to be compiled correctly. Must be an multiple of 4 // bytes, and a word which has each byte the same (i.e. 0) if ((value == 0) & (logand(amount, 3) == 0)) primitive-fill-bytes! (target, primitive-repeated-slot-offset(target), integer-as-raw(start), integer-as-raw(amount), integer-as-raw(value)) else // If the primitive will fail, do it the slow way let fill :: = as(, logand(value, #xff)); without-bounds-checks for (i :: from start below last) element(target, i) := fill; end for; end without-bounds-checks; end if; end; define sealed method buffer-fill (target :: , value :: , #key start :: = 0, end: last = size(target)) => (); let last :: = check-start-compute-end(target, start, last); fill-bytes!(target, value, start, last) end; define sealed method buffer-fill (target :: , value :: , #key start :: = 0, end: last = size(target)) => (); buffer-fill(target, as(, value), start: start, end: last) end; //---*** It would sure be nice to have low-level run-time support for this define function copy-bytes-range-error (src, src-start :: , dst, dst-start :: , n :: ) => () error("SRC-START %d DST-START %d AND N %d OUTSIDE OF SRC %= AND DST %=", src-start, dst-start, n, src, dst); end function; define sealed method copy-bytes (src :: , src-start :: , dst :: , dst-start :: , n :: ) => () let src-end :: = src-start + n; let dst-end :: = dst-start + n; if (n >= 0 & src-start >= 0 & dst-start >= 0 & src-end <= size(src) & dst-end <= size(dst)) primitive-replace-bytes! (dst, primitive-repeated-slot-offset(dst), integer-as-raw(dst-start), src, primitive-repeated-slot-offset(src), integer-as-raw(src-start), integer-as-raw(n)); else copy-bytes-range-error(src, src-start, dst, dst-start, n); end if; end method; define sealed method copy-bytes (src :: , src-start :: , dst :: , dst-start :: , n :: ) => () let src-end :: = src-start + n; let dst-end :: = dst-start + n; if (n >= 0 & src-start >= 0 & dst-start >= 0 & src-end <= size(src) & dst-end <= size(dst)) primitive-replace-bytes! (dst, primitive-repeated-slot-offset(dst), integer-as-raw(dst-start), src, primitive-repeated-slot-offset(src), integer-as-raw(src-start), integer-as-raw(n)); else copy-bytes-range-error(src, src-start, dst, dst-start, n); end if; end method; define sealed method copy-bytes (src :: , src-start :: , dst :: , dst-start :: , n :: ) => () let src-end :: = src-start + n; let dst-end :: = dst-start + n; if (n >= 0 & src-start >= 0 & dst-start >= 0 & src-end <= size(src) & dst-end <= size(dst)) primitive-replace-bytes! (dst, primitive-repeated-slot-offset(dst), integer-as-raw(dst-start), src, primitive-repeated-slot-offset(src), integer-as-raw(src-start), integer-as-raw(n)); else copy-bytes-range-error(src, src-start, dst, dst-start, n); end if; end method; define sealed method copy-bytes (src :: , src-start :: , dst :: , dst-start :: , n :: ) => () let src-end :: = src-start + n; let dst-end :: = dst-start + n; if (n >= 0 & src-start >= 0 & dst-start >= 0 & src-end <= size(src) & dst-end <= size(dst)) primitive-replace-bytes! (dst, primitive-repeated-slot-offset(dst), integer-as-raw(dst-start), src, primitive-repeated-slot-offset(src), integer-as-raw(src-start), integer-as-raw(n)); else copy-bytes-range-error(src, src-start, dst, dst-start, n); end if; end method; define sealed method copy-bytes (src :: , src-start :: , dst :: , dst-start :: , n :: ) => () let src-end :: = src-start + n; let dst-end :: = dst-start + n; if (n >= 0 & src-start >= 0 & dst-start >= 0 & src-end <= size(src) & dst-end <= size(dst)) primitive-replace-bytes! (dst, primitive-repeated-slot-offset(dst), integer-as-raw(dst-start), src, primitive-repeated-slot-offset(src), integer-as-raw(src-start), integer-as-raw(n)); else copy-bytes-range-error(src, src-start, dst, dst-start, n); end if; end method; define sealed method copy-bytes (src :: , src-start :: , dst :: , dst-start :: , n :: ) => () let src-end :: = src-start + n; let dst-end :: = dst-start + n; if (n >= 0 & src-start >= 0 & dst-start >= 0 & src-end <= size(src) & dst-end <= size(dst)) for (src-i :: from src-start below src-end, dst-i :: from dst-start) buffer-element(dst, dst-i) := as(, element-no-bounds-check(src, src-i)); end for; else copy-bytes-range-error(src, src-start, dst, dst-start, n); end if; end method; define sealed method copy-bytes (src :: , src-start :: , dst :: , dst-start :: , n :: ) => () let src-end :: = src-start + n; let dst-end :: = dst-start + n; if (n >= 0 & src-start >= 0 & dst-start >= 0 & src-end <= size(src) & dst-end <= size(dst)) without-bounds-checks for (src-i :: from src-start below src-end, dst-i :: from dst-start) dst[dst-i] := src[src-i]; end for; end without-bounds-checks; else copy-bytes-range-error(src, src-start, dst, dst-start, n); end if; end method; // eof