blob: e0209704d6d651445308cd9cabf55bddeeb51e91 [file] [log] [blame]
// Copyright 2018 The Fuchsia Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
#ifndef LIB_FIDL_CPP_COMPARISON_H_
#define LIB_FIDL_CPP_COMPARISON_H_
#include <array>
#include <cstdint>
#include <map>
#include <memory>
#include <string>
#include <type_traits>
#include <utility>
#include <vector>
#include "lib/fidl/cpp/types.h"
#ifdef __Fuchsia__
#include <lib/zx/object.h>
#endif
// Comparisons that uses structure equality on on std::unique_ptr instead of
// pointer equality.
namespace fidl {
template <class T>
bool Equals(const T& lhs, const T& rhs);
template <typename T, typename = void>
struct Equality {};
template <class T>
struct Equality<T, typename std::enable_if_t<std::is_integral<T>::value>> {
constexpr bool operator()(const T& lhs, const T& rhs) const { return lhs == rhs; }
};
template <class T>
struct Equality<T, typename std::enable_if_t<std::is_floating_point<T>::value>> {
constexpr bool operator()(const T& lhs, const T& rhs) const {
// TODO(ianloic): do something better for floating point comparison?
return lhs == rhs;
}
};
#ifdef __Fuchsia__
template <class T>
struct Equality<T, typename std::enable_if_t<std::is_base_of<zx::object_base, T>::value>> {
bool operator()(const T& lhs, const T& rhs) const { return lhs.get() == rhs.get(); }
};
#endif // __Fuchsia__
template <typename T, size_t N>
struct Equality<std::array<T, N>> {
// N.B.: This may be constexpr-able in C++20.
bool operator()(const std::array<T, N>& lhs, const std::array<T, N>& rhs) const {
return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), ::fidl::Equality<T>{});
}
};
template <>
struct Equality<std::string> {
bool operator()(const std::string& lhs, const std::string& rhs) const { return lhs == rhs; }
};
template <class T>
struct Equality<std::vector<T>> {
bool operator()(const std::vector<T>& lhs, const std::vector<T>& rhs) const {
if (lhs.size() != rhs.size()) {
return false;
}
return std::equal(lhs.cbegin(), lhs.cend(), rhs.cbegin(), rhs.cend(), ::fidl::Equality<T>{});
}
};
template <class T>
struct Equality<std::unique_ptr<T>> {
constexpr bool operator()(const std::unique_ptr<T>& lhs, const std::unique_ptr<T>& rhs) const {
if (lhs == nullptr || rhs == nullptr) {
return rhs == lhs;
}
return ::fidl::Equality<T>{}(*lhs, *rhs);
}
};
template <>
struct Equality<UnknownBytes> {
bool operator()(const UnknownBytes& lhs, const UnknownBytes& rhs) const {
return ::fidl::Equality<std::vector<uint8_t>>{}(lhs.bytes, rhs.bytes);
}
};
template <>
struct Equality<std::map<uint64_t, std::vector<uint8_t>>> {
bool operator()(const std::map<uint64_t, std::vector<uint8_t>>& lhs,
const std::map<uint64_t, std::vector<uint8_t>>& rhs) const {
return lhs == rhs;
}
};
#ifdef __Fuchsia__
template <>
struct Equality<UnknownData> {
bool operator()(const UnknownData& lhs, const UnknownData& rhs) const {
return ::fidl::Equality<std::vector<uint8_t>>{}(lhs.bytes, rhs.bytes) &&
::fidl::Equality<std::vector<zx::handle>>{}(lhs.handles, rhs.handles);
}
};
template <>
struct Equality<std::map<uint64_t, UnknownData>> {
bool operator()(const std::map<uint64_t, UnknownData>& lhs,
const std::map<uint64_t, UnknownData>& rhs) const {
if (lhs.size() != rhs.size()) {
return false;
}
auto l = lhs.cbegin();
auto r = rhs.cbegin();
while (l != lhs.cend()) {
if (!Equals(l->first, r->first) || !Equals(l->second, r->second)) {
return false;
}
std::advance(l, 1);
std::advance(r, 1);
}
return true;
}
};
#endif
template <class T>
bool Equals(const T& lhs, const T& rhs) {
return ::fidl::Equality<T>{}(lhs, rhs);
}
} // namespace fidl
#endif // LIB_FIDL_CPP_COMPARISON_H_