// 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: //.. // template <class VALUE_TYPE, class KEY_EXTRACTOR> // void mySort(VALUE_TYPE *begin, VALUE_TYPE *end, const KEY_EXTRACTOR&) // // 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. // { // 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 static const KeyType& extractKey(const VALUE_TYPE& object); // 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. }; // ============================================================================ // 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 ----------------------------------