1

I have a 1D char vector emulating a 2D vector (this is a requirement). This vector is 000111 and it's equivalent to vector[0] = 000 and vector[1] = 111 of a 2D. So it has two strings, all of same length (3 in this case). I want to set every string as a key in a std::unordered_map, so I am doing:

#include <iostream>
#include <unordered_map>
#include <string>
#include <vector>

int main ()
{
  std::unordered_map<std::string, int> mymap;
  std::vector<char> keys(2 * 3); // 2 keys, each one of length 3
  for(int i = 0; i < 2; ++i)
  {
    for(int j = 0; j < 3; ++j)
    {
      keys[j + i * 3] = (i) ? '1' : '0';
    }
  }
  // keys = 000111

  for(int i = 0; i < 2; ++i)
  {
    mymap[std::string(keys.begin() + i * 3, keys.begin() + (i + 1) * 3)] = i;
  }

  for (auto& x: mymap) {
    std::cout << x.first << ": " << x.second << std::endl;
  }

  /*
  Output:
  111: 1
  000: 0
  */

  return 0;
}

which makes me unhappy because I have to construct a new string and then insert that to the map. It would be nice if I could just emplace it or something in one step. Can I?

gsamaras
  • 71,951
  • 46
  • 188
  • 305
  • 1
    *"the construction is poor?"* Yep. `char(0) != '0'` – Baum mit Augen Nov 27 '16 at 15:50
  • Silly of me @BaummitAugen, you are right, I updated the question, please re-read! :) – gsamaras Nov 27 '16 at 16:03
  • @gsamaras Same problem as before. ;) Try `keys[j + i * 3] = (i) ? '1' : '0';` – Baum mit Augen Nov 27 '16 at 16:05
  • I have fixed that in my real code, forgot to update it @BaummitAugen, danke! – gsamaras Nov 27 '16 at 16:05
  • 2
    Are you able to use ``? http://en.cppreference.com/w/cpp/header/string_view You could also roll your own string_view. – Captain Giraffe Nov 27 '16 at 16:11
  • No @CaptainGiraffe, but it would be nice to have an answer with that for future use (and if possible, no you wan't without, *if* this holds). To be honest I would be excited to see such an answer! – gsamaras Nov 27 '16 at 16:19
  • 1
    *which makes me unhappy because I have to construct a new string* Don't let silly things like that affect your happiness. I could understand you if you were upset because the performance of your program was worse than expected by 10%, but not because you can't avoid an operation, whose impact on performance is unknown and is likely to be negligible. – Leon Nov 27 '16 at 16:33
  • Leon Aristotle and Plato would agree with you. Thanks. I will let it be, but an answer from @CaptainGiraffe would be cool with the new features for future readers! – gsamaras Nov 27 '16 at 16:34
  • @gsamaras I'll see if I can hammer something out. – Captain Giraffe Nov 27 '16 at 16:37
  • You should be happy when your program works correctly. If it doesn't, what use is it being fast? It will just make more errors per second. Now please excuse my asking, what happens when your matrix is filled with zeros? Is the map useful in this case? – n. m. could be an AI Nov 27 '16 at 16:50
  • @n.m. indeed. Well in my real application a key could indeed be full of zeroes and have a value of zero and it makes sense, extreme case, but possible. – gsamaras Nov 27 '16 at 16:52
  • No, I'm asking what happens if the entire matrix is full of zeros, not just a single key. – n. m. could be an AI Nov 27 '16 at 16:55
  • You mean that every key of the map is `000` @n.m.? Well, that would be bad. Maybe you are trying to make a point I fail to see. :/ – gsamaras Nov 27 '16 at 16:56
  • I just wonder why you would need such a map. There is no motivation and no justification of its suitability for a given task (what is this task?). – n. m. could be an AI Nov 27 '16 at 17:06
  • @n.m. I hided the reason for the sake of the minimal example. You can get a taste of what am I after by reading [this question](http://stackoverflow.com/questions/40768507/query-points-on-the-vertices-of-a-hamming-cube). It may have a -3, but that's what I must do. Every key will be actually a vertex of the Hamming cube and the value will be a vector of the points ([as discussed in this question](http://stackoverflow.com/questions/40710592/how-to-retrieve-collisions-of-unordered-map)) that are assigned to that vertex. It might be not clear what I am trying to do, but it's part of a bigger algo – gsamaras Nov 27 '16 at 17:14

1 Answers1

1

I think this is a drop-in replacement for a c++17 string_view. A string_view doesn't own any of the strings, so const-ness can be a problem (see the const-cast when inserting into the map)

The only changes that nedded to be made was

  1. const-cast, you'll have to solve this.
  2. the type of the multimap.
  3. Note the using statement just at the #endif

I just bolted a class, a hash-struct(in std::!) and a few overloads onto your code.

#include <iostream>
#include <unordered_map>
#include <string>
#include <vector>
#ifdef HAS_STRING_VIEW
#include <string_view>
#else

class lps_noz_view{
public:
    lps_noz_view() = delete;
    lps_noz_view(const char* start, size_t size):start(start), stop(start + size){}
    lps_noz_view(const lps_noz_view& ) = default;
    lps_noz_view(lps_noz_view&& ) = default;
    const char* begin(){  return start;}
    const char* end(){  return stop;}
    const char* begin() const{  return start;}
    const char* end() const{  return stop;}
    std::string to_string() const{  return std::string(start, stop);}
private:
    const char* start;
    const char* stop;
};

bool operator < (const lps_noz_view& lhs, const lps_noz_view& rhs){
    return lhs.to_string() < rhs.to_string();  
    // or use strncmp to avoid creating strings =)
}

bool operator == (const lps_noz_view& lhs, const lps_noz_view& rhs){
    return lhs.to_string() == rhs.to_string();  
    // strncmp
}
std::ostream& operator << (std::ostream& os, const lps_noz_view& rhs){
    return os << rhs.to_string();
}

namespace std{
template<>
struct hash<lps_noz_view>
{
    using argument_type = lps_noz_view;
    using result_type = size_t;
    size_t operator()(const lps_noz_view& arg) const{
        return std::hash<std::string>()(std::string(arg.begin(), arg.end()));
    }
};
};

using string_view = lps_noz_view;
#endif
// 
int main ()
{
  std::unordered_map<string_view, int> mymap;
  std::vector<char> keys(2 * 3); // 2 keys, each one of length 3
  for(int i = 0; i < 2; ++i)
  {
    for(int j = 0; j < 3; ++j)
    {
      keys[j + i * 3] = (i) ? '1' : '0';
    }
  }
  // keys = 000111

  for(int i = 0; i < 2; ++i)
  {
    mymap[string_view(const_cast<const char*>(&(*keys.begin()) + i * 3), 
            (i + 1) * 3)] = i;
  }

  for (auto& x: mymap) {
    std::cout << x.first << ": " << x.second << std::endl;
  }

  /*
  Output:
  111: 1
  000: 0
  */

  return 0;
}
Captain Giraffe
  • 14,407
  • 6
  • 39
  • 67