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
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.
Note that none of the primitives are namespaced!
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
).
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");
Similar to Error, the None
type acts as "syntactic sugar"
to make using Option less verbose. For example:
Option<bool> o = None();
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.
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");
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.
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).
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.
Requires Boost.
Requires Boost.
Requires Boost.
There are a fair number of utilities behind a few namespaces.
Requires protobuf.
Like the primitives, these miscellaneous utilities are not namespaced.
<a href="foreach>
Requires Boost.
Requires gtest.
Requires Boost.
"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!
The library WILL NEVER throw exceptions and will attempt to capture any exceptions thrown by underlying C++ functions and convert them into an Error.
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