Files
2026-07-13 12:47:05 +08:00

173 lines
5.9 KiB
Markdown

## Helpers
### Requirements Helper
Requirements helper was introduced to replace plain checks for making them output informative messages (Debug and Verbose mode) and also replace macros REQUIRE_TRUE.
- it will lazily evaluate values and messages if the type wrapped and has` getValue` and `getMsg` methods
- it is implicit bool. this makes it usable with logical operators and also inside if conditions. Besides it will benefit from shortcircuit nature of those operators.
- it has the following check methods
```cpp
Requirements& expect(const T& expVar,const T1& reqVar, Op comparison, const char *first_half="")
Requirements& expectEq(const T& exp,const T1& req)
Requirements& expectNotEq(const T& exp,const T1& req)
Requirements& expectLess(const T& exp,const T1& req)
Requirements& expectLessEq(const T& exp,const T1& req)
Requirements& expectGreater(T exp, T1 req)
Requirements& expectGreaterEq(const T& exp,const T1& req
Requirements& expectTrue(const T& expVar, const char *msg=)
Requirements& expectFalse(const T& expVar, const char *msg=)
```
- you can either log the success case or throw error on the failure
- it can use plain types for checks.
- if value has stream operator it will be used to output its value. for custom types you may need add that by yourself
`ostream& operator<<(ostream& os, const CustomUserType& dt)`
- there is generic template `InfoVariable` wrapper for types to make it informative. you can use lambda operators with them as well to make it lazily evaluated
- we added custom `ShapeInfoVariable` wrapper for the NDArray and vector<> shapes to make them informative
- one can use `expect` to add its own proper comparison. simple lambda for that will be like this:
```cpp
[](const decltype(expType)& l, const decltype(reqType)& r){
//compare and return
return ....;
}
```
#### Examples:
firstly, we should enable logging
```cpp
sd::Environment::getInstance().setDebug(true);
sd::Environment::getInstance().setVerbose(true);
```
1. simple case
```cpp
Requirements req1("Requirement Helper Example#1");
int x = 20;
req1.expectLess(x, 22);
req1.expectEq(x, 21); //should fail
```
Output:
``` Requirement Helper Example#1: {20} expected to be equal to 21```
2. using InfoVariable wrapper
```cpp
int age = 15;
Requirements req2("Requirement Helper Example#2");
req2.expectGreaterEq(makeInfoVariable(age, "the user's age"), 18);
```
Output:
```
Requirement Helper Example#2: the user's age {15} expected to be greater than or equal 18
```
3. helper behavior while using many checks in one block
```cpp
int getAge(){
std::cout<<"getAge() was called"<<std::endl;
return 15;
}
....
Requirements req3("Requirement Helper Example#3");
int z = 20;
req3.expectEq(z, 21);
req3.expectGreaterEq(makeInfoVariable(getAge(), "the user's age"), 18);
```
Output:
```
Requirement Helper Example#3: {20} expected to be equal to 21
getAge() was called
```
As it is seen the second check did not happen as the previous failed. But still ```getAge()``` method was called as its function argument.
4. using **shortcircuit** to avoid Requirement call at all if the previous one was failed
```cpp
Requirements req4("Requirement Helper Example#4");
int zz = 20;
req4.expectEq(zz, 21) && //shortcircuit And
req4.expectGreaterEq(makeInfoVariable(getAge(), "the user's age"), 18);
```
Output:
```
Requirement Helper Example#4: {20} expected to be equal to 21
```
5. using lambdas with InfoVariable. it will make it lazily evaluated
```cpp
Requirements req5("Requirement Helper Example#5");
req5.expectEq( 21,
makeInfoVariable(21, []{
std::cout<<"lambda call#1"<<std::endl;
return "twenty one";
}));
req5.expectEq(makeInfoVariable([]{ return 20;}, []{return "twenty";}),
makeInfoVariable(21, []{
std::cout<<"lambda call#2"<<std::endl;
return "twenty one";
}));
req5.expectGreaterEq(makeInfoVariable([]{
std::cout<<"lambda call#3" <<std::endl;
return 15;
},
[]{ return "the user's age";}),
makeInfoVariable([]{return 18;}, []{return "the allowed age";})
);
```
Output:
```
lambda call#2
Requirement Helper Example#5: twenty {20} expected to be equal to twenty one 21
```
6. use bool nature and also log the success case
```cpp
Requirements req6("Requirement Helper Example#6");
NDArray * arr= nullptr;
arr !=nullptr && req6.expectEq(arr->rankOf(), 3) ;
req6.logTheSuccess();
```
Output:
```
Requirement Helper Example#6: meets the requirements
```
7. custom comparision lambda and also another usage of the custom wrapper written by us ```ShapeInfoVariable```. Note: we will use ```std::vector<int>```. this wrapper can be used with ```NDArray``` as well.
```cpp
Requirements req7("Requirement Helper Example#7");
req7.expect(makeShapeInfoVariable(std::vector<sd::LongType>{2,3,4,5}, SHAPE_MSG_INPUT0), makeShapeInfoVariable(std::vector<sd::LongType>{2,3,4,7}, SHAPE_MSG_INPUT1),
[](const std::vector<sd::LongType>& l, const std::vector<sd::LongType>& r){
return l == r;
}
, EXPECTED_EQ_MSG);
}
```
Output:
```
Requirement Helper Example#7: the Shape of the Input NDArray#0 {[2, 3, 4, 5]} expected to be equal to the Shape of the Input NDArray#1 [2, 3, 4, 7]
```
8. throw error when there is failure
```cpp
Requirements req8("Requirement Helper Example#8");
req8.expectEq(6,6) &&
req8.expectIn(6, {1,2,3,7,8,9});
req8.throws();
```
Output:
```
terminate called after throwing an instance of 'std::invalid_argument'
what(): Op validation failed
...
Requirement Helper Example#8: {6} expected to be one of these {[1, 2, 3, 7, 8, 9, ]}
```
##### Here is live example:
**Note:** some classes were mocked there and do not represent the exact implementations in libnd4j.
https://godbolt.org/z/sq98vchs5