| 218 | } |
| 219 | |
| 220 | bool Expression::Equals(const Expression& other) const { |
| 221 | if (Expression::Identical(*this, other)) return true; |
| 222 | |
| 223 | if (impl_ == nullptr || other.impl_ == nullptr) return false; |
| 224 | |
| 225 | if (impl_->index() != other.impl_->index()) { |
| 226 | return false; |
| 227 | } |
| 228 | |
| 229 | if (auto lit = literal()) { |
| 230 | // The scalar NaN is not equal to the scalar NaN but the literal NaN |
| 231 | // is equal to the literal NaN (e.g. the expressions are equal even if |
| 232 | // the values are not) |
| 233 | EqualOptions equal_options = EqualOptions::Defaults().nans_equal(true); |
| 234 | return lit->scalar()->Equals(*other.literal()->scalar(), equal_options); |
| 235 | } |
| 236 | |
| 237 | if (auto ref = field_ref()) { |
| 238 | return ref->Equals(*other.field_ref()); |
| 239 | } |
| 240 | |
| 241 | auto call = CallNotNull(*this); |
| 242 | auto other_call = CallNotNull(other); |
| 243 | |
| 244 | if (call->function_name != other_call->function_name || |
| 245 | call->kernel != other_call->kernel) { |
| 246 | return false; |
| 247 | } |
| 248 | |
| 249 | for (size_t i = 0; i < call->arguments.size(); ++i) { |
| 250 | if (!call->arguments[i].Equals(other_call->arguments[i])) { |
| 251 | return false; |
| 252 | } |
| 253 | } |
| 254 | |
| 255 | if (call->options == other_call->options) return true; |
| 256 | if (call->options && other_call->options) { |
| 257 | return call->options->Equals(*other_call->options); |
| 258 | } |
| 259 | return false; |
| 260 | } |
| 261 | |
| 262 | bool Expression::Identical(const Expression& l, const Expression& r) { |
| 263 | return l.impl_ == r.impl_; |
no test coverage detected