// bslstl_unorderedmapkeyconfiguration.h -*-C++-*- #ifndef INCLUDED_BSLSTL_UNORDEREDMAPKEYCONFIGURATION #define INCLUDED_BSLSTL_UNORDEREDMAPKEYCONFIGURATION #include <bsls_ident.h> BSLS_IDENT("$Id: $") //@PURPOSE: Provide a class template to extract keys as the 'first' attribute. // //@CLASSES: // bslalg::UnorderedMapKeyConfiguration : extracts 'key' from 'value' type // //@SEE_ALSO: bslalg_hashtableimputil // //@DESCRIPTION: This component will, given an object of a value type consisting // of a key type and some other information, return a const reference to only // the key type within that object. The object passed will be of parameterized // type 'VALUE_TYPE', for which a type 'VALUE_TYPE::first_type' must be // defined and be of the key type, and for which the operation '.first' must be // defined and must yield the object of the key type. // // '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_map' data structure, the 'value type' will be 'bsl::pair', and // the key type will 'bsl::pair::first_type'. // ///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, suppose we are storing information about employees in 'MyPair' // objects, where 'first' is a double storing the employees hourly wage, and // 'second' in the employee's name. Suppose we want to sort the employees by // their hourly wages, which is the '.first' field of the pair. // // We declare our employee pair type: //.. // typedef MyPair<double, const char *> EmployeePair; //.. // Next, we define an array of employee pairs for employees' wages and names: //.. // EmployeePair employees[] = { // { 12.25, "Kyle" }, // { 15.00, "Eric" }, // { 12.25, "Stan" }, // { 7.75, "Kenny" } }; // const int NUM_EMPLOYEES = sizeof employees / sizeof *employees; //.. // Then, we create an 'UnorderedMapKeyConfiguration' type parameterized on // 'EmployeePair', which will extract the '.first' field, which is the wage, // from an employee pair: //.. // bslstl::UnorderedMapKeyConfiguration<EmployeePair> wageExtractor; //.. // Next, we sort: //.. // mySort(employees + 0, employees + NUM_EMPLOYEES, wageExtractor); //.. // Now, we print out our results: //.. // if (verbose) { // printf("\nList of employees, cheapest first:\n" // "==================================\n"); // // printf("Name Wage\n" // "----- -----\n"); // // for (int i = 0; i < NUM_EMPLOYEES; ++i) { // const EmployeePair& employee = employees[i]; // // printf("%-5s %5.2f\n", employee.second, employee.first); // } // } //.. // Finally, we see our output. Note that the ordering of Kyle and Stan, who // are paid the same wage, is preserved. //.. // List of employees, cheapest first: // ================================== // Name Wage // ----- ----- // Kenny 7.75 // Kyle 12.25 // Stan 12.25 // Eric 15.00 //.. #include <bslscm_version.h> namespace BloombergLP { namespace bslstl { // =================================== // struct UnorderedMapKeyConfiguration // =================================== template <class KEY, class VALUE_TYPE> struct UnorderedMapKeyConfiguration { public: typedef VALUE_TYPE ValueType; typedef KEY 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. This is the // key abstraction, turning 'bslalg::BidirectionalLink*' into 'VALUE_TYPE&' // CLASS METHODS static const KeyType& extractKey(const VALUE_TYPE& obj); // Return the member 'first' of the specified object 'obj'. // 'obj.first' must be of type 'VALUE_TYPE::first_type', which is the // 'key' portion of 'obj'. }; // ============================================================================ // TEMPLATE AND INLINE FUNCTION DEFINITIONS // ============================================================================ //----------------------------------- // class UnorderedMapKeyConfiguration //----------------------------------- // CLASS METHODS template <class KEY, class VALUE_TYPE> inline const KEY& UnorderedMapKeyConfiguration<KEY, VALUE_TYPE>::extractKey(const VALUE_TYPE& obj) { return obj.first; } } // 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 ----------------------------------