• Advertisement

Archived

This topic is now archived and is closed to further replies.

string tables

This topic is 5298 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hi! I''ve been thinking about string table implementations. It''s often useful to bind a int to a string (such as error codes or menu options, etc). How do _you_ like to implement yours? Kinda curious of different implementations. I know of two ways:
//  the first one 

enum myEnum { ZERO, ONE, NUM_ENUMS );
std::string stringtable[ NUM_ENUMS ];

stringtable[ ZERO ] = "Zero";
stringtable[ ONE ] = "One";


// the second one

std::map< int, std::string > stringtable;
Both ways has one "flaw"... They need to be initiated by an instance. Say there in a class, in someones constructor or somewhere they must be set. I would like to make the stringtables like when #define something. A static const in a class can be initated "alone" in the .cpp file, but an array?.. Of course one way would be to read the strings from a file and enumerate them along the way (0 - N) but... Well, kinda curious. Any tips or links? "No lies of sugar can sweeten the sournes of reality" }+TITANIUM+{ A.K.A. DXnewbie[onMIRC]

Share this post


Link to post
Share on other sites
Advertisement
If the errors start from zero or one:

std::string errors[] = { "error one", "error two" };

That works fine outside of any procedure.

Share this post


Link to post
Share on other sites
yeah, I''ve used that too. But it''s kinda hard to controll to what number it''s tied to.
"error one" should _always_ be [1], having a big table it''s hard to maintain. Especially if one element is moved :/
one method I used was using comments like

enum eErrors { ZERO, ONE };
std::string errors[] = {
/* ZERO */ "Error zero",
/* ONE */ "Error one"
};


if the enums names are numbers it''s easy to sort. but say they''re actions? PUNCH, KICK, etc. That''s a little harder... :/

any other ways?

"No lies of sugar can sweeten the sournes of reality"

}+TITANIUM+{ A.K.A. DXnewbie[onMIRC]

Share this post


Link to post
Share on other sites
If the error codes are sequential and start from zero, then the array method works fine, however, I just dispense with the minimal overhead that std::string gives, and just go with const chars:


enum ErrorCode
{
ErrorOne,
ErrorTwo,
ErrorThree,
// etc

NumErrors
};

static const char* gErrorMessages[NumErrors] = {
"This is an error message for ErrorOne",
"This is an error message for ErrorTwo",
"This is an error message for ErrorThree",
// etc

};


Otherwise, if the error codes are scattered all over the place and/or I only need to map strings to a few of them, then the easiest way (IMO) is to use a std::map:


const int ErrorOne = 123;
const int ErrorTwo = 456;
const int ErrorThree = 789;

static std::map<int,const char*> gErrorMsgMap;

// in some initialization function:

{
gErrorMsgMap[ErrorOne] = "This is an error message for ErrorOne";
gErrorMsgMap[ErrorTwo] = "This is an error message for ErrorTwo";
gErrorMsgMap[ErrorThree] = "This is an error message for ErrorThree";
}

Share this post


Link to post
Share on other sites
Simple way to keep enum and string in sync: x macros.
See http://www.flipcode.com/cgi-bin/msg.cgi?showThread=Tip-LoadLibraryGetProcAddress&forum=totd&id=-1

In short:
{error_defs.h}
X(ENOENT, "file not found")
...

{error string allocation in error_strs.cpp}
#define X(name, str) str,
static const char* errors[] = {
#include "error_defs.h"
""
};
#undef X

{enum definition in errors.h}
#define X(name, str) name,
enum
{
#include "error_defs.h"
NUM_ERRORS
};

no init, no runtime overhead, easy to keep everything together.

Share this post


Link to post
Share on other sites
Use std::lower_bound for a fast binary search, should be about as fast as std::map if not faster, and should use less memory than std::map and could be put in a const/read-only block by the compiler/linker. It need to be sorted by hand though.

#include <algorithm>

struct value_string
{
value_string(int value, const char* string)
: _value(value),
_string(string)
{
}

static bool value_pred(const value_string& lhs, int value)
{
return lhs._value < value;
}

int _value;
const char* _string;
};

const value_string value_string_collection[] =
{
value_string(123, "123"),
value_string(456, "456"),
value_string(789, "789"),
};

const value_string* value_string_collection_end = value_string_collection + sizeof value_string_collection / sizeof value_string_collection[0];

const char* find_value(int value)
{
const value_string* p = std::lower_bound(value_string_collection, value_string_collection_end, value, value_string::value_pred);
if ((p != value_string_collection_end) && (p->_value == value))
return p->_string;
else
return 0;
}

int main()
{
const char* p1 = find_value(0); // returns 0

const char* p2 = find_value(123); // returns "123"

const char* p3 = find_value(456); // returns "456"

const char* p4 = find_value(1000); // returns 0

}


[How To Ask Questions|STL Programmer''s Guide|Bjarne FAQ|C++ FAQ Lite|C++ Reference|MSDN]

Share this post


Link to post
Share on other sites
yes! that''s what I''m talking about :D *love to see what people can think of*

initating an array with { a, #a } I didn''t know that was possible, to say what element first and then the string. kewl! That solves the problem I thought I had


Error codes and engine specific stuff (static strings) I think it''s best with the compiler-generated-include-file-with-macro-trick, and for dynamic data such as dialogs and stuff a std::map (or a hash?) would be best. Right?

"No lies of sugar can sweeten the sournes of reality"

}+TITANIUM+{ A.K.A. DXnewbie[onMIRC]

Share this post


Link to post
Share on other sites
I''d say it''s a better idea to keep the strings in a seperate file (even if that file is then compiled into the EXE as a resource). It''s easier to then create different files for different languages.

Superpig
- saving pigs from untimely fates, and when he''s not doing that, runs The Binary Refinery.
Enginuity1 | Enginuity2 | Enginuity3 | Enginuity4

Share this post


Link to post
Share on other sites
Yes that would be a good idea too. How would _you_ sync the strings with the enums? Would you still have a file full with MACRO( enum, string_english ) , and another with MACRO( enum, string_russian ) ?

"No lies of sugar can sweeten the sournes of reality"

}+TITANIUM+{ A.K.A. DXnewbie[onMIRC]

Share this post


Link to post
Share on other sites
I''d have a Word/Excel document with a list of message numbers and message meanings printed out and stuck up by my desk. Then, I''d sync the message numbers to line numbers in the file (by adding blank lines where necessary).

That excel file could then be sent off to the localisation outsourcers to create a file for me.

Superpig
- saving pigs from untimely fates, and when he''s not doing that, runs The Binary Refinery.
Enginuity1 | Enginuity2 | Enginuity3 | Enginuity4

Share this post


Link to post
Share on other sites

  • Advertisement