// util/stl-utils.h // Copyright 2009-2011 Microsoft Corporation; Saarland University // See ../../COPYING for clarification regarding multiple authors // // 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 // // THIS CODE IS PROVIDED *AS IS* BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY // KIND, EITHER EXPRESS OR IMPLIED, INCLUDING WITHOUT LIMITATION ANY IMPLIED // WARRANTIES OR CONDITIONS OF TITLE, FITNESS FOR A PARTICULAR PURPOSE, // MERCHANTABLITY OR NON-INFRINGEMENT. // See the Apache 2 License for the specific language governing permissions and // limitations under the License. #ifndef KALDI_UTIL_STL_UTILS_H_ #define KALDI_UTIL_STL_UTILS_H_ #include #include using std::unordered_map; using std::unordered_set; #include #include #include #include #include #include "base/kaldi-common.h" namespace kaldi { /// Sorts and uniq's (removes duplicates) from a vector. template inline void SortAndUniq(std::vector *vec) { std::sort(vec->begin(), vec->end()); vec->erase(std::unique(vec->begin(), vec->end()), vec->end()); } /// Returns true if the vector is sorted. template inline bool IsSorted(const std::vector &vec) { typename std::vector::const_iterator iter = vec.begin(), end = vec.end(); if (iter == end) return true; while (1) { typename std::vector::const_iterator next_iter = iter; ++next_iter; if (next_iter == end) return true; // end of loop and nothing out of order if (*next_iter < *iter) return false; iter = next_iter; } } /// Returns true if the vector is sorted and contains each element /// only once. template inline bool IsSortedAndUniq(const std::vector &vec) { typename std::vector::const_iterator iter = vec.begin(), end = vec.end(); if (iter == end) return true; while (1) { typename std::vector::const_iterator next_iter = iter; ++next_iter; if (next_iter == end) return true; // end of loop and nothing out of order if (*next_iter <= *iter) return false; iter = next_iter; } } /// Removes duplicate elements from a sorted list. template inline void Uniq(std::vector *vec) { // must be already sorted. KALDI_PARANOID_ASSERT(IsSorted(*vec)); KALDI_ASSERT(vec); vec->erase(std::unique(vec->begin(), vec->end()), vec->end()); } /// Copies the elements of a set to a vector. template void CopySetToVector(const std::set &s, std::vector *v) { // copies members of s into v, in sorted order from lowest to highest // (because the set was in sorted order). KALDI_ASSERT(v != NULL); v->resize(s.size()); typename std::set::const_iterator siter = s.begin(), send = s.end(); typename std::vector::iterator viter = v->begin(); for (; siter != send; ++siter, ++viter) { *viter = *siter; } } template void CopySetToVector(const unordered_set &s, std::vector *v) { KALDI_ASSERT(v != NULL); v->resize(s.size()); typename unordered_set::const_iterator siter = s.begin(), send = s.end(); typename std::vector::iterator viter = v->begin(); for (; siter != send; ++siter, ++viter) { *viter = *siter; } } /// Copies the (key, value) pairs in a map to a vector of pairs. template void CopyMapToVector(const std::map &m, std::vector > *v) { KALDI_ASSERT(v != NULL); v->resize(m.size()); typename std::map::const_iterator miter = m.begin(), mend = m.end(); typename std::vector >::iterator viter = v->begin(); for (; miter != mend; ++miter, ++viter) { *viter = std::make_pair(miter->first, miter->second); // do it like this because of const casting. } } /// Copies the keys in a map to a vector. template void CopyMapKeysToVector(const std::map &m, std::vector *v) { KALDI_ASSERT(v != NULL); v->resize(m.size()); typename std::map::const_iterator miter = m.begin(), mend = m.end(); typename std::vector::iterator viter = v->begin(); for (; miter != mend; ++miter, ++viter) { *viter = miter->first; } } /// Copies the values in a map to a vector. template void CopyMapValuesToVector(const std::map &m, std::vector *v) { KALDI_ASSERT(v != NULL); v->resize(m.size()); typename std::map::const_iterator miter = m.begin(), mend = m.end(); typename std::vector::iterator viter = v->begin(); for (; miter != mend; ++miter, ++viter) { *viter = miter->second; } } /// Copies the keys in a map to a set. template void CopyMapKeysToSet(const std::map &m, std::set *s) { KALDI_ASSERT(s != NULL); s->clear(); typename std::map::const_iterator miter = m.begin(), mend = m.end(); for (; miter != mend; ++miter) { s->insert(s->end(), miter->first); } } /// Copies the values in a map to a set. template void CopyMapValuesToSet(const std::map &m, std::set *s) { KALDI_ASSERT(s != NULL); s->clear(); typename std::map::const_iterator miter = m.begin(), mend = m.end(); for (; miter != mend; ++miter) s->insert(s->end(), miter->second); } /// Copies the contents of a vector to a set. template void CopyVectorToSet(const std::vector &v, std::set *s) { KALDI_ASSERT(s != NULL); s->clear(); typename std::vector::const_iterator iter = v.begin(), end = v.end(); for (; iter != end; ++iter) s->insert(s->end(), *iter); // s->end() is a hint in case v was sorted. will work regardless. } /// Deletes any non-NULL pointers in the vector v, and sets /// the corresponding entries of v to NULL template void DeletePointers(std::vector *v) { KALDI_ASSERT(v != NULL); typename std::vector::iterator iter = v->begin(), end = v->end(); for (; iter != end; ++iter) { if (*iter != NULL) { delete *iter; *iter = NULL; // set to NULL for extra safety. } } } /// Returns true if the vector of pointers contains NULL pointers. template bool ContainsNullPointers(const std::vector &v) { typename std::vector::const_iterator iter = v.begin(), end = v.end(); for (; iter != end; ++iter) if (*iter == static_cast (NULL)) return true; return false; } /// Copies the contents a vector of one type to a vector /// of another type. template void CopyVectorToVector(const std::vector &vec_in, std::vector *vec_out) { KALDI_ASSERT(vec_out != NULL); vec_out->resize(vec_in.size()); for (size_t i = 0; i < vec_in.size(); i++) (*vec_out)[i] = static_cast (vec_in[i]); } /// A hashing function-object for vectors. template struct VectorHasher { // hashing function for vector. size_t operator()(const std::vector &x) const noexcept { size_t ans = 0; typename std::vector::const_iterator iter = x.begin(), end = x.end(); for (; iter != end; ++iter) { ans *= kPrime; ans += *iter; } return ans; } VectorHasher() { // Check we're instantiated with an integer type. KALDI_ASSERT_IS_INTEGER_TYPE(Int); } private: static const int kPrime = 7853; }; /// A hashing function-object for pairs of ints template struct PairHasher { // hashing function for pair size_t operator()(const std::pair &x) const noexcept { // 7853 was chosen at random from a list of primes. return x.first + x.second * 7853; } PairHasher() { // Check we're instantiated with an integer type. KALDI_ASSERT_IS_INTEGER_TYPE(Int1); KALDI_ASSERT_IS_INTEGER_TYPE(Int2); } }; /// A hashing function object for strings. struct StringHasher { // hashing function for std::string size_t operator()(const std::string &str) const noexcept { size_t ans = 0, len = str.length(); const char *c = str.c_str(), *end = c + len; for (; c != end; c++) { ans *= kPrime; ans += *c; } return ans; } private: static const int kPrime = 7853; }; /// Reverses the contents of a vector. template inline void ReverseVector(std::vector *vec) { KALDI_ASSERT(vec != NULL); size_t sz = vec->size(); for (size_t i = 0; i < sz/2; i++) std::swap( (*vec)[i], (*vec)[sz-1-i]); } /// Comparator object for pairs that compares only the first pair. template struct CompareFirstMemberOfPair { inline bool operator() (const std::pair &p1, const std::pair &p2) { return p1.first < p2.first; } }; /// For a vector of pair where I is an integer and F a floating-point or /// integer type, this function sorts a vector of type vector > on /// the I value and then merges elements with equal I values, summing these over /// the F component and then removing any F component with zero value. This /// is for where the vector of pairs represents a map from the integer to float /// component, with an "adding" type of semantics for combining the elements. template inline void MergePairVectorSumming(std::vector > *vec) { KALDI_ASSERT_IS_INTEGER_TYPE(I); CompareFirstMemberOfPair c; std::sort(vec->begin(), vec->end(), c); // sort on 1st element. typename std::vector >::iterator out = vec->begin(), in = vec->begin(), end = vec->end(); // special case: while there is nothing to be changed, skip over // initial input (avoids unnecessary copying). while (in + 1 < end && in[0].first != in[1].first && in[0].second != 0.0) { in++; out++; } while (in < end) { // We reach this point only at the first element of // each stretch of identical .first elements. *out = *in; ++in; while (in < end && in->first == out->first) { out->second += in->second; // this is the merge operation. ++in; } if (out->second != static_cast(0)) // Don't keep zero elements. out++; } vec->erase(out, end); } } // namespace kaldi #endif // KALDI_UTIL_STL_UTILS_H_