Commit 9eef9f86 authored by Yedidya Feldblum's avatar Yedidya Feldblum Committed by Facebook GitHub Bot

operator symmetry for folly::dynamic

Summary: Symmetric operators are done using free or non-member operators. This ensures that whatever conversions could happen to the RHS can also happen to the LHS, symmetrically.

Reviewed By: philippv

Differential Revision: D31582089

fbshipit-source-id: ecae61bc810ee9538b1c2b738c58d4e9e01f1483
parent e2504d85
...@@ -67,25 +67,25 @@ TypeError::TypeError( ...@@ -67,25 +67,25 @@ TypeError::TypeError(
#define FB_DYNAMIC_APPLY(type, apply) \ #define FB_DYNAMIC_APPLY(type, apply) \
do { \ do { \
switch ((type)) { \ switch ((type)) { \
case NULLT: \ case dynamic::NULLT: \
apply(std::nullptr_t); \ apply(std::nullptr_t); \
break; \ break; \
case ARRAY: \ case dynamic::ARRAY: \
apply(Array); \ apply(dynamic::Array); \
break; \ break; \
case BOOL: \ case dynamic::BOOL: \
apply(bool); \ apply(bool); \
break; \ break; \
case DOUBLE: \ case dynamic::DOUBLE: \
apply(double); \ apply(double); \
break; \ break; \
case INT64: \ case dynamic::INT64: \
apply(int64_t); \ apply(int64_t); \
break; \ break; \
case OBJECT: \ case dynamic::OBJECT: \
apply(ObjectImpl); \ apply(dynamic::ObjectImpl); \
break; \ break; \
case STRING: \ case dynamic::STRING: \
apply(std::string); \ apply(std::string); \
break; \ break; \
default: \ default: \
...@@ -94,31 +94,34 @@ TypeError::TypeError( ...@@ -94,31 +94,34 @@ TypeError::TypeError(
} \ } \
} while (0) } while (0)
bool dynamic::operator<(dynamic const& o) const { bool operator<(dynamic const& a, dynamic const& b) {
if (UNLIKELY(type_ == OBJECT || o.type_ == OBJECT)) { constexpr auto obj = dynamic::OBJECT;
throw_exception<TypeError>("object", type_); if (UNLIKELY(a.type_ == obj || b.type_ == obj)) {
auto type = a.type_ == obj ? b.type_ : b.type_ == obj ? a.type_ : obj;
throw_exception<TypeError>("object", type);
} }
if (type_ != o.type_) { if (a.type_ != b.type_) {
return type_ < o.type_; return a.type_ < b.type_;
} }
#define FB_X(T) return CompareOp<T>::comp(*getAddress<T>(), *o.getAddress<T>()) #define FB_X(T) \
FB_DYNAMIC_APPLY(type_, FB_X); return dynamic::CompareOp<T>::comp(*a.getAddress<T>(), *b.getAddress<T>())
FB_DYNAMIC_APPLY(a.type_, FB_X);
#undef FB_X #undef FB_X
} }
bool dynamic::operator==(dynamic const& o) const { bool operator==(dynamic const& a, dynamic const& b) {
if (type() != o.type()) { if (a.type() != b.type()) {
if (isNumber() && o.isNumber()) { if (a.isNumber() && b.isNumber()) {
auto& integ = isInt() ? *this : o; auto& integ = a.isInt() ? a : b;
auto& doubl = isInt() ? o : *this; auto& doubl = a.isInt() ? b : a;
return integ.asInt() == doubl.asDouble(); return integ.asInt() == doubl.asDouble();
} }
return false; return false;
} }
#define FB_X(T) return *getAddress<T>() == *o.getAddress<T>(); #define FB_X(T) return *a.getAddress<T>() == *b.getAddress<T>();
FB_DYNAMIC_APPLY(type_, FB_X); FB_DYNAMIC_APPLY(a.type_, FB_X);
#undef FB_X #undef FB_X
} }
......
...@@ -60,8 +60,6 @@ ...@@ -60,8 +60,6 @@
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <boost/operators.hpp>
#include <folly/Expected.h> #include <folly/Expected.h>
#include <folly/Range.h> #include <folly/Range.h>
#include <folly/Traits.h> #include <folly/Traits.h>
...@@ -85,7 +83,7 @@ using detect_construct_string = decltype(std::string( ...@@ -85,7 +83,7 @@ using detect_construct_string = decltype(std::string(
FOLLY_DECLVAL(T const&).data(), FOLLY_DECLVAL(T const&).size())); FOLLY_DECLVAL(T const&).data(), FOLLY_DECLVAL(T const&).size()));
} }
struct dynamic : private boost::operators<dynamic> { struct dynamic {
enum Type { enum Type {
NULLT, NULLT,
ARRAY, ARRAY,
...@@ -223,13 +221,23 @@ struct dynamic : private boost::operators<dynamic> { ...@@ -223,13 +221,23 @@ struct dynamic : private boost::operators<dynamic> {
* "Deep" equality comparison. This will compare all the way down * "Deep" equality comparison. This will compare all the way down
* an object or array, and is potentially expensive. * an object or array, and is potentially expensive.
*/ */
bool operator==(dynamic const& o) const; friend bool operator==(dynamic const& a, dynamic const& b);
friend bool operator!=(dynamic const& a, dynamic const& b) {
return !(a == b);
}
/* /*
* For all types except object this returns the natural ordering on * For all types except object this returns the natural ordering on
* those types. For objects, we throw TypeError. * those types. For objects, we throw TypeError.
*/ */
bool operator<(dynamic const& o) const; friend bool operator<(dynamic const& a, dynamic const& b);
friend bool operator>(dynamic const& a, dynamic const& b) { return b < a; }
friend bool operator<=(dynamic const& a, dynamic const& b) {
return !(b < a);
}
friend bool operator>=(dynamic const& a, dynamic const& b) {
return !(a < b);
}
/* /*
* General operators. * General operators.
...@@ -251,6 +259,44 @@ struct dynamic : private boost::operators<dynamic> { ...@@ -251,6 +259,44 @@ struct dynamic : private boost::operators<dynamic> {
dynamic& operator++(); dynamic& operator++();
dynamic& operator--(); dynamic& operator--();
friend dynamic operator+(dynamic const& a, dynamic const& b) {
return std::move(copy(a) += b);
}
friend dynamic operator-(dynamic const& a, dynamic const& b) {
return std::move(copy(a) -= b);
}
friend dynamic operator*(dynamic const& a, dynamic const& b) {
return std::move(copy(a) *= b);
}
friend dynamic operator/(dynamic const& a, dynamic const& b) {
return std::move(copy(a) /= b);
}
friend dynamic operator%(dynamic const& a, dynamic const& b) {
return std::move(copy(a) %= b);
}
friend dynamic operator|(dynamic const& a, dynamic const& b) {
return std::move(copy(a) |= b);
}
friend dynamic operator&(dynamic const& a, dynamic const& b) {
return std::move(copy(a) &= b);
}
friend dynamic operator^(dynamic const& a, dynamic const& b) {
return std::move(copy(a) ^= b);
}
friend dynamic operator+(dynamic&& a, dynamic const& b) {
return std::move(a += b);
}
dynamic operator++(int) {
auto self = *this;
return ++*this, self;
}
dynamic operator-(int) {
auto self = *this;
return --*this, self;
}
/* /*
* Assignment from other dynamics. Because of the implicit conversion * Assignment from other dynamics. Because of the implicit conversion
* to dynamic from its potential types, you can use this to change the * to dynamic from its potential types, you can use this to change the
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment