A C++ library for building sturdy software.
Switch branches/tags
Nothing to show
Clone or download
Latest commit 270dba8 May 28, 2013
Permalink
Failed to load latest commit information.
include/stout Fixes os::environ for OS X. May 28, 2013
m4 Initial commit. May 27, 2013
tests Initial commit. May 27, 2013
LICENSE Initial commit. May 27, 2013
Makefile.am Initial commit. May 27, 2013
README.md Updated README and made markdown. May 27, 2013
bootstrap Initial commit. May 27, 2013
configure.ac Initial commit. May 27, 2013
install-sh Initial commit. May 27, 2013

README.md

Stout is a header-only C++ library.

No action is needed if you would like to use this library in your project. Simply add the include folder to your include path during compilation.

Depending on which headers you'd like to use, you may require the following third party libraries:

  • Boost
  • Google's glog (this dependency will be removed in the future)
  • Google's protobuf
  • Google's gmock/gtest

User Guide

There are a handful of primitives and collections that are provided within the library, as well as some namespaced and miscellaneous utilities.

It probably makes sense to at least take a look at Option, Try, and Result as they are used extensively throughout the library. Note that the library is designed to completely avoid exceptions. See exceptions for further discussion.

Primitives

Note that none of the primitives are namespaced!

Duration

Used to represent some duration of time. The main way to construct a Duration is to invoke Duration::parse which expects a string made up of a number and a unit, i.e., 42ns, 42us, 42ms, 42secs, 42mins, 42hrs, 42days, 42weeks. For each of the supported units there are associated types: Nanoseconds, Microseconds, Milliseconds, Seconds, Minutes, Hours, Days, Weeks. Each of these types inherit from Duration and can be used anywhere a Duration is expected, for example:

        Duration d = Seconds(5);

Note that we also provide an overload of the std::ostream operator << for Duration that formats the output (including the unit) based on the magnitude (e.g., Seconds(42) outputs 42secs but Seconds(120) outputs 2mins).

Error

Primitives such as Try and Result can represent errors. You can explicitly construct one of these types as an error, but it's a bit verbose. The Error type acts as "syntactic sugar" for implicitly constructing one of these types. That is, Error is implicitly convertible to a Try<T> or Result<T> for any T. For example:

        Try<bool> parse(const std::string& s) {
          if (s == "true") return true;
          else if (s == "false") return false;
          else return Error("Failed to parse string as boolean");
        }

        Try<bool> t = parse("false");

None

Similar to Error, the None type acts as "syntactic sugar" to make using Option less verbose. For example:

        Option<bool> o = None();

Nothing

A lot of functions that return void can also "return" an error. Since we don't use exceptions (see Exceptions) we capture this pattern using Try<Nothing> (see Try.

Option

The Option type provides a safe alternative to using NULL. There are implicit constructors provided by Option as well:

        Option<bool> o = true;

Note that the current implementation copies the underlying values. See Philosophy for more discussion. Nothing prevents you from using pointers, however, the pointer will not be deleted when the Option is destructed:

        Option<std::string*> o = new std::string("hello world");

Owned

The Owned type represents a uniquely owned pointer. With C++11 this will extend std::unique_ptr, requiring the user to adhere to move semantics. Until then, an Owned instance inherits from std::tr1::shared_ptr and is used more as a placeholder for where we want to use move semantics in the future.

Result

Try

Stopwatch

UUID

Collections

The library includes a few different collections. Mostly these are wrappers around existing collections but with modified interfaces to provide a more monadic apporach (e.g., returning an Option).

cache

A templated implementation of a least-recently used (LRU) cache. Note that the key type must be compatible with std::tr1::unordered_map. The interface is rather poor right now, only providing 'put' and 'get' operations.

hashmap

Requires Boost.

hashset

Requires Boost.

multihashmap

Requires Boost.

Namespaces

There are a fair number of utilities behind a few namespaces.

fs

gzip

JSON

lambda

net

os

path

protobuf

Requires protobuf.

strings

Miscellaneous

Like the primitives, these miscellaneous utilities are not namespaced.

copy

EXIT

fatal

<a href="foreach>

foreach

Requires Boost.

gtest

Requires gtest.

numify

preprocessor

Requires Boost.

stringify

Philosophy

"Premature optimization is the root of all evil."

You'll notice that the library is designed in a way that can lead to a lot of copying. This decision was deliberate. Capturing the semantics of pointer ownership is hard to enforce programmatically unless you copy, and in many instances these copies can be elided by an optimizing compiler. We've choosen safety rather than premature optimizations.

Note, however, that we plan to liberally augment the library as we add C++11 support. In particular, we plan to use rvalue references and std::unique_ptr (although, likely wrapped as Owned) in order to explicitly express ownership semantics. Until then, it's unlikely that the performance overhead incurred via any extra copying is your bottleneck, and if it is we'd love to hear from you!

Exceptions

The library WILL NEVER throw exceptions and will attempt to capture any exceptions thrown by underlying C++ functions and convert them into an Error.

Building Tests

We'll assume you've got a distribution of gmock and have already built a static archive called libgmock.a (see gmock's README to learn how). We'll also assume the Boost, glog, and protobuf headers can be found via the include paths and libglog.* can be found via the library search paths. You can then build the tests via:

   $ g++ -I${STOUT}/include -I$(GMOCK)/gtest/include -I$(GMOCK)/include \
     ${STOUT}/tests/tests.cpp libgmock.a -lglog -o tests

Note that if you want to test the gzip headers you'll need to define HAVE_LIBZ and link against libz:

   $ g++ -I${STOUT}/include -I$(GMOCK)/gtest/include -I$(GMOCK)/include \
     -DHAVE_LIBZ ${STOUT}/tests/tests.cpp libgmock.a -lglog -lz -o tests