Skip to content

Commit 2705dc8

Browse files
committed
Merge branch 'release/2.3.0'
Release v2.3.0
2 parents 94c1c4d + 3c2d428 commit 2705dc8

38 files changed

+3355
-70
lines changed

CHANGELOG.md

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,26 @@ From v2.0.0 all notable changes to this project will be documented in this file.
88
99
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/) and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
1010

11+
## v2.3.0 of 2025/09/13
12+
13+
* Updated the collection specification:
14+
* Added snippet properties to enable recording of compilation results with Delphi 13 (issue [62](https://github.com/delphidabbler/code-snippets/issues/62)).
15+
* Deprecated compiler results with value `W` (issue [63](https://github.com/delphidabbler/code-snippets/issues/63)).
16+
* Changes were made to the _Structures_ category:
17+
* Added a new `TIntegerRange` advanced record (issue [56](https://github.com/delphidabbler/code-snippets/issues/56)).
18+
* Fixed an error in the description of the `Range` snippet.
19+
* Added a warning to the `TRangeEx` advanced record to note potentially buggy behaviour if the range lower bound is greater than the upper bound.
20+
* Added new `RandomString` routine to the _String Management_ category (issue [28](https://github.com/delphidabbler/code-snippets/issues/28)).
21+
* Added results of compiling every snippet with Delphi 13 (issue [60](https://github.com/delphidabbler/code-snippets/issues/60)).
22+
* Fixed bug that was preventing the `Softmax` routine in the _Mathematics_ category from compiling due to a missing unit declaration (issue [61](https://github.com/delphidabbler/code-snippets/issues/61)).
23+
* Changes to unit tests:
24+
* Added a new DUnit test project for the _Structures_ category and added it to the _CodeSnippetsTestsXE_ project group. Unit tests for all snippets in the _Structures_ category were created (issue [58](https://github.com/delphidabbler/code-snippets/issues/58)).
25+
* Added further unit tests for all snippets in the _Arrays_ category that did not already have them (issue [38](https://github.com/delphidabbler/code-snippets/issues/38)).
26+
* Added unit tests for the new `RandomString` routine.
27+
* Documentation:
28+
* Updated `tests/README.md` re the unit test changes in this release and other minor revisions.
29+
* Fixed typo in `README.md`.
30+
1131
## v2.2.3 of 2025/04/03
1232

1333
* Added results of compiling with Delphi 12 for all snippets with no pre-existing compile results for that compiler (issue [#27](https://github.com/delphidabbler/code-snippets/issues/27)).

README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,7 @@ See the `README.md` file in the `tests` directory for full details.
3636

3737
Releases can be found on the `releases` tab on the GitHub project page.
3838

39-
Each release[^1] comprises three zip files, as follows (replace `X.Y.X` in the file names with the release version number):
39+
Each release[^1] comprises three zip files, as follows (replace `X.Y.Z` in the file names with the release version number):
4040

4141
* `csdb-vX.Y.Z-data.zip` - Contains all the data in the collection. Required by applications that access the collection.
4242
* `csdb-vX.Y.Z-docs.zip` - Contains the documentation developers need to understand the structure of the data.

collection/706.dat

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
type
2+
TIntegerRange = record
3+
strict private
4+
var
5+
fLowerBound: Integer;
6+
fUpperBound: Integer;
7+
function GetLowerBound: Integer;
8+
function GetUpperBound: Integer;
9+
function IsSubrangeOf(const ARange: TIntegerRange): Boolean;
10+
public
11+
// Constructs a range whose bounds are A and B. The lowest of the two
12+
// parameters is taken as the lower bound of the range with the other
13+
// parameter taken as the upper bound.
14+
// Valid bounds must fall in the range -MaxInt..MaxInt. An
15+
// EArgumentException exception is raised otherwise.
16+
constructor Create(const A, B: Integer);
17+
18+
// Constructs an empty range.
19+
class function CreateEmpty: TIntegerRange; static;
20+
21+
// Checks if the range is empty.
22+
function IsEmpty: Boolean;
23+
24+
// Returns the length of the range, i.e. the number of integers in the range.
25+
function Length: Cardinal;
26+
27+
// Constrains AValue to fall within this range. If the value lies within the
28+
// range it is returned unchanged. If it is outside the range then either
29+
// LowerBound or UpperBound is returned, depending on whether the value
30+
// falls below or above the range, respectively.
31+
// An EInvalidOpException exception is raised if the range is empty.
32+
function Constrain(const AValue: Integer): Integer;
33+
34+
// Checks if this range overlaps with ARange, i.e. the interection of the
35+
// ranges is non empty. Empty ranges cannot overlap with any range.
36+
function OverlapsWith(const ARange: TIntegerRange): Boolean;
37+
38+
// Checks if this range is immediately adjacent to ARange, with no overlap.
39+
// Empty ranges are never contiguous with other ranges or themselves.
40+
function IsContiguousWith(const ARange: TIntegerRange): Boolean;
41+
42+
// Checks if the set of all values in this range and ARange form a
43+
// continuous sequence. This implies that a range is continuous with itself.
44+
// Since adding an empty range to a non-empty range doesn't change the
45+
// non-empty range we define empty ranges to be continuous with any range.
46+
function IsContinuousWith(const ARange: TIntegerRange): Boolean;
47+
48+
// Checks if ranges A and B are the same
49+
class operator Equal(const A, B: TIntegerRange): Boolean;
50+
51+
// Checks if ranges A and B are not the same
52+
class operator NotEqual(const A, B: TIntegerRange): Boolean;
53+
54+
// Checks if range A is contained in, or is the same as, range B.
55+
// An empty range is deemed to be contained in any other range.
56+
class operator LessThanOrEqual(const A, B: TIntegerRange): Boolean;
57+
58+
// Checks if range A is contains, or is the same as, range B.
59+
// A non-empty range is never contained in an empty range.
60+
class operator GreaterThanOrEqual(const A, B: TIntegerRange): Boolean;
61+
62+
// Combine two ranges, A and B. The result is the smallest range that
63+
// contains both A and B.
64+
// If A and B are not continuous the resulting range will contain values
65+
// that were not in either A or B.
66+
// Combining any range either with itself or with an empty range is a no-op.
67+
class operator Add(const A, B: TIntegerRange): TIntegerRange;
68+
69+
// Returns a range that is the intersection of ranges A and B.
70+
// Returns an empty range if A and B do not overlap.
71+
class operator Multiply(const A, B: TIntegerRange): TIntegerRange;
72+
73+
// Checks if integer AValue is contained within range ARange.
74+
class operator In(const AValue: Integer; const ARange: TIntegerRange):
75+
Boolean;
76+
77+
// Implicitly casts ARange to a string. If ARange is non-empty the string
78+
// has format [X..Y], where X and Y are the lower and upper bounds of
79+
// ARange respectively. If ARange is empty then [] is returned.
80+
// This means that ARange can be assigned directly to a string.
81+
class operator Implicit(const ARange: TIntegerRange): string;
82+
83+
// Explicitly casts ARange to a string. If ARange is non-empty the string
84+
// has format [X..Y], where X and Y are the lower and upper bounds of
85+
// ARange respectively. If ARange is empty then [] is returned.
86+
// This means that ARange can be explicitly cast to a string using
87+
// string(ARange).
88+
class operator Explicit(const ARange: TIntegerRange): string;
89+
90+
// The lower bound of a non-empty range.
91+
// EInvalidOpException is raised if the property is read when the range is
92+
// empty.
93+
property LowerBound: Integer read GetLowerBound;
94+
95+
// The upper bound of a non-empty range.
96+
// EInvalidOpException is raised if the property is read when the range is
97+
// empty.
98+
property UpperBound: Integer read GetUpperBound;
99+
end;
100+
101+
class operator TIntegerRange.Add(const A, B: TIntegerRange): TIntegerRange;
102+
begin
103+
if A.IsEmpty then
104+
Exit(B);
105+
if B.IsEmpty then
106+
Exit(A);
107+
Result := TIntegerRange.Create(
108+
Math.Min(A.fLowerBound, B.fLowerBound),
109+
Math.Max(A.fUpperBound, B.fUpperBound)
110+
);
111+
end;
112+
113+
function TIntegerRange.Constrain(const AValue: Integer): Integer;
114+
begin
115+
if IsEmpty then
116+
raise Sysutils.EInvalidOpException.Create(
117+
'TIntegerRange.Constrain not valid for an empty range.'
118+
);
119+
Result := Math.EnsureRange(AValue, fLowerBound, fUpperBound);
120+
end;
121+
122+
constructor TIntegerRange.Create(const A, B: Integer);
123+
begin
124+
// Normalise range so that smallest parameter is the lower bound
125+
fLowerBound := Math.Min(A, B);
126+
fUpperBound := Math.Max(A, B);
127+
if fLowerBound = Low(Integer) then
128+
// This restriction is required to prevent the Length method's Cardinal
129+
// return value from wrapping around / overflowing
130+
raise SysUtils.EArgumentException.CreateFmt(
131+
'TIntegerRange.Create: Arguments must be greater than %d', [Low(Integer)]
132+
);
133+
end;
134+
135+
class function TIntegerRange.CreateEmpty: TIntegerRange;
136+
begin
137+
Result.fLowerBound := High(Integer);
138+
Result.fUpperBound := Low(Integer);
139+
end;
140+
141+
class operator TIntegerRange.Equal(const A, B: TIntegerRange): Boolean;
142+
begin
143+
if A.IsEmpty or B.IsEmpty then
144+
Exit(A.IsEmpty and B.IsEmpty);
145+
Result := (A.fLowerBound = B.fLowerBound) and (A.fUpperBound = B.fUpperBound);
146+
end;
147+
148+
class operator TIntegerRange.Explicit(const ARange: TIntegerRange): string;
149+
begin
150+
if ARange.IsEmpty then
151+
Exit('[]');
152+
Result := SysUtils.Format(
153+
'[%d..%d]', [ARange.fLowerBound, ARange.fUpperBound]
154+
);
155+
end;
156+
157+
function TIntegerRange.GetLowerBound: Integer;
158+
begin
159+
if IsEmpty then
160+
raise Sysutils.EInvalidOpException.Create(
161+
'TIntegerRange.LowerBound not valid for an empty range.'
162+
);
163+
Result := fLowerBound;
164+
end;
165+
166+
function TIntegerRange.GetUpperBound: Integer;
167+
begin
168+
if IsEmpty then
169+
raise Sysutils.EInvalidOpException.Create(
170+
'TIntegerRange.LowerBound not valid for an empty range.'
171+
);
172+
Result := fUpperBound;
173+
end;
174+
175+
class operator TIntegerRange.GreaterThanOrEqual(const A, B: TIntegerRange):
176+
Boolean;
177+
begin
178+
Result := B.IsSubrangeOf(A);
179+
end;
180+
181+
class operator TIntegerRange.Implicit(const ARange: TIntegerRange): string;
182+
begin
183+
Result := string(ARange); // calls Explicit cast operator
184+
end;
185+
186+
class operator TIntegerRange.In(const AValue: Integer;
187+
const ARange: TIntegerRange): Boolean;
188+
begin
189+
if ARange.IsEmpty then
190+
Exit(False);
191+
Result := (AValue >= ARange.fLowerBound) and (AValue <= ARange.fUpperBound);
192+
end;
193+
194+
function TIntegerRange.IsContiguousWith(const ARange: TIntegerRange): Boolean;
195+
begin
196+
if Self.IsEmpty or ARange.IsEmpty then
197+
Exit(False);
198+
Result := (Self + ARange).Length = (Self.Length + ARange.Length);
199+
end;
200+
201+
function TIntegerRange.IsContinuousWith(const ARange: TIntegerRange): Boolean;
202+
begin
203+
if Self.IsEmpty or ARange.IsEmpty then
204+
// Empty ranges are only continuous with other empty ranges
205+
Exit(True);
206+
Result := IsContiguousWith(ARange) or OverlapsWith(ARange);
207+
end;
208+
209+
function TIntegerRange.IsEmpty: Boolean;
210+
begin
211+
Result := fLowerBound > fUpperBound;
212+
end;
213+
214+
function TIntegerRange.IsSubrangeOf(const ARange: TIntegerRange): Boolean;
215+
begin
216+
if ARange.IsEmpty then
217+
Exit(Self.IsEmpty);
218+
Result := (Self.fLowerBound >= ARange.fLowerBound)
219+
and (Self.fUpperBound <= ARange.fUpperBound)
220+
or Self.IsEmpty
221+
end;
222+
223+
function TIntegerRange.Length: Cardinal;
224+
begin
225+
if IsEmpty then
226+
Exit(0);
227+
Result := fUpperBound - fLowerBound + 1
228+
end;
229+
230+
class operator TIntegerRange.LessThanOrEqual(const A, B: TIntegerRange):
231+
Boolean;
232+
begin
233+
Result := A.IsSubrangeOf(B);
234+
end;
235+
236+
class operator TIntegerRange.Multiply(const A, B: TIntegerRange): TIntegerRange;
237+
var
238+
Up, Lo: Integer;
239+
begin
240+
if A.IsEmpty or B.IsEmpty then
241+
Exit(TIntegerRange.CreateEmpty);
242+
Lo := Math.Max(A.fLowerBound, B.fLowerBound);
243+
Up := Math.Min(A.fUpperBound, B.fUpperBound);
244+
if Lo <= Up then
245+
Result := TIntegerRange.Create(Lo, Up)
246+
else
247+
Result := TIntegerRange.CreateEmpty;
248+
end;
249+
250+
class operator TIntegerRange.NotEqual(const A, B: TIntegerRange): Boolean;
251+
begin
252+
if A.IsEmpty or B.IsEmpty then
253+
Exit(A.IsEmpty <> B.IsEmpty);
254+
Result := (A.fLowerBound <> B.fLowerBound)
255+
or (A.fUpperBound <> B.fUpperBound);
256+
end;
257+
258+
function TIntegerRange.OverlapsWith(const ARange: TIntegerRange): Boolean;
259+
begin
260+
Result := not (Self * ARange).IsEmpty;
261+
end;

collection/707.dat

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
function RandomString(const SL: Classes.TStrings): string; overload;
2+
begin
3+
if SL.Count = 0 then
4+
raise SysUtils.EArgumentException.Create(
5+
'RandomString called with empty string list'
6+
);
7+
Result := SL[Random(SL.Count)];
8+
end;

collection/VERSION

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.2.3
1+
2.3.0

0 commit comments

Comments
 (0)