Skip to content

Commit 03ed7f2

Browse files
committed
Implement SetterFlags_SkipNA; update header.
1 parent c2a1664 commit 03ed7f2

File tree

3 files changed

+84
-22
lines changed

3 files changed

+84
-22
lines changed

include/dss_capi.h

+37
Original file line numberDiff line numberDiff line change
@@ -342,6 +342,43 @@ extern "C" {
342342
*/
343343
};
344344

345+
/*!
346+
Setter flags customize down how the update of DSS properties are handled by the
347+
engine and parts of the API. Use especially in the `Obj` and `Batch` APIs
348+
*/
349+
enum SetterFlags {
350+
SetterFlags_ImplicitSizes = 0x00000001, /*!<
351+
Most array properties depend on sizes defined by other properties.
352+
Using this flag, many properties allow users to skip setting the other property
353+
directly, allowing the engine to use the size of the provided array to
354+
initialize the other property.
355+
*/
356+
357+
SetterFlags_AvoidFullRecalc = 0x00000002, /*!<
358+
Some components like Loads don't need to update YPrim for every change, e.g. setting
359+
"`load.a_load.kW=1`" if was "kW" previously 2 should not force a YPrim update, but it does
360+
force an update by default.
361+
Using this flag will reproduce what the classic OpenDSS API for Loads (DSS.ActiveCircuit.Loads)
362+
does, but removes a lot of duplicated code. Besides that, we can extend the feature
363+
for other components if we think it fits.
364+
*/
365+
366+
SetterFlags_SkipNA = 0x00000004, /*!<
367+
For batch operations with arrays, skip NA values
368+
369+
Currently, NA values are interpret as:
370+
- NaN for float64
371+
- INT32_MIN (0x80000000) for int32
372+
- Null pointers for strings (in this case, use a `"\0"` string for empty strings)
373+
*/
374+
375+
SetterFlags_AllowAllConductors = 0x80000000 /*!<
376+
Used internally for the "Wires" property ("Conductors").
377+
This was left public in case someone tries to implement some internal aspects in
378+
external functions.
379+
*/
380+
};
381+
345382
/*!
346383
The values from AltDSSEvent are used in the updated DSSEvents_* functions to
347384
register callbacks for different events. Note that in the official OpenDSS

src/CAPI/CAPI_Obj.pas

+44-21
Original file line numberDiff line numberDiff line change
@@ -1623,6 +1623,7 @@ procedure Batch_SetFloat64Array(batch: TDSSObjectPtr; batchSize: Integer; Index:
16231623
doublePtr: PDouble;
16241624
propFlags: TPropertyFlags;
16251625
singleEdit: Boolean;
1626+
allowNA: Boolean;
16261627
begin
16271628
if (batch = NIL) or (batch^ = NIL) or (batchSize = 0) then
16281629
Exit;
@@ -1638,23 +1639,30 @@ procedure Batch_SetFloat64Array(batch: TDSSObjectPtr; batchSize: Integer; Index:
16381639
]) then
16391640
Exit;
16401641

1642+
allowNA := not (TDSSPropertySetterFlag.SkipNA in setterFlags);
1643+
16411644
if (cls.PropertyType[Index] = TPropertyType.DoubleProperty) and
16421645
(propFlags = []) and
16431646
(cls.PropertyScale[Index] = 1) then
16441647
begin
1648+
// Faster path
16451649
for i := 1 to batchSize do
16461650
begin
1647-
singleEdit := not (Flg.EditingActive in batch^.Flags);
1648-
if singleEdit then
1649-
cls.BeginEdit(batch^, False);
1651+
// check for each element, in case the element is being edited somewhere else
1652+
if (allowNA) or (not IsNaN(Value^)) then
1653+
begin
1654+
singleEdit := not (Flg.EditingActive in batch^.Flags);
1655+
if singleEdit then
1656+
cls.BeginEdit(batch^, False);
16501657

1651-
doublePtr := PDouble(PtrUint(batch^) + propOffset);
1652-
prev := doubleptr^;
1653-
doublePtr^ := Value^;
1654-
batch^.PropertySideEffects(Index, Round(prev), setterFlags);
1658+
doublePtr := PDouble(PtrUint(batch^) + propOffset);
1659+
prev := doubleptr^;
1660+
doublePtr^ := Value^;
1661+
batch^.PropertySideEffects(Index, Round(prev), setterFlags);
16551662

1656-
if singleEdit then
1657-
cls.EndEdit(batch^, 1);
1663+
if singleEdit then
1664+
cls.EndEdit(batch^, 1);
1665+
end;
16581666
inc(batch);
16591667
inc(Value);
16601668
end;
@@ -1663,7 +1671,9 @@ procedure Batch_SetFloat64Array(batch: TDSSObjectPtr; batchSize: Integer; Index:
16631671

16641672
for i := 1 to batchSize do
16651673
begin
1666-
batch^.SetDouble(Index, Value^, setterFlags);
1674+
if (allowNA) or (not IsNaN(Value^)) then
1675+
batch^.SetDouble(Index, Value^, setterFlags);
1676+
16671677
inc(batch);
16681678
inc(Value)
16691679
end;
@@ -1678,6 +1688,7 @@ procedure Batch_SetInt32Array(batch: TDSSObjectPtr; batchSize: Integer; Index: I
16781688
intPtr: PInteger;
16791689
propFlags: TPropertyFlags;
16801690
singleEdit: Boolean;
1691+
allowNA: Boolean;
16811692
begin
16821693
if (batch = NIL) or (batch^ = NIL) or (batchSize = 0) then
16831694
Exit;
@@ -1695,23 +1706,30 @@ procedure Batch_SetInt32Array(batch: TDSSObjectPtr; batchSize: Integer; Index: I
16951706
]) then
16961707
Exit;
16971708

1709+
allowNA := not (TDSSPropertySetterFlag.SkipNA in setterFlags);
1710+
16981711
if (cls.PropertyType[Index] <> TPropertyType.IntegerOnStructArrayProperty) and
16991712
(propFlags = []) and
17001713
(cls.PropertyScale[Index] = 1) then
17011714
begin
1715+
// Faster path
17021716
for i := 1 to batchSize do
17031717
begin
1704-
singleEdit := not (Flg.EditingActive in batch^.Flags);
1705-
if singleEdit then
1706-
cls.BeginEdit(batch^, False);
1718+
if (allowNA) or (Value^ = $80000000) then
1719+
begin
1720+
// check for each element, in case the element is being edited somewhere else
1721+
singleEdit := not (Flg.EditingActive in batch^.Flags);
1722+
if singleEdit then
1723+
cls.BeginEdit(batch^, False);
17071724

1708-
intPtr := PInteger(PtrUint(batch^) + propOffset);
1709-
prev := intPtr^;
1710-
intPtr^ := Value^;
1711-
batch^.PropertySideEffects(Index, prev, setterFlags);
1725+
intPtr := PInteger(PtrUint(batch^) + propOffset);
1726+
prev := intPtr^;
1727+
intPtr^ := Value^;
1728+
batch^.PropertySideEffects(Index, prev, setterFlags);
17121729

1713-
if singleEdit then
1714-
cls.EndEdit(batch^, 1);
1730+
if singleEdit then
1731+
cls.EndEdit(batch^, 1);
1732+
end;
17151733
inc(batch);
17161734
inc(Value);
17171735
end;
@@ -1720,7 +1738,8 @@ procedure Batch_SetInt32Array(batch: TDSSObjectPtr; batchSize: Integer; Index: I
17201738

17211739
for i := 1 to batchSize do
17221740
begin
1723-
batch^.SetInteger(Index, Value^, setterFlags);
1741+
if (allowNA) or (Value^ = $80000000) then
1742+
batch^.SetInteger(Index, Value^, setterFlags);
17241743
inc(batch);
17251744
inc(Value)
17261745
end;
@@ -1732,6 +1751,7 @@ procedure Batch_SetStringArray(batch: TDSSObjectPtr; batchSize: Integer; Index:
17321751
// propOffset: PtrUint;
17331752
i: Integer;
17341753
// propFlags: TPropertyFlags;
1754+
allowNA: Boolean;
17351755
begin
17361756
if (batch = NIL) or (batch^ = NIL) or (batchSize = 0) then
17371757
Exit;
@@ -1750,9 +1770,12 @@ procedure Batch_SetStringArray(batch: TDSSObjectPtr; batchSize: Integer; Index:
17501770
]) then
17511771
Exit;
17521772

1773+
allowNA := not (TDSSPropertySetterFlag.SkipNA in setterFlags);
1774+
17531775
for i := 1 to batchSize do
17541776
begin
1755-
batch^.SetString(Index, Value^, setterFlags);
1777+
if (allowNA) or (Value^ <> NIL) then
1778+
batch^.SetString(Index, Value^, setterFlags);
17561779
inc(batch);
17571780
inc(Value)
17581781
end;

src/Common/DSSClass.pas

+3-1
Original file line numberDiff line numberDiff line change
@@ -92,7 +92,9 @@ interface
9292
// for other components if we think it fits.
9393
AvoidFullRecalc = 1,
9494

95-
Reserved2 = 2,
95+
// For batch operations, skip NA values -- values of NaN for float64, INT32_MIN (0x80000000) for int32, null pointers for strings.
96+
SkipNA = 2,
97+
9698
Reserved3 = 3,
9799
Reserved4 = 4,
98100
Reserved5 = 5,

0 commit comments

Comments
 (0)