Thread: Help with <algorithm> functions with 2 ranges

  1. #1
    -bleh-
    Join Date
    Aug 2010
    Location
    somewhere in this universe
    Posts
    463

    Help with <algorithm> functions with 2 ranges

    I read the possible implementation of is_permutation from <algorithm> and got a bit confused about the handling of the second range.

    Code:
    template <class InputIterator1, class InputIterator2>
      bool is_permutation (InputIterator1 first1, InputIterator1 last1,
                           InputIterator2 first2)
    {
      std::tie (first1,first2) = std::mismatch (first1,last1,first2);
      if (first1==last1) return true;
      InputIterator2 last2 = first2; std::advance (last2,std::distance(first1,last1));
      for (InputIterator1 it1=first1; it1!=last1; ++it1) {
        if (std::find(first1,it1,*it1)==it1) {
          auto n = std::count (first2,last2,*it1);
          if (n==0 || std::count (it1,last1,*it1)!=n) return false;
        }
      }
      return true;
    }

    is_permuation only takes in range2.begin() and then advance the begin iter by the length of range 1. So if range 1 is longer than range 2, the advance will calculate the last2 way beyond where range.end() should be.

    How come the don't take range2.end() as an argument?

    When you use these function in your work, have you noticed any bug caused by this?
    "All that we see or seem
    Is but a dream within a dream." - Poe

  2. #2
    Registered User antred's Avatar
    Join Date
    Apr 2012
    Location
    Germany
    Posts
    257
    is_permuation

    Returns true if there exists a permutation of the elements in the range [first1, last1) that makes that range equal to the range [first2,last2), where last2 denotes first2 + (last1 - first1) if it was not given.
    EDIT: In other words, it is assumed that the 2nd sequence has the same length as the first.
    Last edited by antred; 09-15-2014 at 01:36 PM.

  3. #3
    -bleh-
    Join Date
    Aug 2010
    Location
    somewhere in this universe
    Posts
    463
    Quote Originally Posted by antred View Post
    is_permuation



    EDIT: In other words, it is assumed that the 2nd sequence has the same length as the first.

    So it's really not safe to use when the lengths are mismatched?
    "All that we see or seem
    Is but a dream within a dream." - Poe

  4. #4
    C++まいる!Cをこわせ!
    Join Date
    Oct 2007
    Location
    Inside my computer
    Posts
    24,654
    Quote Originally Posted by nimitzhunter View Post
    So it's really not safe to use when the lengths are mismatched?
    It's not safe to use if |Range2| < |Range1|. But as I understand it, it makes no sense to use it if |Range2| != |Range1| because there can exist no permutation if that is the case.
    Quote Originally Posted by Adak View Post
    io.h certainly IS included in some modern compilers. It is no longer part of the standard for C, but it is nevertheless, included in the very latest Pelles C versions.
    Quote Originally Posted by Salem View Post
    You mean it's included as a crutch to help ancient programmers limp along without them having to relearn too much.

    Outside of your DOS world, your header file is meaningless.

  5. #5
    Master Apprentice phantomotap's Avatar
    Join Date
    Jan 2008
    Posts
    5,108
    How come the don't take range2.end() as an argument?
    O_o

    Bug. (That is, the missing functions are considered a bug in the standard.) The functions you are asking about have been tagged for a future version of the standard.

    When you use these function in your work, have you noticed any bug caused by this?
    If you use them incorrectly, the bug will be in your code.

    But as I understand it, it makes no sense to use it if |Range2| != |Range1| because there can exist no permutation if that is the case.
    That is not the least bit relevant.

    If you have two--four iterators--ranges, you would be required to write sentry code to correctly use the interface. The missing interfaces allow you to just ask the question making the code, for the client developer, more clearly self-documenting thanks to being simpler.

    The missing interfaces also bring parity with other standard interfaces.

    If anyone wants, you can easily wrap a bit of forwarding code behind an optionally compiled block of code so you can start using the missing functions.

    [Edit]
    The code below uses my semantics because I'm used to those semantics.

    The standard semantics for `is_permutation' is more inline with `contains_leading_permutation' or something.

    To get standard behavior, you'd need to get the minimum distance and accordingly adjust the range limits.
    [/Edit]

    Soma

    Code:
    #include <algorithm>
    #include <iomanip>
    #include <iostream>
    #include <vector>
    
    namespace shim
    {
        using namespace std;
        template
        <
            typename FIterator1
          , typename FIterator2
        >
        bool is_permutation
        (
            FIterator1 fOrigin1
          , FIterator1 fTerminus1
          , FIterator2 fOrigin2
          , FIterator2 fTerminus2
        )
        {
            return((distance(fOrigin1, fTerminus1) == distance(fOrigin2, fTerminus2)) ? (is_permutation(fOrigin1, fTerminus1, fOrigin2)) : (false));
        }
        template
        <
            typename FIterator1
          , typename FIterator2
          , typename FPredicate
        >
        bool is_permutation
        (
            FIterator1 fOrigin1
          , FIterator1 fTerminus1
          , FIterator2 fOrigin2
          , FIterator2 fTerminus2
          , FPredicate fPredicate
        )
        {
            return((distance(fOrigin1, fTerminus1) == distance(fOrigin2, fTerminus2)) ? (is_permutation(fOrigin1, fTerminus1, fOrigin2, fPredicate)) : (false));
        }
    }
    
    int main()
    {
        std::vector<int> s1{1,2,3,4,5};
        std::vector<int> s2{3,5,4,1,2};
        std::vector<int> s3{3,5,4,1};
        std::vector<int> s4{3,5,4,1,6};
        std::cout << std::boolalpha << shim::is_permutation(s1.begin(), s1.end(), s2.begin(), s2.end()) << '\n';
        std::cout << std::boolalpha << shim::is_permutation(s1.begin(), s1.end(), s3.begin(), s3.end()) << '\n';
        std::cout << std::boolalpha << shim::is_permutation(s1.begin(), s1.end(), s4.begin(), s4.end()) << '\n';
        return(0);
    }
    Last edited by phantomotap; 09-15-2014 at 03:31 PM.
    “Salem Was Wrong!” -- Pedant Necromancer
    “Four isn't random!” -- Gibbering Mouther

  6. #6
    Registered User antred's Avatar
    Join Date
    Apr 2012
    Location
    Germany
    Posts
    257
    Well, apparently this is going to be changed for C++14, as the overloads taking 4 iterators instead of 3 all have a little "since C++14" next to them on cppreference.com.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 5
    Last Post: 09-16-2012, 03:11 PM
  2. declaring ranges a-z A-Z 0-9 etc. ?
    By kezkez in forum C Programming
    Replies: 1
    Last Post: 07-01-2010, 05:48 PM
  3. Asserts and their ranges
    By Matamoros123 in forum C++ Programming
    Replies: 8
    Last Post: 10-07-2006, 12:32 PM
  4. C Ranges
    By EvoTone in forum C Programming
    Replies: 20
    Last Post: 09-28-2006, 05:40 AM
  5. iterators cursors and ranges in STL
    By superchritch in forum C++ Programming
    Replies: 0
    Last Post: 09-20-2005, 09:03 AM