// bslstl_unorderedsetkeyconfiguration.h                              -*-C++-*-
#ifndef INCLUDED_BSLSTL_UNORDEREDSETKEYCONFIGURATION
#define INCLUDED_BSLSTL_UNORDEREDSETKEYCONFIGURATION

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

//@PURPOSE: Provide a configuration class to use a whole object as its own key.
//
//@CLASSES:
//   bslstl::UnorderedSetKeyConfiguration: trivial identity transformation
//
//@SEE_ALSO: bslstl_unorderedmapkeyconfiguration, bslalg_hashtableimputil
//
//@DESCRIPTION: This component provides an identity transformation.
// `bslalg::HashTableImpUtil` has a static `extractKey` function template
// that, given a `value type`, will represent objects stored in a data
// structure, will abstract out the `key type` portion of that object.  In the
// case of the `unordered_set` data structure, the `key type` and the
// `value type` are one and the same, so the `extractKey` transformation is a
// trivial identity transformation.
//
///Usage
///-----
// This section illustrates intended use of this component.
//
///Example 1: Using Multiple Extractors to Sort an Array on Different Keys
///- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -
// Suppose we want to define a `sort` function which will work on a variety
// of different object types.  The object has to have a `key` within it,
// possibly the whole object, which will compare with the `key` of other
// objects with a transitive `<` operator.
//
// First, we define our function `mySort`, which takes two template args:
// `VALUE_TYPE`, the type of object being sorted, and `KEY_EXTRACTOR`, the
// utility class that will extra which part of the objects to be sorted is the
// key which will drive the sort:
// ```
// /// This function provides an order-preserving sort of the items in the
// /// range `[begin .. end)`, where `KEY_EXTRACTOR::extractKey` yields the
// /// key being sorted over.  We require that `VALUE_TYPE` support copy
// /// construction and assignment.
// template <class VALUE_TYPE, class KEY_EXTRACTOR>
// void mySort(VALUE_TYPE *begin, VALUE_TYPE *end, const KEY_EXTRACTOR&)
// {
//     while (begin < --end) {
//         for (VALUE_TYPE *it = begin; it < end; ++it) {
//             if (KEY_EXTRACTOR::extractKey(it[1]) <
//                                         KEY_EXTRACTOR::extractKey(it[0])) {
//                 // they're in the wrong order -- swap them
//
//                 VALUE_TYPE tmp(it[0]);
//                 it[0] = it[1];
//                 it[1] = tmp;
//             }
//         }
//
//         // '*end' is now the highest element in the range '[begin .. end]',
//         // so we only have to sort the elements before it in the next pass.
//     }
// }
// ```
// Then, we define `StudentRecord`, which keeps some vital statistics on
// students:
// ```
// struct StudentRecord {
//     const char *d_name;
//     double      d_gpa;
//     int         d_age;
// };
// ```
// Next, we define two extractors for `StudentRecord`, which will yield the
// `GPA` or `Age` fields:
// ```
// struct StudentRecordGPAExtractor {
//     static
//     const double& extractKey(const StudentRecord& record)
//     {
//         return record.d_gpa;
//     }
// };
//
// struct StudentRecordAgeExtractor {
//     static
//     const int& extractKey(const StudentRecord& record)
//     {
//         return record.d_age;
//     }
// };
// ```
// Then, in `main`, we create an array of `StudentRecord`s describing a set of
// students, with their names, GPA's, and ages.
// ```
// StudentRecord studentArray[] = {
//     { "Phil",  3.4, 19 },
//     { "Bob",   2.7, 20 },
//     { "Bill",  4.2, 21 },
//     { "Stan",  1.9, 18 },
//     { "Ann",   2.3, 21 },
//     { "Julie", 2.3, 20 } };
// const int NUM_STUDENTS = sizeof studentArray / sizeof *studentArray;
// ```
// Next, using our GPA extractor and our `mySort` function, we sort the
// students by GPA:
// ```
// StudentRecordGPAExtractor gpaExtractor;
//
// mySort(studentArray + 0,
//        studentArray + NUM_STUDENTS,
//        gpaExtractor);
// ```
// Then, we print out the sorted array of students:
// ```
// if (verbose) {
//     printf("\nList of students, lowest GPA first:\n");
//     printf(  "===================================\n");
//
//     printf("Name   GPA  AGE\n"
//            "-----  ---  ---\n");
//     for (int i = 0; i < NUM_STUDENTS; ++i) {
//         const StudentRecord& record = studentArray[i];
//
//         printf("%-5s  %g  %3d\n", record.d_name,
//                                   record.d_gpa,
//                                   record.d_age);
//     }
// }
// ```
// The output produced is:
// ```
// List of students, lowest GPA first:
// ===================================
//                             Name   GPA  AGE
// -----  ---  ---
// Stan   1.9   18
// Ann    2.3   21
// Julie  2.3   20
// Bob    2.7   20
// Phil   3.4   19
// Bill   4.2   21
// ```
// Note that Ann and Julie, who have the same GPA, are still in the same order
// as they were before the sort, as `mySort` was an order-preserving sort:
//
// Next, we sort by age with our age extractor, and print out the results:
// ```
// StudentRecordAgeExtractor ageExtractor;
//
// mySort(studentArray + 0,
//        studentArray + NUM_STUDENTS,
//        ageExtractor);
//
// if (verbose) {
//     printf("\nList of students, youngest first:\n");
//     printf(  "================================\n");
//
//     printf("Name   GPA  AGE\n"
//            "-----  ---  ---\n");
//     for (int i = 0; i < NUM_STUDENTS; ++i) {
//         const StudentRecord& record = studentArray[i];
//
//         printf("%-5s  %g  %3d\n", record.d_name,
//                                   record.d_gpa,
//                                   record.d_age);
//     }
// }
// ```
// The output is:
// ```
// List of students, youngest first:
// ================================
//                             Name   GPA  AGE
// -----  ---  ---
// Stan   1.9   18
// Phil   3.4   19
// Julie  2.3   20
// Bob    2.7   20
// Ann    2.3   21
// Bill   4.2   21
// ```
// Note again, the ordering of students with identical ages is preserved.
//
// Then, we define an array full of integers to be sorted.
// ```
// int intArray[] = { 8, 3728, 2919, 27438, -2837, 18282, 34, -3 };
// const int NUM_INTS = sizeof intArray / sizeof *intArray;
// ```
// Next, we want to sort the integers.  In this case, the key being sorted on
// is the whole `int`, so we use `bslstl::UnorderedSetKeyConfiguration<int>` as
// our extractor:
// ```
// bslstl::UnorderedSetKeyConfiguration<int> intExtractor;
// ```
// Now, we sort the array using our `sort` function and the extractor, and
// printout out the sorted array:
// ```
// mySort(intArray + 0, intArray + NUM_INTS, intExtractor);
//
// if (verbose) {
//     printf("\nSorted integer array:\n"
//              "====================\n");
//
//     for (int i = 0; i < NUM_INTS; ++i) {
//         printf("%s%d", (i ? ", " : ""), intArray[i]);
//     }
//     printf("\n");
// }
// ```
// Finally, we observe that the output produced is:
// ```
// Sorted integer array:
// ====================
// -2837, -3, 8, 34, 2919, 3728, 18282, 27438
// ```

#include <bslscm_version.h>

namespace BloombergLP {

namespace bslstl {

                       // ===================================
                       // struct UnorderedSetKeyConfiguration
                       // ===================================

template <class VALUE_TYPE>
struct UnorderedSetKeyConfiguration {
  public:
    typedef VALUE_TYPE ValueType;
    typedef ValueType  KeyType;

    // Choosing to implement for each configuration, to reduce the template
    // mess.  With only two policies, not much is saved using a shared
    // dependent base class to provide a common implementation.

    // CLASS METHODS

    /// Given a specified `object`, return a reference to the `KeyType`
    /// contained within that object.  In this case, the `KeyType` returned
    /// is simply the object itself.
    static const KeyType& extractKey(const VALUE_TYPE& object);
};

// ============================================================================
//                  TEMPLATE AND INLINE FUNCTION DEFINITIONS
// ============================================================================

                      //------------------------------------
                      // struct UnorderedSetKeyConfiguration
                      //------------------------------------


template <class VALUE_TYPE>
inline
const typename UnorderedSetKeyConfiguration<VALUE_TYPE>::KeyType&
UnorderedSetKeyConfiguration<VALUE_TYPE>::extractKey(const VALUE_TYPE& object)
{
    return object;
}

}  // close package namespace

}  // close enterprise namespace

#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 ----------------------------------
