// 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:
//..
//  template <typename TYPE, typename EQUALS = bsl::equal_to<TYPE> >
//  class ListSet {
//      // 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.
//
//      // 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
//      explicit
//      ListSet(bslma::Allocator *allocator = 0)
//      : d_comparator()
//      , d_nodeList(0)
//      , d_allocator_p(bslma::Default::allocator(allocator))
//          // Create an empty "ListSet' using the specified 'allocator', or
//          // the default allocator if none is specified.
//      {}
//
//      ~ListSet()
//          // Release all memory used by this 'ListSet'
//      {
//          for (Node *node = d_nodeList; node; ) {
//              Node *toDelete = node;
//              node = node->d_next;
//
//              d_allocator_p->deleteObject(toDelete);
//          }
//      }
//
//      // MANIPULATOR
//      bool insert(const TYPE& value)
//          // If 'value' isn't contained in this 'ListSet', add it and return
//          // 'true', otherwise, return 'false' with no change to the
//          // 'ListSet'.
//      {
//          if (count(value)) {
//              return false;                                         // RETURN
//          }
//
//          Node *node = (Node *) d_allocator_p->allocate(sizeof(Node));
//          bslma::ConstructionUtil::construct(&node->d_value,
//                                             d_allocator_p,
//                                             value);
//          node->d_next = d_nodeList;
//          d_nodeList = node;
//
//          return true;
//      }
//
//      int count(const TYPE& value) const
//          // Return the number of nodes whose 'd_value' field is equivalent
//          // to the specified 'value', which will always be 0 or 1.
//      {
//          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 *'.
//..
//  class StringThing {
//      // 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.
//
//      // DATA
//      const char *d_string;    // held, not owned
//
//    public:
//      // CREATOR
//      StringThing(const char *string)                             // IMPLICIT
//      : d_string(string)
//          // Create a 'StringThing' object out of the specified 'string'.
//      {}
//
//      // ACCESSOR
//      operator const char *() const
//          // Implicitly cast this 'StringThing' object to a 'const char *'
//          // that refers to the same buffer.
//      {
//          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
                       // ===============

template<class VALUE_TYPE = void>
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.

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

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

    //! equal_to(const equal_to& original) = 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() = default;
        // Destroy this object.

    // MANIPULATORS
    //! equal_to& operator=(const equal_to&) = default;
        // 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.

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

template<>
struct equal_to<void> {
    // 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.

    // PUBLIC TYPES
    typedef void is_transparent;

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

    //! equal_to(const equal_to& original) = 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() = default;
        // Destroy this object.

    // MANIPULATORS
    //! equal_to& operator=(const equal_to&) = default;
        // 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.

    // ACCESSORS
#if BSLS_COMPILERFEATURES_CPLUSPLUS >= 201103L
    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 '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)'.
    { return            std::forward<TYPE1>(lhs) == std::forward<TYPE2>(rhs); }
#else
    template<class TYPE1, class TYPE2>
    inline bool operator()(const TYPE1& lhs, const TYPE2& rhs) const
        // 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).
    {
        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 ----------------------------------