Here I show off self-contained utilties I have accumulated for C++ over time. Included are small functions for:
- Directory manipulation and searching
- Creating a timer
- Simple performance stats
- Printing the type of an object.
- printf-like string manipulation
Overview:
While working on lanarts I frequently had to write code that was simply an #ifdef between UNIX land and Windows land. I made sure to minimize the amount of #ifdef's inside the actual game engine, pushing it into small C++ classes or one-file modules
Time has passed and they have remained useful to me; I publish them here for anyone to use. I figure stand-alone C++ utilities, where you can simply paste one or two small files into your code are worth releasing. You can incorporate them into namespaces if the need is felt; I usually go global for convenience.
Note 1: If you find yourself hungering endlessly for classes like these, I heartily recommend Boost. Personally though, I like to make due if I can with smaller dependencies.
Note 2: Most of these are from C++03 usage, so if there's a better way to do it in C++11 I may have missed it.
1. Simple directory access
directory.h
directory.cpp
It uses tinydir.h:
tinydir.h
This works on Linux/Mac/UNIX-like systems and Windows.
Don't expect much options here, but it is quite complete. 'search_directory' provides recursive directory searching, retrieving a filename list. The name pattern takes wildcards.
'ensure_directory' can create a directory if one does not already exist, returning false on failure.
See the header file for details.
2. Simple timer utility
Timer.cpp
Timer.h
Ever messed about trying to have a simple timing class in C++?
This one relies on using gettimeofday on Linux/Mac/UNIX-like systems, and emulating it on Windows. The Windows code was from Stack Overflow.
Provides these member functions:
Timer():
Sets a timer, get_microseconds() == 0 at this point.
void start():
Resets a timer, makes get_microseconds() == 0 again
unsigned long get_microseconds():
Time in microseconds, multiply by 10e-6 to get seconds. May want to change signature to 'long long' by editing the source.
Example usage:
Timer timer;
... stuff occurs ...
cout << "Seconds have passed: " << timer.get_microseconds() * 1e-6;
3. Simple performance stats
PerfTimer.h
PerfTimer.cpp
perf_timer.h
Simply, PerfTimer uses the above Timer class to create timers suitable for use with long-running methods (a map to the type name is used for convenience, but isn't super-fast).
Example usage:
Simply include perf_timer.h, and have:
PERF_TIMER();
at the start of your function. It will record simple statistics such as average time, max, standard deviation, etc.
Then, when you want to see the results, simply run:
perf_print_results();
And you will get fairly nicely formatted results. The advantage is this approach is enough to see obvious bottlenecks (ie, this function is taking 75% of the time) and does not require the use of external tools.
Example Output:
func bool analyzer_follow_entity(AnalysisState&, int, double):
>> total 3797.9561ms
calls 2801
average 1.3559ms
max 23.2120ms
std.dev +-1.8125ms, +-133.67%
4. Simple typename printing utility
typename.h
typename.cpp
Useful for templated functions, when you want to pretty-print an object's type. Note that proper use of a debugger may or may not be more appropriate; littering print statements still has its place, though.
Example usage:
template <typename T>
void my_template(const T& obj) {
cout << "got object of type: " << cpp_type_name_no_namespace(obj);
}
5. 'sprintf' into an std::string
strformat.h
strformat.cpp
This provides a global function called 'format' (again, edit to your needs!) that takes printf-style arguments and returns an std::string. To me, this clears a pain-point where I prefer printf-style syntax for output, but cannot use it to make temporary strings in output functions.
Note that the code is not designed for efficiency for strings > 512 bytes, but it does guarantee correctness.
Example usage:
std::string my_str = format("(%d, %d)", 1, 2); // -> Goes to "(1, 2)"
What else?
I have a Lua wrapping library (C++03 compatible) very similar to luabind but with no dependencies, and quite small size. It may be worth talking about in a follow-up.
Just a note: in typename.cpp, the result of a successful call to abi::__cxa_demangle should be freed (with a call to std::free) after its contents are copied to a std::string.
ReplyDeletehttp://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html
Fixed now, thanks!
ReplyDeleteThis comment has been removed by a blog administrator.
ReplyDelete