J
James
BTW, this is homework. I hope I am not out of line here...
I am in the process of learning C++. I have been given a task to complete
which involves mapping strings to a value. The minimum length of a string is
4 characters and only uses lowercase alphabetic characters. It needs to work
with more than just ASCII, (e.g., EBCDIC) I need to do this mapping without
using any standard containers. I immediately thought of using a 4 dimintinal
array of values to do a very fast lookup:
#define DEPTH (UCHAR_MAX + 1)
void* array[DEPTH][DEPTH][DEPTH][DEPTH];
However, this uses way to much memory. So, I thought of using the following
table:
#define DEPTH 27
void* array[DEPTH][DEPTH][DEPTH][DEPTH];
Which should handle all lowercase letters. However, I need to translate the
character value to an index into this array. So, here is what I have come up
with so far:
#include <iostream>
#include <climits>
#include <cctype>
#include <cstring>
#include <cassert>
class translator
{
static unsigned char g_chars[UCHAR_MAX + 1];
static char const* const g_alpha;
public:
translator()
{
for (int i = 0; i <= UCHAR_MAX; ++i)
{
if (isalpha(i) && islower(i))
{
for (int a = 0; a < 26; ++a)
{
if (i == g_alpha[a])
{
g_chars = a;
break;
}
}
}
}
}
public:
inline int operator [] (char c) const
{
return g_chars[(unsigned int)c];
}
};
unsigned char
translator::g_chars[UCHAR_MAX + 1] = { 0 };
char const* const
translator::g_alpha = "abcdefghijklmnopqrstuvwxyz";
static translator g_translator;
template<typename TR, typename T>
class cmap
{
typedef TR (*fp_command) (T);
struct table
{
fp_command m_fp[27][27][27][27];
};
private:
table m_table;
public:
cmap(fp_command fp_default)
{
for (std::size_t i1 = 0; i1 < 27; ++i1)
{
for (std::size_t i2 = 0; i2 < 27; ++i2)
{
for (std::size_t i3 = 0; i3 < 27; ++i3)
{
for (std::size_t i4 = 0; i4 < 27; ++i4)
{
m_table.m_fp[i1][i2][i3][i4] = fp_default;
}
}
}
}
}
private:
inline fp_command& prv_find(char const* name)
{
assert(strlen(name) >= 4);
return m_table.m_fp
[g_translator[name[0]]]
[g_translator[name[1]]]
[g_translator[name[2]]]
[g_translator[name[3]]];
}
inline fp_command prv_find(char const* name) const
{
assert(strlen(name) >= 4);
return m_table.m_fp
[g_translator[name[0]]]
[g_translator[name[1]]]
[g_translator[name[2]]]
[g_translator[name[3]]];
}
public:
void add(char const* name, fp_command cmd)
{
prv_find(name) = cmd;
}
inline TR exec(char const* name, T P) const
{
return prv_find(name)(P);
}
};
void
command_north(char const* str)
{
std::cout << "void command_north(char const* "
<< str
<< ")"
<< std::endl;
}
void
command_south(char const* str)
{
std::cout << "void command_south(char const* "
<< str
<< ")"
<< std::endl;
}
void
command_east(char const* str)
{
std::cout << "void command_east(char const* "
<< str
<< ")"
<< std::endl;
}
void
command_west(char const* str)
{
std::cout << "void command_west(char const* "
<< str
<< ")"
<< std::endl;
}
void
command_attack(char const* str)
{
std::cout << "void command_attack(char const* "
<< str
<< ")"
<< std::endl;
}
void
command_unknown(char const* str)
{
std::cout << "void command_unknown(char const* "
<< str
<< ")"
<< std::endl;
}
int main()
{
{
static cmap<void, char const*> cm_normal(command_unknown);
static cmap<void, char const*> cm_reverse(command_unknown);
cm_normal.add("north", command_north);
cm_normal.add("south", command_south);
cm_normal.add("east", command_east);
cm_normal.add("west", command_west);
cm_normal.add("attack", command_attack);
cm_reverse.add("north", command_south);
cm_reverse.add("south", command_north);
cm_reverse.add("east", command_west);
cm_reverse.add("west", command_east);
cm_reverse.add("attack", command_attack);
cm_normal.exec("north", "Message1");
cm_normal.exec("south", "Message2");
cm_normal.exec("east", "Message3");
cm_normal.exec("west", "Message4");
cm_normal.exec("west", "Message5");
cm_normal.exec("weild", "Message6");
cm_normal.exec("attack", "Big Monster!");
cm_normal.exec("fight", "Message7");
cm_normal.exec("1234xx566", "Message8");
cm_normal.exec("zzzz", "Message9");
std::cout << "----------------------------" << std::endl;
cm_reverse.exec("north", "Message1");
cm_reverse.exec("south", "Message2");
cm_reverse.exec("east", "Message3");
cm_reverse.exec("west", "Message4");
cm_reverse.exec("west", "Message5");
cm_reverse.exec("weild", "Message6");
cm_reverse.exec("attack", "Big Monster!");
cm_reverse.exec("fight", "Message7");
cm_reverse.exec("1234xx566", "Message8");
cm_reverse.exec("zzzz", "Message9");
}
return 0;
}
It seems to work, but I am a but uneasy... What do you all think of this? Am
I going about solving the problem in an ass-backwards manner?
Thanks.
BTW, can you think of a faster way to perform the lookup process???
I am in the process of learning C++. I have been given a task to complete
which involves mapping strings to a value. The minimum length of a string is
4 characters and only uses lowercase alphabetic characters. It needs to work
with more than just ASCII, (e.g., EBCDIC) I need to do this mapping without
using any standard containers. I immediately thought of using a 4 dimintinal
array of values to do a very fast lookup:
#define DEPTH (UCHAR_MAX + 1)
void* array[DEPTH][DEPTH][DEPTH][DEPTH];
However, this uses way to much memory. So, I thought of using the following
table:
#define DEPTH 27
void* array[DEPTH][DEPTH][DEPTH][DEPTH];
Which should handle all lowercase letters. However, I need to translate the
character value to an index into this array. So, here is what I have come up
with so far:
#include <iostream>
#include <climits>
#include <cctype>
#include <cstring>
#include <cassert>
class translator
{
static unsigned char g_chars[UCHAR_MAX + 1];
static char const* const g_alpha;
public:
translator()
{
for (int i = 0; i <= UCHAR_MAX; ++i)
{
if (isalpha(i) && islower(i))
{
for (int a = 0; a < 26; ++a)
{
if (i == g_alpha[a])
{
g_chars = a;
break;
}
}
}
}
}
public:
inline int operator [] (char c) const
{
return g_chars[(unsigned int)c];
}
};
unsigned char
translator::g_chars[UCHAR_MAX + 1] = { 0 };
char const* const
translator::g_alpha = "abcdefghijklmnopqrstuvwxyz";
static translator g_translator;
template<typename TR, typename T>
class cmap
{
typedef TR (*fp_command) (T);
struct table
{
fp_command m_fp[27][27][27][27];
};
private:
table m_table;
public:
cmap(fp_command fp_default)
{
for (std::size_t i1 = 0; i1 < 27; ++i1)
{
for (std::size_t i2 = 0; i2 < 27; ++i2)
{
for (std::size_t i3 = 0; i3 < 27; ++i3)
{
for (std::size_t i4 = 0; i4 < 27; ++i4)
{
m_table.m_fp[i1][i2][i3][i4] = fp_default;
}
}
}
}
}
private:
inline fp_command& prv_find(char const* name)
{
assert(strlen(name) >= 4);
return m_table.m_fp
[g_translator[name[0]]]
[g_translator[name[1]]]
[g_translator[name[2]]]
[g_translator[name[3]]];
}
inline fp_command prv_find(char const* name) const
{
assert(strlen(name) >= 4);
return m_table.m_fp
[g_translator[name[0]]]
[g_translator[name[1]]]
[g_translator[name[2]]]
[g_translator[name[3]]];
}
public:
void add(char const* name, fp_command cmd)
{
prv_find(name) = cmd;
}
inline TR exec(char const* name, T P) const
{
return prv_find(name)(P);
}
};
void
command_north(char const* str)
{
std::cout << "void command_north(char const* "
<< str
<< ")"
<< std::endl;
}
void
command_south(char const* str)
{
std::cout << "void command_south(char const* "
<< str
<< ")"
<< std::endl;
}
void
command_east(char const* str)
{
std::cout << "void command_east(char const* "
<< str
<< ")"
<< std::endl;
}
void
command_west(char const* str)
{
std::cout << "void command_west(char const* "
<< str
<< ")"
<< std::endl;
}
void
command_attack(char const* str)
{
std::cout << "void command_attack(char const* "
<< str
<< ")"
<< std::endl;
}
void
command_unknown(char const* str)
{
std::cout << "void command_unknown(char const* "
<< str
<< ")"
<< std::endl;
}
int main()
{
{
static cmap<void, char const*> cm_normal(command_unknown);
static cmap<void, char const*> cm_reverse(command_unknown);
cm_normal.add("north", command_north);
cm_normal.add("south", command_south);
cm_normal.add("east", command_east);
cm_normal.add("west", command_west);
cm_normal.add("attack", command_attack);
cm_reverse.add("north", command_south);
cm_reverse.add("south", command_north);
cm_reverse.add("east", command_west);
cm_reverse.add("west", command_east);
cm_reverse.add("attack", command_attack);
cm_normal.exec("north", "Message1");
cm_normal.exec("south", "Message2");
cm_normal.exec("east", "Message3");
cm_normal.exec("west", "Message4");
cm_normal.exec("west", "Message5");
cm_normal.exec("weild", "Message6");
cm_normal.exec("attack", "Big Monster!");
cm_normal.exec("fight", "Message7");
cm_normal.exec("1234xx566", "Message8");
cm_normal.exec("zzzz", "Message9");
std::cout << "----------------------------" << std::endl;
cm_reverse.exec("north", "Message1");
cm_reverse.exec("south", "Message2");
cm_reverse.exec("east", "Message3");
cm_reverse.exec("west", "Message4");
cm_reverse.exec("west", "Message5");
cm_reverse.exec("weild", "Message6");
cm_reverse.exec("attack", "Big Monster!");
cm_reverse.exec("fight", "Message7");
cm_reverse.exec("1234xx566", "Message8");
cm_reverse.exec("zzzz", "Message9");
}
return 0;
}
It seems to work, but I am a but uneasy... What do you all think of this? Am
I going about solving the problem in an ass-backwards manner?
Thanks.
BTW, can you think of a faster way to perform the lookup process???