// bslstl_equalto.h                                                   -*-C++-*-
#ifndef INCLUDED_BSLSTL_EQUALTO
#define INCLUDED_BSLSTL_EQUALTO

#include <bsls_ident.h>
BSLS_IDENT("$Id: $")

//@PURPOSE: Provide a binary functor conforming to the C++11 `equal_to` spec.
//
//@CLASSES:
//  equal_to: C++11-compliant binary functor applying `operator==`
//
//@CANONICAL_HEADER: bsl_functional.h
//
//@SEE_ALSO: bslstl_unorderedmap, bslstl_unorderedset
//
//@DESCRIPTION: This component provides the C+11 standard binary comparison
// functor, `bsl::equal_to`, that evaluates equality of two `VALUE_TYPE`
// objects through the `operator==`.  The application of the functor to two
// different objects `o1` and `o2` returns true if `o1 == o2`.  Note that this
// the for use as keys in the standard unordered associative containers such as
// `bsl::unordered_map` and `bsl::unordered_set`.  Also note that this class is
// an empty POD type.
//
///Usage
///-----
// This section illustrates intended usage of this component.
//
///Example 1: Creating and Using a List Set
/// - - - - - - - - - - - - - - - - - - - -
// Suppose we want to keep a set of a small number of elements, and the only
// comparison operation we have on the type of the elements is an equality
// operator.  We can keep a singly-linked list of the elements, and
// exhaustively use the comparison operator to see if a given value exists in
// the list, forming a primitive set.
//
// First, we define our `ListSet` template class:
// ```
// /// This class implements a crude implementation of a set, that will
// /// keep a set of values and be able to determine if an element is a
// /// member of the set.  Unlike a `bsl::set` or `bsl::unordered_set`, no
// /// hash function or transitive `operator<` is required -- only a
// /// transitive `EQUALS` operator.
// ///
// /// The `TYPE` template parameter must have a public copy constructor
// /// and destructor available.
// ///
// /// The `EQUALS` template parameter must a function with a function
// /// whose signature is
// ///...
// ///  bool operator()(const TYPE& lhs, const TYPE& rhs) const;
// /// ```
// /// and which returns `true` if `lhs` and `rhs` are equivalent and
// /// `false` otherwise.  This equivalence relation must be transitive and
// /// symmetric.  The comparator must have a default constructor and
// /// destructor which are public.
// template <typename TYPE, typename EQUALS = bsl::equal_to<TYPE> >
// class ListSet {
//
//     // PRIVATE TYPES
//     struct Node {
//         TYPE  d_value;
//         Node *d_next;
//     };
//
//     // DATA
//     EQUALS            d_comparator;
//     Node             *d_nodeList;
//     bslma::Allocator *d_allocator_p;
//
//   private:
//     // NOT IMPLEMENTED
//     ListSet(const ListSet&);
//     ListSet& operator=(const ListSet&);
//
//   public:
//     // CREATORS
//
//     /// Create an empty `ListSet` using the specified `allocator`, or
//     /// the default allocator if none is specified.
//     explicit
//     ListSet(bslma::Allocator *allocator = 0)
//     : d_comparator()
//     , d_nodeList(0)
//     , d_allocator_p(bslma::Default::allocator(allocator))
//     {}
//
//     /// Release all memory used by this `ListSet`
//     ~ListSet()
//     {
//         for (Node *node = d_nodeList; node; ) {
//             Node *toDelete = node;
//             node = node->d_next;
//
//             d_allocator_p->deleteObject(toDelete);
//         }
//     }
//
//     // MANIPULATOR
//
//     /// If `value` isn't contained in this `ListSet`, add it and return
//     /// `true`, otherwise, return `false` with no change to the
//     /// `ListSet`.
//     bool insert(const TYPE& value)
//     {
//         if (count(value)) {
//             return false;                                         // RETURN
//         }
//
//         Node *node =
//                  bslma::AllocatorUtil::allocateObject<Node>(d_allocator_p);
//         bslma::ConstructionUtil::construct(&node->d_value,
//                                            d_allocator_p,
//                                            value);
//         node->d_next = d_nodeList;
//         d_nodeList = node;
//
//         return true;
//     }
//
//     /// Return the number of nodes whose `d_value` field is equivalent
//     /// to the specified `value`, which will always be 0 or 1.
//     int count(const TYPE& value) const
//     {
//         for (Node *node = d_nodeList; node; node = node->d_next) {
//             if (d_comparator(node->d_value, value)) {
//                 return 1;                                         // RETURN
//             }
//         }
//
//         return 0;
//     }
// };
// ```
// Then, in `main`, we declare an instance of `ListSet` storing `int`s.  The
// default definition of `bsl::equal_to` will work nicely:
// ```
// ListSet<int> lsi;
// ```
// Now, we insert several values into our `ListSet`.  Note that successful
// insertions return `true` while redundant ones return `false` with no effect:
// ```
// assert(true  == lsi.insert( 5));
// assert(false == lsi.insert( 5));
// assert(false == lsi.insert( 5));
// assert(true  == lsi.insert(11));
// assert(true  == lsi.insert(17));
// assert(true  == lsi.insert(81));
// assert(true  == lsi.insert(32));
// assert(false == lsi.insert(17));
// ```
// Finally, we observe that our `count` method successfully distinguishes
// between values that have been stored in our `ListSet` and those that
// haven't:
// ```
// assert(0 == lsi.count( 7));
// assert(1 == lsi.count( 5));
// assert(0 == lsi.count(13));
// assert(1 == lsi.count(11));
// assert(0 == lsi.count(33));
// assert(1 == lsi.count(32));
// ```
//
///Example 2: Using Our List Set For a Custom Type
///- - - - - - - - - - - - - - - - - - - - - - - -
// Suppose we want to have a list set containing objects of a custom type.  We
// can declare an `operator==` for our custom type, and `equal_to` will use
// that.  We will re-use the `ListSet` template class from example 1, and
// create a new custom type.
//
// First, we define a type `StringThing`, which will contain a `const char *`
// pointer, it will be a very simple type, that is implicitly castable to or
// from a `const char *`.
// ```
// /// This class holds a pointer to zero-terminated string.  It is
// /// implicitly convertible to and from a `const char *`.  The difference
// /// between this type and a `const char *` is that `operator==` will
// /// properly compare two objects of this type for equality of strings
// /// rather than equality of pointers.
// class StringThing {
//
//     // DATA
//     const char *d_string;    // held, not owned
//
//   public:
//     // CREATOR
//
//     /// Create a `StringThing` object out of the specified `string`.
//     StringThing(const char *string)                             // IMPLICIT
//     : d_string(string)
//     {}
//
//     // ACCESSOR
//
//     /// Implicitly cast this `StringThing` object to a `const char *`
//     /// that refers to the same buffer.
//     operator const char *() const
//     {
//         return d_string;
//     }
// };
// ```
// Then, we create an `operator==` for StringThings
// ```
//
//   bool operator==(const StringThing& lhs, const StringThing& rhs)
//       {
//           return !strcmp(lhs, rhs);
//       }
//
// ```
// Next, in `main`, we declare a `ListSet` containing `StringThing`s:
// ```
// ListSet<StringThing> lsst;
// ```
// Then, we insert a number of values, and observe that redundant inserts
// return `false` with no effect:
// ```
// assert(true  == lsst.insert("woof"));
// assert(true  == lsst.insert("meow"));
// assert(true  == lsst.insert("arf"));
// assert(false == lsst.insert("woof"));
// assert(true  == lsst.insert("bark"));
// assert(false == lsst.insert("meow"));
// assert(false == lsst.insert("woof"));
// ```
// Now, we observe that our `count` method successfully distinguishes between
// values that have been stored in `lsst` and those that haven't:
// ```
// assert(1 == lsst.count("meow"));
// assert(0 == lsst.count("woo"));
// assert(1 == lsst.count("woof"));
// assert(1 == lsst.count("arf"));
// assert(0 == lsst.count("chomp"));
// ```
// Finally, we copy values into a buffer and observe that this makes no
// difference to `count`s results:
// ```
// char buffer[10];
// strcpy(buffer, "meow");
// assert(1 == lsst.count(buffer));
// strcpy(buffer, "bite");
// assert(0 == lsst.count(buffer));
// ```

#include <bslscm_version.h>

#include <bsls_compilerfeatures.h>
#include <bsls_keyword.h>

#include <bsla_nodiscard.h>

#include <bslmf_istriviallycopyable.h>
#include <bslmf_istriviallydefaultconstructible.h>

#include <utility> // for std::forward

namespace bsl {

                       // ===============
                       // struct equal_to
                       // ===============

/// This `struct` defines a binary comparison functor applying `operator==`
/// to two `VALUE_TYPE` objects.  This class conforms to the C++11 standard
/// specification of `std::equal_to` that does not require inheriting from
/// `std::binary_function`.  Note that this class is an empty POD type.
template<class VALUE_TYPE = void>
struct equal_to {

    // PUBLIC TYPES
    typedef VALUE_TYPE first_argument_type;
    typedef VALUE_TYPE second_argument_type;
    typedef bool       result_type;

    /// Create a `equal_to` object.
    //! equal_to() = default;

    /// Create a `equal_to` object.  Note that as `equal_to` is an empty
    /// (stateless) type, this operation will have no observable effect.
    //! equal_to(const equal_to& original) = default;

    /// Destroy this object.
    //! ~equal_to() = default;

    // MANIPULATORS

    /// Assign to this object the value of the specified `rhs` object, and
    /// a return a reference providing modifiable access to this object.
    /// Note that as `equal_to` is an empty (stateless) type, this operation
    /// will have no observable effect.
    //! equal_to& operator=(const equal_to&) = default;

    // ACCESSORS

    /// Return `true` if the specified `lhs` compares equal to the specified
    /// `rhs` using the equality-comparison operator, `lhs == rhs`.
    BSLA_NODISCARD BSLS_KEYWORD_CONSTEXPR bool
    operator()(const VALUE_TYPE& lhs, const VALUE_TYPE& rhs) const;
};

/// This `struct` defines a binary comparison functor applying `operator==`
/// to two objects of (possibly different) types.  Note that this class is
/// an empty POD type.
template<>
struct equal_to<void> {

    // PUBLIC TYPES
    typedef void is_transparent;

    /// Create a `equal_to` object.
    //! equal_to() = default;

    /// Create a `equal_to` object.  Note that as `equal_to<void>` is an
    /// empty (stateless) type, this operation will have no observable
    /// effect.
    //! equal_to(const equal_to& original) = default;

    /// Destroy this object.
    //! ~equal_to() = default;

    // MANIPULATORS

    /// Assign to this object the value of the specified `rhs` object, and
    /// a return a reference providing modifiable access to this object.
    /// Note that as `equal_to` is an empty (stateless) type, this
    /// operation will have no observable effect.
    //! equal_to& operator=(const equal_to&) = default;

    // ACCESSORS
#if BSLS_COMPILERFEATURES_CPLUSPLUS >= 201103L
    /// Return `true` if the specified `lhs` compares equal to the specified
    /// `rhs` using the equality-comparison operator, `lhs == rhs`.
    /// Implemented inline because of all the duplication of
    /// `std::forward<TYPE1>(lhs) == std::forward<TYPE2>(rhs)`.
    template<class TYPE1, class TYPE2>
    BSLA_NODISCARD BSLS_KEYWORD_CONSTEXPR inline
    auto operator()(TYPE1&& lhs, TYPE2&& rhs) const
      noexcept(noexcept(std::forward<TYPE1>(lhs) == std::forward<TYPE2>(rhs)))
      -> decltype(      std::forward<TYPE1>(lhs) == std::forward<TYPE2>(rhs))
    { return            std::forward<TYPE1>(lhs) == std::forward<TYPE2>(rhs); }
#else
    /// Return `true` if the specified `lhs` compares equal to the specified
    /// `rhs` using the equality-comparison operator, `lhs == rhs`.
    /// Implemented inline because of compiler errors (AIX, SUN).
    template<class TYPE1, class TYPE2>
    inline bool operator()(const TYPE1& lhs, const TYPE2& rhs) const
    {
        return lhs == rhs;
    }
#endif
};

}  // close namespace bsl

namespace bsl {

// ============================================================================
//                      INLINE FUNCTION DEFINITIONS
// ============================================================================

                       // --------------------
                       // struct bsl::equal_to
                       // --------------------

// ACCESSORS
template<class VALUE_TYPE>
BSLA_NODISCARD BSLS_KEYWORD_CONSTEXPR inline
bool equal_to<VALUE_TYPE>::operator()(const VALUE_TYPE& lhs,
                                      const VALUE_TYPE& rhs) const
{
    return lhs == rhs;
}
}  // close namespace bsl

// ============================================================================
//                                TYPE TRAITS
// ============================================================================

// Type traits for 'equal_to'
//: o 'equal_to' is a stateless POD, trivially constructible, copyable, and
//:   moveable.

namespace bsl {

template<class VALUE_TYPE>
struct is_trivially_default_constructible<equal_to<VALUE_TYPE> >
: bsl::true_type
{};

template<class VALUE_TYPE>
struct is_trivially_copyable<equal_to<VALUE_TYPE> >
: bsl::true_type
{};

}  // close namespace bsl

#endif

// ----------------------------------------------------------------------------
// Copyright 2013 Bloomberg Finance L.P.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
// ----------------------------- END-OF-FILE ----------------------------------
