123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156(** {1 Introduction} *)(** Adjustable grids are two dimensional arrays whose width/height can be changed by adding
or removing row/column at either end (one at a time).
Implemented using the {{:https://github.com/backtracking/flex-array}
flex-array library by Jean-Christophe Filliâtre}. *)(** The type of grids. This is an immutable data structure. Values of type
['a t] can be compared using structural equality [=] (provided the elements
of type ['a] can). *)type+'at='aFlex_array.tFlex_array.t(** {1 Using grids} *)(** [width g] returns the width of [g], that is to say its number of columns. *)letwidth(grid:'at)=ifFlex_array.lengthgrid=0then0elseFlex_array.length(Flex_array.getgrid0)(** [height g] returns the height of [g], that is to say its number of rows. *)letheight(grid:'at)=Flex_array.lengthgrid(** [dim g] returns a pair in which the first element is the width of [g] and
the second one its height. *)letdim(grid:'at)=letheight=Flex_array.lengthgridinifheight=0then(0,0)else(Flex_array.length(Flex_array.getgrid0),height)(** [get g ~x ~y] returns the element at width-index [~x] and height-index [~y]
in grid [g]. Index start at 0. *)letget(grid:'at)~x~y=letrow=Flex_array.getgridyinFlex_array.getrowx(** [get_row g y] returns the row at height-index [y] in grid [g]. Index start
at 0. *)letget_row(grid:'at)y=Flex_array.getgridy(** [get_col g x] returns the column at width-index [x] in grid [g]. Index start
at 0. *)letget_col(grid:'at)y=Flex_array.map(funrow->Flex_array.getrowy)grid(** {1 Building grids} *)(** The empty grid. *)letempty:'at=Flex_array.empty(** [of_array a] returns a grid from the two dimensional array [a] with the same
height, width and order. *)letof_arraya:'at=Flex_array.of_array(Array.mapFlex_array.of_arraya)(** [of_list l] returns a grid from the two dimensional list [l] with the same
height, width and order. *)letof_listl:'at=Flex_array.of_list(List.mapFlex_array.of_listl)(** [set g ~x ~y v] returns a new grid where all elements are identical to those
of [g], except at width-index [x] and height-index [y] where the element is
[v]. *)letset(grid:'at)~x~yv:'at=letrow=Flex_array.getgridyinletrow=Flex_array.setrowxvinFlex_array.setgridyrow(** [cons_row row grid] returns a new grid obtained by appending the row [row]
at the height-axis front of grid [g]. *)letcons_rowrow(grid:'at):'at=Flex_array.consrowgrid(** [snow_row grid row] returns a new grid obtained by appending the row [row]
at the height-axis end of grid [g]. *)letsnoc_row(grid:'at)row:'at=Flex_array.snocgridrow(** [cons_col col grid] returns a new grid obtained by appending the column
[col] at the width-axis front of grid [g]. *)letcons_colcol(grid:'at):'at=ifgrid=emptythenFlex_array.map(funel->Flex_array.conselFlex_array.empty)colelseFlex_array.mapi(funirow->Flex_array.cons(Flex_array.getcoli)row)grid(** [snow_col grid col] returns a new grid obtained by appending the column
[col] at the width-axis end of grid [g]. *)letsnoc_col(grid:'at)col:'at=ifgrid=emptythenFlex_array.map(funel->Flex_array.conselFlex_array.empty)colelseFlex_array.mapi(funirow->Flex_array.snocrow(Flex_array.getcoli))grid(** [tail_row g] returns a new grid obtained by removing the row at the
height-axis front of grid [g]. *)lettail_row(grid:'at):'at=Flex_array.tailgrid(** [liat_row g] returns a new grid obtained by removing the row at the
height-axis end of grid [g]. *)letliat_row(grid:'at):'at=Flex_array.liatgrid(** [tail_col g] returns a new grid obtained by removing the column at the
width-axis front of grid [g]. *)lettail_col(grid:'at):'at=Flex_array.mapFlex_array.tailgrid(** [liat_col g] returns a new grid obtained by removing the column at the
width-axis end of grid [g]. *)letliat_col(grid:'at):'at=Flex_array.mapFlex_array.liatgrid(** {1 Iterators} *)(** [iter f g] applies function [f] in turn to all the elements of [g]. It goes
row by row. It is equivalent to
[f (get g ~x:0 ~y:0); f (get g ~x:1 ~y:0); ...; f (get g ~x:(w - 1) ~y:0);
...; f (get g ~x:0 ~y:(h - 1)); f (get g ~x:1 ~y:(h -1)); ...; f (get g
~x:(w - 1) ~y:(h - 1))] where [w] and [h] are respectively the width and the
height of [g] but runs faster. *)letiterf(grid:'at)=Flex_array.iter(Flex_array.iterf)grid(** Same as {!iter}, but the function is applied with the width-index and
height-index of the element as first and second argument, and the element
itself as third argument. *)letiterif(grid:'at)=Flex_array.iteri(funyrow->Flex_array.iteri(funxv->f~x~yv)row)grid(** [map f g] returns a grid with the same dimension than [g] but where each
element [x] has been replaced by the value of [f x]. *)letmapf(grid:'at):'bt=Flex_array.map(Flex_array.mapf)grid(** Same as {!map}, but the function is applied with the width-index and
height-index of the element as first and second arguement, and the element
itself as third argument. *)letmapif(grid:'at):'bt=Flex_array.mapi(funxrow->Flex_array.mapi(funyv->f~x~yv)row)grid(** [fold f acc g] computes [Flex_array.fold (Flex_array.fold f) acc g]. *)letfoldfacc(grid:'at)=Flex_array.fold(Flex_array.foldf)accgrid(** [pp ?pp_sep_row ?pp_sep_col pp_v fmt g] prints items of grid [g] using
[pp_v] to print each item, calling [pp_sep_row] between rows and
[pp_sep_col] between items (i.e. between each column). [pp_sep_row] defaults
to {!Format.pp_print_cut} and [pp_print_col] defaults to
[fun fmt () -> Format.fprintf fmt ";"]. Does nothing on empty grids. *)letpp?(pp_sep_row=Format.pp_print_newline)?(pp_sep_col=funfmt()->Format.fprintffmt";")pp_vfmt(grid:'at)=Flex_array.pp~pp_sep:pp_sep_row(funfmtel->Flex_array.pp~pp_sep:pp_sep_colpp_vfmtel)fmtgrid