Skip to content

Commit

Permalink
Mostly complete FakeOFStream. Copy fast integer to string routines.
Browse files Browse the repository at this point in the history
  • Loading branch information
kpu committed Apr 10, 2015
1 parent 90ac8e8 commit b48172f
Show file tree
Hide file tree
Showing 9 changed files with 856 additions and 43 deletions.
1 change: 1 addition & 0 deletions LICENSE
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ util/murmur_hash.cc
util/string_piece.hh and util/string_piece.cc
util/double-conversion/LICENSE covers util/double-conversion except Jamfile
util/file.cc contains a modified implementation of mkstemp under the LGPL
util/integer_to_string.* is BSD
jam-files/LICENSE_1_0.txt covers jam-files except Jamroot

For the rest:
Expand Down
2 changes: 1 addition & 1 deletion util/Jamfile
Original file line number Diff line number Diff line change
Expand Up @@ -21,7 +21,7 @@ obj file_piece_test.o : file_piece_test.cc /top//boost_unit_test_framework : $(c

fakelib parallel_read : parallel_read.cc : <threading>multi:<source>/top//boost_thread <threading>multi:<define>WITH_THREADS : : <include>.. ;

fakelib kenutil : bit_packing.cc ersatz_progress.cc exception.cc file.cc file_piece.cc mmap.cc murmur_hash.cc parallel_read pool.cc read_compressed scoped.cc string_piece.cc usage.cc double-conversion//double-conversion : <include>.. <os>LINUX,<threading>single:<source>rt : : <include>.. ;
fakelib kenutil : bit_packing.cc ersatz_progress.cc exception.cc file.cc file_piece.cc float_to_string.cc integer_to_string.cc mmap.cc murmur_hash.cc parallel_read pool.cc read_compressed scoped.cc string_piece.cc usage.cc double-conversion//double-conversion : <include>.. <os>LINUX,<threading>single:<source>rt : : <include>.. ;

exe cat_compressed : cat_compressed_main.cc kenutil ;

Expand Down
6 changes: 6 additions & 0 deletions util/exception.hh
Original file line number Diff line number Diff line change
Expand Up @@ -91,6 +91,12 @@ template <class Except, class Data> typename Except::template ExceptionTag<Excep
#define UTIL_UNLIKELY(x) (x)
#endif

#if __GNUC__ >= 3
#define UTIL_LIKELY(x) __builtin_expect (!!(x), 1)
#else
#define UTIL_LIKELY(x) (x)
#endif

#define UTIL_THROW_IF_ARG(Condition, Exception, Arg, Modify) do { \
if (UTIL_UNLIKELY(Condition)) { \
UTIL_THROW_BACKEND(#Condition, Exception, Arg, Modify); \
Expand Down
94 changes: 52 additions & 42 deletions util/fake_ofstream.hh
Original file line number Diff line number Diff line change
Expand Up @@ -5,48 +5,53 @@
#ifndef UTIL_FAKE_OFSTREAM_H
#define UTIL_FAKE_OFSTREAM_H

#include "util/double-conversion/double-conversion.h"
#include "util/double-conversion/utils.h"
#include "util/file.hh"
#include "util/float_to_string.hh"
#include "util/integer_to_string.hh"
#include "util/scoped.hh"
#include "util/string_piece.hh"

#define BOOST_LEXICAL_CAST_ASSUME_C_LOCALE
#include <boost/lexical_cast.hpp>
#include <cassert>
#include <cstring>

#include <stdint.h>

namespace util {
class FakeOFStream {
private:
// Maximum over all ToString operations.
static const std::size_t kMinBuf = 20;
public:
// Does not take ownership of out.
// Allows default constructor, but must call SetFD.
explicit FakeOFStream(int out = -1, std::size_t buffer_size = 1048576)
: buf_(util::MallocOrThrow(buffer_size)),
builder_(static_cast<char*>(buf_.get()), buffer_size),
// Mostly the default but with inf instead. And no flags.
convert_(double_conversion::DoubleToStringConverter::NO_FLAGS, "inf", "NaN", 'e', -6, 21, 6, 0),
fd_(out),
buffer_size_(buffer_size) {}
: buf_(util::MallocOrThrow(std::max(buffer_size, kMinBuf))),
current_(static_cast<char*>(buf_.get())),
end_(current_ + std::max(buffer_size, kMinBuf)),
fd_(out) {}

~FakeOFStream() {
if (buf_.get()) Flush();
// Could have called Finish already
Flush();
}

void SetFD(int to) {
if (builder_.position()) Flush();
Flush();
fd_ = to;
}

FakeOFStream &Write(const void *data, std::size_t length) {
// Dominant case
if (static_cast<std::size_t>(builder_.size() - builder_.position()) > length) {
builder_.AddSubstring((const char*)data, length);
if (UTIL_LIKELY(current_ + length <= end_)) {
std::memcpy(current_, data, length);
current_ += length;
return *this;
}
Flush();
if (length > buffer_size_) {
util::WriteOrThrow(fd_, data, length);
if (current_ + length <= end_) {
std::memcpy(current_, data, length);
current_ += length;
} else {
builder_.AddSubstring((const char*)data, length);
util::WriteOrThrow(fd_, data, length);
}
return *this;
}
Expand All @@ -55,57 +60,62 @@ class FakeOFStream {
return Write(str.data(), str.size());
}

FakeOFStream &operator<<(float value) {
// Odd, but this is the largest number found in the comments.
EnsureRemaining(double_conversion::DoubleToStringConverter::kMaxPrecisionDigits + 8);
convert_.ToShortestSingle(value, &builder_);
return *this;
}
FakeOFStream &operator<<(float value) { return CallToString(value); }
FakeOFStream &operator<<(double value) { return CallToString(value); }
FakeOFStream &operator<<(uint64_t value) { return CallToString(value); }
FakeOFStream &operator<<(int64_t value) { return CallToString(value); }
FakeOFStream &operator<<(uint32_t value) { return CallToString(value); }
FakeOFStream &operator<<(int32_t value) { return CallToString(value); }
FakeOFStream &operator<<(uint16_t value) { return CallToString(value); }
FakeOFStream &operator<<(int16_t value) { return CallToString(value); }

FakeOFStream &operator<<(double value) {
EnsureRemaining(double_conversion::DoubleToStringConverter::kMaxPrecisionDigits + 8);
convert_.ToShortest(value, &builder_);
FakeOFStream &operator<<(char c) {
EnsureRemaining(1);
*current_++ = c;
return *this;
}

// Inefficient! TODO: more efficient implementation
FakeOFStream &operator<<(unsigned value) {
return *this << boost::lexical_cast<std::string>(value);
}

FakeOFStream &operator<<(char c) {
FakeOFStream &operator<<(unsigned char c) {
EnsureRemaining(1);
builder_.AddCharacter(c);
*current_++ = static_cast<char>(c);
return *this;
}

// Note this does not sync.
void Flush() {
util::WriteOrThrow(fd_, buf_.get(), builder_.position());
builder_.Reset();
if (current_ != buf_.get()) {
util::WriteOrThrow(fd_, buf_.get(), current_ - (char*)buf_.get());
current_ = static_cast<char*>(buf_.get());
}
}

// Not necessary, but does assure the data is cleared.
void Finish() {
Flush();
// It will segfault trying to null terminate otherwise.
builder_.Finalize();
buf_.reset();
current_ = NULL;
util::FSyncOrThrow(fd_);
}

private:
template <class T> FakeOFStream &CallToString(const T value) {
EnsureRemaining(ToStringBuf<T>::kBytes);
current_ = ToString(value, current_);
assert(current_ <= end_);
return *this;
}

void EnsureRemaining(std::size_t amount) {
if (static_cast<std::size_t>(builder_.size() - builder_.position()) <= amount) {
if (UTIL_UNLIKELY(current_ + amount > end_)) {
Flush();
assert(current_ + amount <= end_);
}
}

util::scoped_malloc buf_;
double_conversion::StringBuilder builder_;
double_conversion::DoubleToStringConverter convert_;
char *current_, *end_;

int fd_;
const std::size_t buffer_size_;
};

} // namespace
Expand Down
23 changes: 23 additions & 0 deletions util/float_to_string.cc
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#include "util/float_to_string.hh"

#include "util/double-conversion/double-conversion.h"
#include "util/double-conversion/utils.h"

namespace util {
namespace {
const double_conversion::DoubleToStringConverter kConverter(double_conversion::DoubleToStringConverter::NO_FLAGS, "inf", "NaN", 'e', -6, 21, 6, 0);
} // namespace

char *ToString(double value, char *to) {
double_conversion::StringBuilder builder(to, ToStringBuf<double>::kBytes);
kConverter.ToShortest(value, &builder);
return &to[builder.position()];
}

char *ToString(float value, char *to) {
double_conversion::StringBuilder builder(to, ToStringBuf<float>::kBytes);
kConverter.ToShortestSingle(value, &builder);
return &to[builder.position()];
}

} // namespace util
25 changes: 25 additions & 0 deletions util/float_to_string.hh
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
#ifndef UTIL_FLOAT_TO_STRING_H
#define UTIL_FLOAT_TO_STRING_H

// Just for ToStringBuf
#include "util/integer_to_string.hh"

namespace util {

template <> struct ToStringBuf<double> {
// DoubleToStringConverter::kBase10MaximalLength + 1 for null paranoia.
static const unsigned kBytes = 18;
};

// Single wasn't documented in double conversion, so be conservative and
// say the same as double.
template <> struct ToStringBuf<float> {
static const unsigned kBytes = 18;
};

char *ToString(double value, char *to);
char *ToString(float value, char *to);

} // namespace util

#endif // UTIL_FLOAT_TO_STRING_H
Loading

0 comments on commit b48172f

Please sign in to comment.