[fpc-devel] Initial implementation of a "functional" array helper unit, as suggested by Sven Barth on the Lazarus forums.
Ben Grasset
operator97 at gmail.com
Fri Jun 28 18:39:19 CEST 2019
On Thu, Jun 27, 2019 at 9:09 PM Ben Grasset <operator97 at gmail.com> wrote:
> -snip-
>
> Yikes, I didn't realize the "preformatted" code from the Lazarus HTML
exporter would show up with a bunch of asterisks outside of a real email
client.
Here's normal text versions of both the unit, and the example program:
unit Functional;
{$mode Delphi}{$H+}
interface
type
TArrayHelper<T> = record
public type
TMapModifier = function(constref Current: T): T;
TFilterTest = function(constref Current: T): boolean;
TReduceModifier = procedure(var Accumulator: T; constref Current: T);
ArrayType = array of T;
THelperImpl = record helper for ArrayType
function Map(const Modifier: TMapModifier): ArrayType; overload;
function Filter(const Test: TFilterTest): ArrayType; overload;
function Reduce(const Modifier: TReduceModifier): T; overload;
class function Map(constref Values: array of T; const Modifier:
TMapModifier): ArrayType; static; overload;
class function Filter(constref Values: array of T; const Test:
TFilterTest): ArrayType; static; overload;
class function Reduce(constref Values: array of T; const Modifier:
TReduceModifier): T; static; overload;
end;
end;
(* These are defined without the usual T prefix to avoid any conflict
with possible existing type aliases. *)
UInt8Array = TArrayHelper<Byte>.ArrayType;
ShortIntArray = TArrayHelper<ShortInt>.ArrayType;
SmallIntArray = TArrayHelper<SmallInt>.ArrayType;
UInt16Array = TArrayHelper<Word>.ArrayType;
UInt32Array = TArrayHelper<Cardinal>.ArrayType;
Int32Array = TArrayHelper<LongInt>.ArrayType;
Int64Array = TArrayHelper<Int64>.ArrayType;
UInt64Array = TArrayHelper<QWord>.ArrayType;
Float32Array = TArrayHelper<Single>.ArrayType;
Float64Array = TArrayHelper<Double>.ArrayType;
ShortStringArray = TArrayHelper<ShortString>.ArrayType;
AnsiStringArray = TArrayHelper<AnsiString>.ArrayType;
UnicodeStringArray = TArrayHelper<UnicodeString>.ArrayType;
implementation
function TArrayHelper<T>.THelperImpl.Map(const Modifier: TMapModifier):
ArrayType;
var I: PtrUInt;
begin
SetLength(Result, Length(Self));
for I := 0 to High(Self) do
Result[I] := Modifier(Self[I]);
end;
function TArrayHelper<T>.THelperImpl.Filter(const Test: TFilterTest):
ArrayType;
var I, J: PtrUInt;
begin
J := 0;
SetLength(Result, Length(Self));
for I := 0 to High(Self) do
if Test(Self[I]) then begin
Result[J] := Self[I];
Inc(J);
end;
SetLength(Result, J);
end;
function TArrayHelper<T>.THelperImpl.Reduce(const Modifier:
TReduceModifier): T;
var I: PtrUInt;
begin
Result := Self[0];
for I := 1 to High(Self) do
Modifier(Result, Self[I]);
end;
class function TArrayHelper<T>.THelperImpl.Map(constref Values: array of T;
const Modifier: TMapModifier): ArrayType;
var I: PtrUInt;
begin
SetLength(Result, Length(Values));
for I := 0 to High(Values) do
Result[I] := Modifier(Values[I]);
end;
class function TArrayHelper<T>.THelperImpl.Filter(constref Values: array of
T; const Test: TFilterTest): ArrayType;
var I, J: PtrUInt;
begin
J := 0;
SetLength(Result, Length(Values));
for I := 0 to High(Values) do
if Test(Values[I]) then begin
Result[J] := Values[I];
Inc(J);
end;
SetLength(Result, J);
end;
class function TArrayHelper<T>.THelperImpl.Reduce(constref Values: array of
T; const Modifier: TReduceModifier): T;
var I: PtrUInt;
begin
Result := Values[0];
for I := 1 to High(Values) do
Modifier(Result, Values[I]);
end;
end.
///////////////
program TestFunctional;
{$mode ObjFPC}{$H+}
uses Functional;
function NumMap(constref Current: LongInt): LongInt;
begin
Result := Current + Current;
end;
function NumFilter(constref Current: LongInt): Boolean;
begin
Result := Current > 5;
end;
procedure NumReduce(var Accumulator: LongInt; constref Current: LongInt);
begin
Accumulator += Current;
end;
function StringMap(constref Current: AnsiString): AnsiString;
begin
Result := Current + Current;
end;
function StringFilter(constref Current: AnsiString): boolean;
begin
Result := Current > 'e';
end;
procedure StringReduce(var Accumulator: AnsiString; constref Current:
AnsiString);
begin
Accumulator += Current;
end;
var
I: LongInt;
S: AnsiString;
begin
WriteLn('Instanced Integer Map!');
for I in Int32Array.Create(1, 2, 3, 4, 5, 6, 7, 8, 9, 10).Map(@NumMap) do
WriteLn(I);
WriteLn('Instanced Integer Filter!');
for I in Int32Array.Create(1, 2, 3, 4, 5, 6, 7, 8, 9,
10).Filter(@NumFilter) do WriteLn(I);
WriteLn('Instanced Integer Reduce!');
WriteLn(Int32Array.Create(1, 2, 3, 4, 5, 6, 7, 8, 9,
10).Reduce(@NumReduce));
WriteLn('Static Integer Map!');
for I in Int32Array.Map([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], @NumMap) do
WriteLn(I);
WriteLn('Static Integer Filter!');
for I in Int32Array.Filter([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], @NumFilter)
do WriteLn(I);
WriteLn('Static Integer Reduce!');
WriteLn(Int32Array.Reduce([1, 2, 3, 4, 5, 6, 7, 8, 9, 10], @NumReduce));
WriteLn('Instanced String Map!');
for S in AnsiStringArray.Create('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i').Map(@StringMap) do WriteLn(S);
WriteLn('Instanced String Filter!');
for S in AnsiStringArray.Create('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i').Filter(@StringFilter) do WriteLn(S);
WriteLn('Instanced String Reduce!');
WriteLn(AnsiStringArray.Create('a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i').Reduce(@StringReduce));
WriteLn('Static String Map!');
for S in AnsiStringArray.Map(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i'], @StringMap) do WriteLn(S);
WriteLn('Static String Filter!');
for S in AnsiStringArray.Filter(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i'], @StringFilter) do WriteLn(S);
WriteLn('Static String Reduce!');
WriteLn(AnsiStringArray.Reduce(['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h',
'i'], @StringReduce));
end.
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.freepascal.org/pipermail/fpc-devel/attachments/20190628/b5f8c8c6/attachment.html>
More information about the fpc-devel
mailing list