Common Lisp the Language, 2nd Edition

Next: Strings Up: Arrays Previous: Fill Pointers

# 17.6. Changing the Dimensions of an Array

This function may be used to resize or reshape an array. Its options are similar to those of `make-array`.

[Function]
`adjust-array array new-dimensions &key :element-type :initial-element :initial-contents :fill-pointer :displaced-to :displaced-index-offset`

`adjust-array` takes an array and a number of other arguments as for `make-array`. The number of dimensions specified by new-dimensions must equal the rank of array.

`adjust-array` returns an array of the same type and rank as array, with the specified new-dimensions. In effect, the array argument itself is modified to conform to the new specifications, but this may be achieved either by modifying the array or by creating a new array and modifying the array argument to be displaced to the new array.

In the simplest case, one specifies only the new-dimensions and possibly an `:initial-element` argument. Those elements of array that are still in bounds appear in the new array. The elements of the new array that are not in the bounds of array are initialized to the `:initial-element`; if this argument is not provided, then the initial contents of any new elements are undefined.

If `:element-type` is specified, then array must be such that it could have been originally created with that type; otherwise an error is signaled. Specifying `:element-type` to `adjust-array` serves only to require such an error check.

If `:initial-contents` or `:displaced-to` is specified, then it is treated as for `make-array`. In this case none of the original contents of array appears in the new array.

If `:fill-pointer` is specified, the fill pointer of the array is reset as specified. An error is signaled if array had no fill pointer already.

X3J13 voted in June 1988 (ADJUST-ARRAY-FILL-POINTER) to clarify the treatment of the `:fill-pointer` argument as follows.

If the `:fill-pointer` argument is not supplied, then the fill pointer of the array is left alone. It is an error to try to adjust the array to a total size that is smaller than its fill pointer.

If the `:fill-pointer` argument is supplied, then its value must be either an integer, `t`, or `nil`. If it is an integer, then it is the new value for the fill pointer; it must be non-negative and no greater than the new size to which the array is being adjusted. If it is `t`, then the fill pointer is set equal to the new size for the array. If it is `nil`, then the fill pointer is left alone; it is as if the argument had not been supplied. Again, it is an error to try to adjust the array to a total size that is smaller than its fill pointer.

An error is signaled if a non-`nil :fill-pointer` value is supplied and the array to be adjusted does not already have a fill pointer.

This extended treatment of the `:fill-pointer` argument to `adjust-array` is consistent with the previously existing treatment of the `:fill-pointer` argument to `make-array`.

`adjust-array` may, depending on the implementation and the arguments, simply alter the given array or create and return a new one. In the latter case the given array will be altered so as to be displaced to the new array and have the given new dimensions.

It is not permitted to call `adjust-array` on an array that was not created with the `:adjustable` option. The predicate `adjustable-array-p` may be used to determine whether or not an array is adjustable.

X3J13 voted in January 1989 (ADJUST-ARRAY-NOT-ADJUSTABLE) to allow `adjust-array` to be applied to any array. If `adjust-array` is applied to an array that was originally created with `:adjustable` true, the array returned is `eq` to its first argument. It is not specified whether `adjust-array` returns an array `eq` to its first argument for any other arrays. If the array returned by `adjust-array` is not `eq` to its first argument, the original array is unchanged and does not share storage with the new array.

Under this new definition, it is wise to treat `adjust-array` in the same manner as `delete` and `nconc`: one should carefully retain the returned value, for example by writing

    (setq my-array (adjust-array my-array ...))

rather than relying solely on a side effect.

If `adjust-array` is applied to an array that is displaced to another array x, then afterwards neither array nor the returned result is displaced to x unless such displacement is explicitly re-specified in the call to `adjust-array`.

For example, suppose that the 4-by-4 array `m` looks like this:

    #2A( ( alpha     beta      gamma     delta )
         ( epsilon   zeta      eta       theta )
         ( iota      kappa     lambda    mu    )
         ( nu        xi        omicron   pi    ) )

Then the result of

    (adjust-array m '(3 5) :initial-element 'baz)

is a 3-by-5 array with contents

    #2A( ( alpha     beta      gamma     delta     baz )
         ( epsilon   zeta      eta       theta     baz )
         ( iota      kappa     lambda    mu        baz ) )

Note that if array `a` is created displaced to array `b` and subsequently array `b` is given to `adjust-array`, array `a` will still be displaced to array `b`; the effects of this displacement and the rule of row-major storage order must be taken into account.

X3J13 voted in June 1988 (ADJUST-ARRAY-DISPLACEMENT) to clarify the interaction of `adjust-array` with array displacement.

Suppose that an array A is to be adjusted. There are four cases according to whether or not A was displaced before adjustment and whether or not the result is displaced after adjustment.

- Suppose A is not displaced either before or after. The dimensions of A are altered, and the contents are rearranged as appropriate. Additional elements of A are taken from the `:initial-element` argument. However, the use of the `:initial-contents` argument causes all old contents to be discarded.

- Suppose A is not displaced before, but is displaced to array C after. None of the original contents of A appears in A afterwards; A now contains (some of) the contents of C, without any rearrangement of C.

- Suppose A is displaced to array B before the call, and is displaced to array C after the call. (Note that B and C may be the same array.) The contents of B do not appear in A afterwards (unless such contents also happen to be in C, as when B and C are the same, for example). If `:displaced-index-offset` is not specified in the call to `adjust-array`, it defaults to zero; the old offset (into B) is not retained.

- Suppose A is displaced to array B before the call, but is not displaced afterwards. In this case A gets a new ``data region'' and (some of) the contents of B are copied into it as appropriate to maintain the existing old contents. Additional elements of A are taken from the `:initial-element` argument. However, the use of the `:initial-contents` argument causes all old contents to be discarded.

If array X is displaced to array Y, and array Y is displaced to array Z, and array Y is altered by `adjust-array`, array X must now refer to the adjusted contents of Y. This means that an implementation may not collapse the chain to make X refer to Z directly and forget that the chain of reference passes through array Y. (Caching techniques are of course permitted, as long as they preserve the semantics specified here.)

If X is displaced to Y, it is an error to adjust Y in such a way that it no longer has enough elements to satisfy X. This error may be signaled at the time of the adjustment, but this is not required.

Note that omitting the `:displaced-to` argument to `adjust-array` is equivalent to specifying `:displaced-to nil`; in either case, the array is not displaced after the call regardless of whether it was displaced before the call.

Next: Strings Up: Arrays Previous: Fill Pointers