Interchangeable use of hash_map and unordered_map (C++11) - c++

From an earlier post, Difference between hash_map and unordered_map?, I understand that hash_map that existed in prior-C++-11 was kind of non-standard and that has been replaced by standard unordered_map as interchangeable one. However, I have some doubt.
Earlier (prior to C++11), we used hash_map as:
hash_map<string,string,shash,seq> some_hashmap;
where shash and seq could be defined as below:
class shash {
public:
size_t operator()(const string &a) const {
register size_t ret = 0;
register string::const_iterator a,e;
a = s.begin();
e = s.end();
for(;a != e;++a) {
ret = (ret << 5) + (ret >> 2) + *a;
}
return(ret);
}
};
class seq {
public:
bool operator()(const string &str1,const string &str2) const {
register const char *s1 = str1.c_str();
register const char *s2 = str2.c_str();
for(;*s1 && *s2 && *s1 == *s2;++s1,++s2);
return(!*s1 && !*s2);
}
};
Can unordered_map (C++11) be used interchangeably here? Or, is there any better alternative of shash and seq, or can they be omitted in unordered_map?

Related

Convert std::string to ci_string

I used this approach to create a case-insensitive typedef for string. Now, I'm trying to convert a std::string to ci_string. All of the following throw compiler errors:
std::string s {"a"};
ci_string cis {s};
ci_string cis (s);
ci_string cis {(ci_string)s};
ci_string cis ((ci_string)s);
ci_string cis = s;
I spent some time trying to figure out how to overload the = operator, and I attempted to use static_cast and dynamic_cast without success. How can I do this?
Your two types are different, so you cannot use the constructor with a regular std::string. But your string is still able to copy a C string, so this should work:
std::string s{"a"};
ci_string cis{ s.data() }; // or s.c_str(), they are the same
std::string and ci_string are unrelated types. Why would static_cast or dynamic_cast be able to convert them? Remember: Two different instantiations of the same template are unrelated types and are potentially completely incompatible.
Give up on the idea of overloading operator= or on some magic that performs the conversion automatically. You have two unrelated types. But they both offer member functions that can you can successfully use to copy the char elements from one to the other.
Just write a simple conversion function that takes advantage of the fact that both std::string and ci_string have their value_type defined as char, and appropriately use one of std::basic_string's constructors, either one which takes a pointer to raw data or one which takes two iterators which form a range.
Here is a complete example:
#include <string>
#include <iostream>
struct ci_char_traits : public std::char_traits<char> {
static bool eq(char c1, char c2) { return toupper(c1) == toupper(c2); }
static bool ne(char c1, char c2) { return toupper(c1) != toupper(c2); }
static bool lt(char c1, char c2) { return toupper(c1) < toupper(c2); }
static int compare(const char* s1, const char* s2, size_t n) {
while( n-- != 0 ) {
if( toupper(*s1) < toupper(*s2) ) return -1;
if( toupper(*s1) > toupper(*s2) ) return 1;
++s1; ++s2;
}
return 0;
}
static const char* find(const char* s, int n, char a) {
while( n-- > 0 && toupper(*s) != toupper(a) ) {
++s;
}
return s;
}
};
typedef std::basic_string<char, ci_char_traits> ci_string;
ci_string to_ci_string(std::string const& src)
{
return ci_string(src.begin(), src.end());
// or:
// return ci_string(src.c_str());
}
int main()
{
std::string s {"a"};
auto cis = to_ci_string(s);
std::cout << cis.c_str() << "\n";
}

Array of C strings, initialized with string literals

The Ghostscript interpreter API has a function
GSDLLEXPORT int GSDLLAPI gsapi_init_with_args(void *instance, int argc, char **argv)
The final argument argv is a pointer to an array of C strings, which are interpreted as command-line arguments. I obviously cannot change the signature of the function gsapi_init_with_args to take a const char ** argument instead.
If I were willing to ignore (or silence) the deprecated conversion from string constant to 'char*' warning, then I would write simply
char *gs_argv[] = {"", "-dNOPAUSE", "-dBATCH", ...};
and pass gs_argv as the final argument. But I would prefer to fix my code so that I am not relying on an external function to behave in the way I expect it to (and effectively treat gs_argv as const char**).
Is there any simple way to declare gs_argv as an array of pointers to (non-const) C strings, and initialize its elements with string literals? (That is, using a similar approach to how I can initialize a single C string: using char c_str[] = "abc".) The best I can think of is to use
const char *gs_argv0[] = {"", "-dNOPAUSE", "-dBATCH", ...};
and then copy the contents, element by element, into gs_argv.
Please note that I understand why the compiler gives this warning (and have read the answers to, among others, this question). I am asking for a solution, rather than an explanation.
You can use:
char arg1[] = "";
char arg2[] = "-dNOPAUSE";
char arg3[] = "-dBATCH";
char* gs_argv0[] = {arg1, arg2, arg3, NULL};
int argc = sizeof(gs_argv0)/sizeof(gs_argv0[0]) - 1;
gsapi_init_with_args(instance, argc, gs_argv0)
Create copies of the string literals using strdup. This is more verbose, but fixes the warning.
char* gs_argv0[NARGS];
gs_argv0[0] = strdup("");
gs_argv0[1] = strdup("-dNOPAUSE");
// ...
Note that you will also need to free the memory allocated by strdup if you want to prevent leaks.
You might also want to add a comment to your code saying why you are doing this, to make it clear for future readers.
If you can guarantee that the function will not modify the non-const parameter, then it is acceptable to use const_cast in this situation.
A C++14 solution.
#define W(x) \
(([](auto& s)->char* \
{ \
static char r[sizeof(s)]; \
strcpy (r, s); \
return r; \
})(x))
char* argv[] =
{ W("--foo=bar",
W("baz"),
nullptr
};
Since this code requires C++11, there's a lower cost C++11 solution in another answer below. I'm leaving this one for posterity.
There are pretty much two choices: ignore it and const_cast, or do the right thing. Since this is modern C++, you're supposed to have nice, RAII classes. Thus, the simplest, safest thing to do is to safely wrap such an array.
// https://github.com/KubaO/stackoverflown/tree/master/questions/args-cstrings-32484688
#include <initializer_list>
#include <type_traits>
#include <cstdlib>
#include <cassert>
#include <vector>
class Args {
struct str_vector : std::vector<char*> {
~str_vector() { for (auto str : *this) free(str); }
} m_data;
void append_copy(const char * s) {
assert(s);
auto copy = strdup(s);
if (copy) m_data.push_back(copy); else throw std::bad_alloc();
}
public:
Args(std::initializer_list<const char*> l) {
for (auto str : l) append_copy(str);
m_data.push_back(nullptr);
}
template <std::size_t N>
Args(const char * const (&l)[N]) {
for (auto str : l) append_copy(str);
m_data.push_back(nullptr);
}
/// Initializes the arguments with a null-terminated array of strings.
template<class C, typename = typename std::enable_if<std::is_same<C, char const**>::value>::type>
Args(C l) {
while (*l) append_copy(*l++);
m_data.push_back(nullptr);
}
/// Initializes the arguments with an array of strings with given number of elements.
Args(const char ** l, size_t count) {
while (count--) append_copy(*l++);
m_data.push_back(nullptr);
}
Args(Args && o) = default;
Args(const Args &) = delete;
size_t size() const { return m_data.size() - 1; }
char ** data() { return m_data.data(); }
bool operator==(const Args & o) const {
if (size() != o.size()) return false;
for (size_t i = 0; i < size(); ++i)
if (strcmp(m_data[i], o.m_data[i]) != 0) return false;
return true;
}
};
Let's see how it works:
#include <iostream>
extern "C" int gsapi_init_with_args(void*, int argc, char** argv) {
for (int i = 0; i < argc; ++i)
std::cout << "arg " << i << "=" << argv[i] << std::endl;
return 0;
}
int main()
{
Args args1 { "foo", "bar", "baz" };
const char * args2i[] { "foo", "bar", "baz", nullptr };
Args args2 { (const char **)args2i };
const char * args3i[] { "foo", "bar", "baz" };
Args args3 { args3i };
const char * const args4i[] { "foo", "bar", "baz" };
Args args4 { args4i };
const char * args5i[] { "foo", "bar", "baz" };
Args args5 { args5i, sizeof(args5i)/sizeof(args5i[0]) };
assert(args1 == args2);
assert(args2 == args3);
assert(args3 == args4);
assert(args4 == args5);
gsapi_init_with_args(nullptr, args1.size(), args1.data());
}
Output:
arg 0=foo
arg 1=bar
arg 2=baz
Try to const_cast it:
gsapi_init_with_args(instance, argc, const_cast<char**>(argv));
Maybe it will help with fixing warning.
Inspired by n.m.'s C++14 version, here's a C++11 version. The trick is to use an evaluated empty lambda expression to generate a fresh type, so that each instantiation of W__ is unique.
template <typename T, int N> static char * W__(const char (&src)[N], T) {
static char storage[N];
strcpy(storage, src);
return storage;
}
#define W(x) W__(x, []{})
char * argv[] = {
W("foo"),
W("bar")
};
The static in front of W__'s return type means that W__ has internal linkage and won't bloat the object file with extra symbols. It has nothing to do with the static in front of storage, as the latter indicates the static storage duration for the local variable. The code below would be perfectly valid, but of course doing the wrong thing and having undefined behavior:
template <typename T, int N> static char * BAD(const char (&src)[N], T) {
char storage[N];
strcpy(storage, src);
return storage;
}
Since a lambda has to be evaluated, you can't simply make its type a template argument:
template<typename> void G();
G<decltype([]{})>(); // doesn't work

How to get a fully-qualified function name in C++ (gcc), _excluding_ the return type?

This question describes how to use __PRETTY_FUNCTION__ to get a full name of a function, including its return type, argument types, namespace and template parameters.
Consider the following, beautiful function:
namespace foo {
namespace {
template<int i>
int (*bar(int (*arg)(int *)))(int *) {
printf("%s\n", __PRETTY_FUNCTION__);
return arg;
}
} // anonymous namespace
} // namespace foo
If it's not obvious to you, the function takes, and returns, a pointer to an int * -> int function.
Its pretty name is, when compiled with g++ (4.9),
int (* foo::{anonymous}::bar(int (*)(int*)))(int*) [with int i = 1337]
and, with clang++ (3.5),
int (*foo::(anonymous namespace)::bar(int (*)(int *)) [i = 1337])(int *)
Those strings are pretty unsuitable for testing whether the function is part of a certain namespace. Is there any other way, or, say, a compiler-provided library to parse those strings?
To clarify, I'd rather have something like
foo::{anonymous}::bar <I don't care about anything beyond this point>
Even more ideally, I'd like a compile-time way, such as a constexpr function split(__PRETTY_FUNCTION__) that yields some sort of list of
fully qualified function name
return type
type of arg0
type of arg1
etc, but I'd be happy with just the fully-qualified function name.
After a more careful observation I wrote this code:
template <typename InputIterator, typename T>
InputIterator findClosing( InputIterator first, InputIterator last, T close )
{
if (first == last)
return last;
auto open = *first;
unsigned counter = 1;
while (++first != last)
{
if (*first == close && --counter == 0)
return first;
if (*first == open)
++counter;
}
return last;
}
template <std::size_t N,
std::size_t N2>
std::string f(char const(&str)[N], char const(&name)[N2])
{
using namespace std;
// Argument to isalnum must be unsigned:
auto cond = [] (unsigned char c) {return !isalnum(c) && c != '_';};
auto iter = str;
for (;;++iter)
{
iter = search( iter, end(str),
begin(name), end(name)-1 );
if (iter == end(str))
throw invalid_argument("");
if ((iter == begin(str) || cond(iter[-1]))
&& (iter == end(str) - N2 || (cond(iter[N2-1]) && iter[N2-1] != ':')))
break;
}
auto origin_iter = iter;
while(iter != begin(str))
{
--iter;
for (auto p : {"()", "{}"})
if (*iter == p[1])
iter = findClosing(reverse_iterator<char const*>(iter+1),
reverse_iterator<char const*>(begin(str)),
p[0]).base()-2;
if (cond(*iter) && *iter != ':')
return string(iter+1, origin_iter+N2-1);
}
return string(iter, origin_iter+N2-1);
}
It should work with any function, assuming no unnecessary whitespace is existent in __PRETTY_FUNCTION__ and __func__ contains solely the unqualified function name.
Demo.
This doesn't do quite what you've asked in that it doesn't return a single value which is a constexpr string, but it gets close. It is, however, fully constexpr and it returns a pointer to the beginning of the namespace, and a pointer to the end of it (the beginning of the function name), and, optionally the length of that string.
constexpr bool isNotIdentifierChar(const char *pf)
{
return !isalnum(*pf) && *pf!='_';
}
constexpr const char* getNamespaceEnd(const char *pf, const char *func)
{
return (isNotIdentifierChar(pf) && 0==strncmp(&pf[1], func, strlen(func))
&& isNotIdentifierChar(pf+strlen(func)+1) && ':'!=pf[strlen(func)+1])
? &pf[1]
: getNamespaceEnd(++pf, func);
}
constexpr const char* getNamespaceStartIter(const char *pf, const char *end)
{
return (*pf==' ' && strchr(&pf[1], ' ') > end)
? &pf[1]
: getNamespaceStartIter(++pf, end);
}
constexpr const char* getNamespaceStart(const char *pf, const char *func)
{
return getNamespaceStartIter(pf, getNamespaceEnd(pf, func));
}
constexpr size_t getNamespaceSize(const char *pf, const char *func)
{
return getNamespaceEnd(pf, func) - getNamespaceStart(pf, func);
}
One can't have a constexpr return a std::string because the std::string (or any equivalent construct) has a non-trivial destructor, but we can return the start and end of the namespace like this:
printf("%s\n", std::string(
getNamespaceStart(__PRETTY_FUNCTION__, __func__),
getNamespaceEnd(__PRETTY_FUNCTION__, __func__)+strlen(__func__)
).data());
This version includes the function name ("bar" in this case), but it can also be omitted by simply leaving out the +strlen(__func__).
We could also make it somewhat cleaner by using a simple class:
class NamespaceString {
public:
NamespaceString(const char *pf, const char *func)
: start(getNamespaceStart(pf, func)),
end(getNamespaceEnd(pf, func)) {}
std::string getString() const {
return std::string(start, end);
}
private:
const char *start;
const char *end;
};
Then the use within the function is a bit cleaner:
static const NamespaceString ns(__PRETTY_FUNCTION__, __func__);
printf("%s\n", ns.getString().data());
Updated demo which includes both #Columbo's answer and this one: live code

Getting wrong result for FIND function of map

The method fails to find the char* array passed to it even though it is present in map.
When I replaced char* with std::string in map. Code works fine.
static void CreateTranslationMap();
static UString FindTranslatedString(char* propertyName);
static std::map<char*,UString> TranslationMap ;
static void CreateTranslationMap()
{
UString engString("TextAlignmentPosition");
char* transString= MSGTXT("TextAlignmentPosition");
TranslationMap.insert(std::pair<char*,UString>(transString,engString));
}
UString FindTranslatedString(char* propertyName)
{
UString NotFound("CannotFind");
std::map<char*, UString>::iterator itr;
itr = TranslationMap.begin();
itr = TranslationMap.find(propertyName);
if(itr!= TranslationMap.end())
{
return itr->second;
}
else if(itr== TranslationMap.end())
{
return NotFound;
}
}
You need to use your own custom comparator for comparing pointer to char
Use:
struct cmp_c_string
{
bool operator()(char const *lhs, char const *rhs) const
{
return std::strcmp(lhs, rhs) < 0;
}
};
std::map<char*,UString, cmp_c_string > TranslationMap ;
That's because when doing comparison for equality the map uses <.
When the Key of the map is char* you are doing comparisons of pointers (not the C-String). So you are testing to see if one pointer is less than the other pointer (ie comparing the address).
When the Key of the map is std::string you using the operator< that is defined for std::string, which actually compares the characters in the string to determine which is less than the other.
As the std::map is a template it actually takes more parameters to define how it works. The third parameters is the comparison function (which defaults to less std::less<K> which is usually operator<).
So you can use char* you just need a custom comparator operator.
bool comparitor(char const* lhs, char const* rhs)
{
return (test for less than or some other strict weak function);
}
std::map<char*, UString, comparitor> myMap;
when using char *, it just compare address.
char a[] = "hi";
char b[] = "hi";
char *c = a;
char *d = b;
c & d are different.(c != d) If you want to compare string, you should use strcmp.
But when using string, it overwrites "==" operation.
So you can just compare using "=="
string a = "hi";
string b = "hi";
a & b are same. (a == b)
You have this behavior because you use pointer to string literal which is different every time you create such a pointer. So, for example, you create 2 pointers:
char* p1 = "Hello world!";
char* p2 = "Hello world!";
While content to which p1 and p2 point is identical the pointers, themselves, are different. So p1 != p2, and you trying to store pointer in the map. You should use std::string instead or have global constants pointers which you'd use everywhere; something like:
const char* const c_transString = MSGTXT("TextAlignmentPosition");
...
TranslationMap.insert(std::pair<char*,UString>(c_transString, engString));
...
FindTranslatedString(c_transString)
Just replace char* to const char* because the map data type always take the string in const form . I took your example and it is running in my terminal. So the new code is :
#include<iostream>
using namespace std;
static void CreateTranslationMap();
static string FindTranslatedString(const char* propertyName);
static std::map<const char*,string> TranslationMap ;
static void CreateTranslationMap()
{
string engString("TextAlignmentPosition");
const char* transString= ("1");
TranslationMap.insert(std::pair<const char*,string>(transString,engString));
}
string FindTranslatedString(const char* propertyName)
{
string NotFound("CannotFind");
std::map<const char*, string>::iterator itr;
itr = TranslationMap.begin();
itr = TranslationMap.find(propertyName);
if(itr!= TranslationMap.end())
{
return itr->second;
}
else if(itr== TranslationMap.end())
{
return NotFound;
}
}
int main()
{
CreateTranslationMap();
string s =FindTranslatedString("1");
cout<<s<<endl;
return 0;
}

C++ comparison using strings for operators

I was writing out the function below, and started to think that there's probably a better way to go about it; however Google isn't turning up much, so any insight would be appreciated. I also have a very similar situation involving integers.
bool compare_strs (std::string operator_, std::string str_0, std::string str_1)
{
if (operator_ == ">")
{
return str_0 > str1;
}
else if (operator_ == "<")
{
return str_0 < str1;
}
else if (operator_ == "<=")
{
return str_0 <= str1;
}
else
{
return str_0 >= str1;
}
}
You can use a map to store operators and related functors. In C++11, something along these lines should work, though there might be a couple subtle errors. In C++03, you'll have to change a couple things, including changing std::function to boost::function or function pointers, as well as using std::make_pair to store the map values.
#include <functional> //for std::function and std::less et al.
#include <map> //for std::map
#include <stdexcept> //for std::invalid_argument
#include <string> //for std::string
struct StringComparer {
static bool compare( //split up to fit width
const std::string &oper,
const std::string &str0, const std::string &str1
) {
MapType::const_iterator iter = operations.find(oper);
if (iter == std::end(operations)) //check if operator is found
throw std::invalid_argument("No match for provided operator.");
return iter->second(str0, str1); //call the appropriate functor
}
private:
using MapType = std::map< //makes life easier, same as typedef
std::string,
std::function<bool(const std::string &, const std::string &)>
>;
static const MapType operations; //a map of operators to functors
};
const StringComparer::MapType StringComparer::operations = { //define the map
{"<", std::less<std::string>()}, //std::less is a functor version of <
{"<=", std::less_equal<std::string>()},
{">", std::greater<std::string>()},
{">=", std::greater_equal<std::string>()}
};
You can also see it in action. The nice thing about an approach like this is that it's very easy to include more operators, as all you have to do is add them to the map.
As others have mentioned, you should first ask yourself why you are doing this - there is likely a better solution. Going with this though, I might do something like:
template <typename T1, typename T2>
bool mycompare(std::string operator_, const T1 & _lhs, const T2 & _rhs)
{
if (operator_ == ">")
{
return _lhs > _rhs;
}
else if (operator_ == "<")
{
return _lhs < _rhs;
}
//etc.
else
{
throw new exception("Invalid operator");
}
}