Skip to content

Commit

Permalink
There are a lot of integer types
Browse files Browse the repository at this point in the history
  • Loading branch information
kpu committed Sep 27, 2015
1 parent 9632eb7 commit 4282222
Show file tree
Hide file tree
Showing 3 changed files with 98 additions and 19 deletions.
5 changes: 5 additions & 0 deletions util/fake_ofstream.hh
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,11 @@ class FakeOFStream : public FakeOStream<FakeOFStream> {
return *this;
}

FakeOFStream &seekp(uint64_t to) {
util::SeekOrThrow(fd_, to);
return *this;
}

protected:
friend class FakeOStream;
// For writes directly to buffer guaranteed to have amount < buffer size.
Expand Down
58 changes: 39 additions & 19 deletions util/fake_ostream.hh
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "util/string_piece.hh"

#include <cassert>
#include <limits>
#include <string>

#include <stdint.h>
Expand Down Expand Up @@ -51,8 +52,7 @@ template <class Derived> class FakeOStream {
};
public:
template <class T> typename EnableIfKludge<ToStringBuf<T>::kBytes>::type &operator<<(const T value) {
C().AdvanceTo(ToString(value, C().Ensure(ToStringBuf<T>::kBytes)));
return C();
return CallToString(value);
}

/* clang on OS X appears to consider std::size_t aka unsigned long distinct
Expand All @@ -63,42 +63,62 @@ template <class Derived> class FakeOStream {
* Also, delegating to *this << static_cast<uint64_t>(value) would loop
* indefinitely on gcc.
*/
Derived &operator<<(std::size_t value) {
C().AdvanceTo(ToString(static_cast<uint64_t>(value), C().Ensure(ToStringBuf<uint64_t>::kBytes)));
return C();
}
Derived &operator<<(std::size_t value) { return CoerceToString(value); }

// union types will map to int, but don't pass the template magic above in gcc.
Derived &operator<<(int value) { return CoerceToString(value); }

// gcc considers these distinct from uint64_t
Derived &operator<<(unsigned long long value) { return CoerceToString(value); }
Derived &operator<<(signed long long value) { return CoerceToString(value); }

Derived &operator<<(char val) {
// Character types that get copied as bytes instead of displayed as integers.
Derived &operator<<(char val) { return put(val); }
Derived &operator<<(signed char val) { return put(static_cast<char>(val)); }
Derived &operator<<(unsigned char val) { return put(static_cast<char>(val)); }

Derived &put(char val) {
char *c = C().Ensure(1);
*c = val;
C().AdvanceTo(++c);
return C();
}

Derived &operator<<(signed char val) {
return *this << static_cast<char>(val);
}

Derived &operator<<(unsigned char val) {
return *this << static_cast<char>(val);
}

Derived &put(char c) {
return *this << c;
}

private:
// References to derived class for convenience.
Derived &C() {
return *static_cast<Derived*>(this);
}

const Derived &C() const {
return *static_cast<const Derived*>(this);
}

template <class From, unsigned Length = sizeof(From), bool Signed = std::numeric_limits<From>::is_signed> struct Coerce {};

template <class From> struct Coerce<From, 2, false> { typedef uint16_t To; };
template <class From> struct Coerce<From, 4, false> { typedef uint32_t To; };
template <class From> struct Coerce<From, 8, false> { typedef uint64_t To; };

template <class From> struct Coerce<From, 2, true> { typedef int16_t To; };
template <class From> struct Coerce<From, 4, true> { typedef int32_t To; };
template <class From> struct Coerce<From, 8, true> { typedef int64_t To; };

template <class From> Derived &CoerceToString(const From value) {
return CallToString(static_cast<typename Coerce<From>::To>(value));
}

// This is separate to prevent an infinite loop if the compiler considers
// types the same (i.e. gcc std::size_t and uint64_t or uint32_t).
template <class T> Derived &CallToString(const T value) {
C().AdvanceTo(ToString(value, C().Ensure(ToStringBuf<T>::kBytes)));
return C();
}
};

class FakeSStream : public FakeOStream<FakeSStream> {
public:
// Semantics: appends to string. Remember to clear first!
explicit FakeSStream(std::string &out)
: out_(out) {}

Expand Down
54 changes: 54 additions & 0 deletions util/fake_ostream_test.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,54 @@
#define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
#define BOOST_TEST_MODULE FakeOStreamTest

#include "util/fake_ostream.hh"
#include <boost/test/unit_test.hpp>
#include <boost/lexical_cast.hpp>

#include <limits>

namespace util { namespace {

template <class T> void TestEqual(const T value) {
std::string str;
FakeSStream(str) << value;
BOOST_CHECK_EQUAL(boost::lexical_cast<std::string>(value), str);
}

template <class T> void TestCorners() {
TestEqual(std::numeric_limits<T>::max());
TestEqual(std::numeric_limits<T>::min());
TestEqual(static_cast<T>(0));
TestEqual(static_cast<T>(-1));
TestEqual(static_cast<T>(1));
}

BOOST_AUTO_TEST_CASE(Integer) {
TestCorners<char>();
TestCorners<signed char>();
TestCorners<unsigned char>();

TestCorners<short>();
TestCorners<signed short>();
TestCorners<unsigned short>();

TestCorners<int>();
TestCorners<unsigned int>();
TestCorners<signed int>();

TestCorners<long>();
TestCorners<unsigned long>();
TestCorners<signed long>();

TestCorners<long long>();
TestCorners<unsigned long long>();
TestCorners<signed long long>();
}

enum TinyEnum { EnumValue };

BOOST_AUTO_TEST_CASE(EnumCase) {
TestEqual(EnumValue);
}

}} // namespaces

0 comments on commit 4282222

Please sign in to comment.