Thursday, 24 April 2014

One-file C++ Utilties

Summary:

Here I show off self-contained utilties I have accumulated for C++ over time. Included are small functions for:
  1. Directory manipulation and searching
  2. Creating a timer
  3. Simple performance stats
  4. Printing the type of an object.
  5. printf-like string manipulation
The name is slightly dishonest, but few-file C++ utilities didn't have the same ring.

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.

3 comments:

  1. 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.

    http://gcc.gnu.org/onlinedocs/libstdc++/manual/ext_demangling.html

    ReplyDelete
  2. This comment has been removed by a blog administrator.

    ReplyDelete