<commit_before>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// For 64-bit file access (off_t = off64_t, lseek64, etc).
#define _FILE_OFFSET_BITS 64

#include "net/base/file_stream.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#include "base/basictypes.h"
#include "base/callback.h"
#include "base/eintr_wrapper.h"
#include "base/file_path.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/string_util.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/worker_pool.h"
#include "base/synchronization/waitable_event.h"
#include "net/base/net_errors.h"

// We cast back and forth, so make sure it's the size we're expecting.
COMPILE_ASSERT(sizeof(int64) == sizeof(off_t), off_t_64_bit);

// Make sure our Whence mappings match the system headers.
COMPILE_ASSERT(net::FROM_BEGIN   == SEEK_SET &&
               net::FROM_CURRENT == SEEK_CUR &&
               net::FROM_END     == SEEK_END, whence_matches_system);

namespace net {
namespace {

// Map from errno to net error codes.
int64 MapErrorCode(int err) {
  switch (err) {
    case ENOENT:
      return ERR_FILE_NOT_FOUND;
    case EACCES:
      return ERR_ACCESS_DENIED;
    default:
      LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
      return ERR_FAILED;
  }
}

// ReadFile() is a simple wrapper around read() that handles EINTR signals and
// calls MapErrorCode() to map errno to net error codes.
int ReadFile(base::PlatformFile file, char* buf, int buf_len) {
  base::ThreadRestrictions::AssertIOAllowed();
  // read(..., 0) returns 0 to indicate end-of-file.

  // Loop in the case of getting interrupted by a signal.
  ssize_t res = HANDLE_EINTR(read(file, buf, static_cast<size_t>(buf_len)));
  if (res == static_cast<ssize_t>(-1))
    return MapErrorCode(errno);
  return static_cast<int>(res);
}

// WriteFile() is a simple wrapper around write() that handles EINTR signals and
// calls MapErrorCode() to map errno to net error codes.  It tries to write to
// completion.
int WriteFile(base::PlatformFile file, const char* buf, int buf_len) {
  base::ThreadRestrictions::AssertIOAllowed();
  ssize_t res = HANDLE_EINTR(write(file, buf, buf_len));
  if (res == -1)
    return MapErrorCode(errno);
  return res;
}

// FlushFile() is a simple wrapper around fsync() that handles EINTR signals and
// calls MapErrorCode() to map errno to net error codes.  It tries to flush to
// completion.
int FlushFile(base::PlatformFile file) {
  base::ThreadRestrictions::AssertIOAllowed();
  ssize_t res = HANDLE_EINTR(fsync(file));
  if (res == -1)
    return MapErrorCode(errno);
  return res;
}

// BackgroundReadTask is a simple task that reads a file and then runs
// |callback|.  AsyncContext will post this task to the WorkerPool.
class BackgroundReadTask : public Task {
 public:
  BackgroundReadTask(base::PlatformFile file, char* buf, int buf_len,
                     CompletionCallback* callback);
  ~BackgroundReadTask();

  virtual void Run();

 private:
  const base::PlatformFile file_;
  char* const buf_;
  const int buf_len_;
  CompletionCallback* const callback_;

  DISALLOW_COPY_AND_ASSIGN(BackgroundReadTask);
};

BackgroundReadTask::BackgroundReadTask(
    base::PlatformFile file, char* buf, int buf_len,
    CompletionCallback* callback)
    : file_(file), buf_(buf), buf_len_(buf_len), callback_(callback) {}

BackgroundReadTask::~BackgroundReadTask() {}

void BackgroundReadTask::Run() {
  int result = ReadFile(file_, buf_, buf_len_);
  callback_->Run(result);
}

// BackgroundWriteTask is a simple task that writes to a file and then runs
// |callback|.  AsyncContext will post this task to the WorkerPool.
class BackgroundWriteTask : public Task {
 public:
  BackgroundWriteTask(base::PlatformFile file, const char* buf, int buf_len,
                      CompletionCallback* callback);
  ~BackgroundWriteTask();

  virtual void Run();

 private:
  const base::PlatformFile file_;
  const char* const buf_;
  const int buf_len_;
  CompletionCallback* const callback_;

  DISALLOW_COPY_AND_ASSIGN(BackgroundWriteTask);
};

BackgroundWriteTask::BackgroundWriteTask(
    base::PlatformFile file, const char* buf, int buf_len,
    CompletionCallback* callback)
    : file_(file), buf_(buf), buf_len_(buf_len), callback_(callback) {}

BackgroundWriteTask::~BackgroundWriteTask() {}

void BackgroundWriteTask::Run() {
  int result = WriteFile(file_, buf_, buf_len_);
  callback_->Run(result);
}

}  // namespace

// CancelableCallbackTask takes ownership of the Callback.  This task gets
// posted to the MessageLoopForIO instance.
class CancelableCallbackTask : public CancelableTask {
 public:
  explicit CancelableCallbackTask(Callback0::Type* callback)
      : canceled_(false), callback_(callback) {}

  virtual void Run() {
    if (!canceled_)
      callback_->Run();
  }

  virtual void Cancel() {
    canceled_ = true;
  }

 private:
  bool canceled_;
  scoped_ptr<Callback0::Type> callback_;
};

// FileStream::AsyncContext ----------------------------------------------

class FileStream::AsyncContext {
 public:
  AsyncContext();
  ~AsyncContext();

  // These methods post synchronous read() and write() calls to a WorkerThread.
  void InitiateAsyncRead(
      base::PlatformFile file, char* buf, int buf_len,
      CompletionCallback* callback);
  void InitiateAsyncWrite(
      base::PlatformFile file, const char* buf, int buf_len,
      CompletionCallback* callback);

  CompletionCallback* callback() const { return callback_; }

  // Called by the WorkerPool thread executing the IO after the IO completes.
  // This method queues RunAsynchronousCallback() on the MessageLoop and signals
  // |background_io_completed_callback_|, in case the destructor is waiting.  In
  // that case, the destructor will call RunAsynchronousCallback() instead, and
  // cancel |message_loop_task_|.
  // |result| is the result of the Read/Write task.
  void OnBackgroundIOCompleted(int result);

 private:
  // Always called on the IO thread, either directly by a task on the
  // MessageLoop or by ~AsyncContext().
  void RunAsynchronousCallback();

  // The MessageLoopForIO that this AsyncContext is running on.
  MessageLoopForIO* const message_loop_;
  CompletionCallback* callback_;  // The user provided callback.

  // A callback wrapper around OnBackgroundIOCompleted().  Run by the WorkerPool
  // thread doing the background IO on our behalf.
  CompletionCallbackImpl<AsyncContext> background_io_completed_callback_;

  // This is used to synchronize between the AsyncContext destructor (which runs
  // on the IO thread and OnBackgroundIOCompleted() which runs on the WorkerPool
  // thread.
  base::WaitableEvent background_io_completed_;

  // These variables are only valid when background_io_completed is signaled.
  int result_;
  CancelableCallbackTask* message_loop_task_;

  bool is_closing_;

  DISALLOW_COPY_AND_ASSIGN(AsyncContext);
};

FileStream::AsyncContext::AsyncContext()
    : message_loop_(MessageLoopForIO::current()),
      callback_(NULL),
      background_io_completed_callback_(
          this, &AsyncContext::OnBackgroundIOCompleted),
      background_io_completed_(true, false),
      message_loop_task_(NULL),
      is_closing_(false) {}

FileStream::AsyncContext::~AsyncContext() {
  is_closing_ = true;
  if (callback_) {
    // If |callback_| is non-NULL, that implies either the worker thread is
    // still running the IO task, or the completion callback is queued up on the
    // MessageLoopForIO, but AsyncContext() got deleted before then.
    const bool need_to_wait = !background_io_completed_.IsSignaled();
    base::TimeTicks start = base::TimeTicks::Now();
    RunAsynchronousCallback();
    if (need_to_wait) {
      // We want to see if we block the message loop for too long.
      UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose",
                          base::TimeTicks::Now() - start);
    }
  }
}

void FileStream::AsyncContext::InitiateAsyncRead(
    base::PlatformFile file, char* buf, int buf_len,
    CompletionCallback* callback) {
  DCHECK(!callback_);
  callback_ = callback;

  base::WorkerPool::PostTask(FROM_HERE,
                             new BackgroundReadTask(
                                 file, buf, buf_len,
                                 &background_io_completed_callback_),
                             true /* task_is_slow */);
}

void FileStream::AsyncContext::InitiateAsyncWrite(
    base::PlatformFile file, const char* buf, int buf_len,
    CompletionCallback* callback) {
  DCHECK(!callback_);
  callback_ = callback;

  base::WorkerPool::PostTask(FROM_HERE,
                             new BackgroundWriteTask(
                                 file, buf, buf_len,
                                 &background_io_completed_callback_),
                             true /* task_is_slow */);
}

void FileStream::AsyncContext::OnBackgroundIOCompleted(int result) {
  result_ = result;
  message_loop_task_ = new CancelableCallbackTask(
      NewCallback(this, &AsyncContext::RunAsynchronousCallback));
  message_loop_->PostTask(FROM_HERE, message_loop_task_);
  background_io_completed_.Signal();
}

void FileStream::AsyncContext::RunAsynchronousCallback() {
  // Wait() here ensures that all modifications from the WorkerPool thread are
  // now visible.
  background_io_completed_.Wait();

  // Either we're in the MessageLoop's task, in which case Cancel() doesn't do
  // anything, or we're in ~AsyncContext(), in which case this prevents the call
  // from happening again.  Must do it here after calling Wait().
  message_loop_task_->Cancel();
  message_loop_task_ = NULL;

  if (is_closing_) {
    callback_ = NULL;
    return;
  }

  DCHECK(callback_);
  CompletionCallback* temp = NULL;
  std::swap(temp, callback_);
  background_io_completed_.Reset();
  temp->Run(result_);
}

// FileStream ------------------------------------------------------------

FileStream::FileStream()
    : file_(base::kInvalidPlatformFileValue),
      open_flags_(0),
      auto_closed_(true) {
  DCHECK(!IsOpen());
}

FileStream::FileStream(base::PlatformFile file, int flags)
    : file_(file),
      open_flags_(flags),
      auto_closed_(false) {
  // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to
  // make sure we will perform asynchronous File IO to it.
  if (flags & base::PLATFORM_FILE_ASYNC) {
    async_context_.reset(new AsyncContext());
  }
}

FileStream::~FileStream() {
  if (auto_closed_)
    Close();
}

void FileStream::Close() {
  // Abort any existing asynchronous operations.
  async_context_.reset();

  if (file_ != base::kInvalidPlatformFileValue) {
    if (close(file_) != 0) {
      NOTREACHED();
    }
    file_ = base::kInvalidPlatformFileValue;
  }
}

int FileStream::Open(const FilePath& path, int open_flags) {
  if (IsOpen()) {
    DLOG(FATAL) << "File is already open!";
    return ERR_UNEXPECTED;
  }

  open_flags_ = open_flags;
  file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL);
  if (file_ == base::kInvalidPlatformFileValue) {
    return MapErrorCode(errno);
  }

  if (open_flags_ & base::PLATFORM_FILE_ASYNC) {
    async_context_.reset(new AsyncContext());
  }

  return OK;
}

bool FileStream::IsOpen() const {
  return file_ != base::kInvalidPlatformFileValue;
}

int64 FileStream::Seek(Whence whence, int64 offset) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  // If we're in async, make sure we don't have a request in flight.
  DCHECK(!async_context_.get() || !async_context_->callback());

  off_t res = lseek(file_, static_cast<off_t>(offset),
                    static_cast<int>(whence));
  if (res == static_cast<off_t>(-1))
    return MapErrorCode(errno);

  return res;
}

int64 FileStream::Available() {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  int64 cur_pos = Seek(FROM_CURRENT, 0);
  if (cur_pos < 0)
    return cur_pos;

  struct stat info;
  if (fstat(file_, &info) != 0)
    return MapErrorCode(errno);

  int64 size = static_cast<int64>(info.st_size);
  DCHECK_GT(size, cur_pos);

  return size - cur_pos;
}

int FileStream::Read(
    char* buf, int buf_len, CompletionCallback* callback) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // read(..., 0) will return 0, which indicates end-of-file.
  DCHECK(buf_len > 0);
  DCHECK(open_flags_ & base::PLATFORM_FILE_READ);

  if (async_context_.get()) {
    DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
    // If we're in async, make sure we don't have a request in flight.
    DCHECK(!async_context_->callback());
    async_context_->InitiateAsyncRead(file_, buf, buf_len, callback);
    return ERR_IO_PENDING;
  } else {
    return ReadFile(file_, buf, buf_len);
  }
}

int FileStream::ReadUntilComplete(char *buf, int buf_len) {
  int to_read = buf_len;
  int bytes_total = 0;

  do {
    int bytes_read = Read(buf, to_read, NULL);
    if (bytes_read <= 0) {
      if (bytes_total == 0)
        return bytes_read;

      return bytes_total;
    }

    bytes_total += bytes_read;
    buf += bytes_read;
    to_read -= bytes_read;
  } while (bytes_total < buf_len);

  return bytes_total;
}

int FileStream::Write(
    const char* buf, int buf_len, CompletionCallback* callback) {
  // write(..., 0) will return 0, which indicates end-of-file.
  DCHECK_GT(buf_len, 0);

  if (!IsOpen())
    return ERR_UNEXPECTED;

  if (async_context_.get()) {
    DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
    // If we're in async, make sure we don't have a request in flight.
    DCHECK(!async_context_->callback());
    async_context_->InitiateAsyncWrite(file_, buf, buf_len, callback);
    return ERR_IO_PENDING;
  } else {
    return WriteFile(file_, buf, buf_len);
  }
}

int64 FileStream::Truncate(int64 bytes) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  // We better be open for reading.
  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);

  // Seek to the position to truncate from.
  int64 seek_position = Seek(FROM_BEGIN, bytes);
  if (seek_position != bytes)
    return ERR_UNEXPECTED;

  // And truncate the file.
  int result = ftruncate(file_, bytes);
  return result == 0 ? seek_position : MapErrorCode(errno);
}

int FileStream::Flush() {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  return FlushFile(file_);
}

}  // namespace net
<commit_msg>Use NewRunnableFunction in file_stream_posix.cc to get rid of custom Task subclasses.<commit_after>// Copyright (c) 2010 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

// For 64-bit file access (off_t = off64_t, lseek64, etc).
#define _FILE_OFFSET_BITS 64

#include "net/base/file_stream.h"

#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <errno.h>

#include "base/basictypes.h"
#include "base/callback.h"
#include "base/eintr_wrapper.h"
#include "base/file_path.h"
#include "base/logging.h"
#include "base/message_loop.h"
#include "base/metrics/histogram.h"
#include "base/string_util.h"
#include "base/task.h"
#include "base/threading/thread_restrictions.h"
#include "base/threading/worker_pool.h"
#include "base/synchronization/waitable_event.h"
#include "net/base/net_errors.h"

// We cast back and forth, so make sure it's the size we're expecting.
COMPILE_ASSERT(sizeof(int64) == sizeof(off_t), off_t_64_bit);

// Make sure our Whence mappings match the system headers.
COMPILE_ASSERT(net::FROM_BEGIN   == SEEK_SET &&
               net::FROM_CURRENT == SEEK_CUR &&
               net::FROM_END     == SEEK_END, whence_matches_system);

namespace net {
namespace {

// Map from errno to net error codes.
int64 MapErrorCode(int err) {
  switch (err) {
    case ENOENT:
      return ERR_FILE_NOT_FOUND;
    case EACCES:
      return ERR_ACCESS_DENIED;
    default:
      LOG(WARNING) << "Unknown error " << err << " mapped to net::ERR_FAILED";
      return ERR_FAILED;
  }
}

// ReadFile() is a simple wrapper around read() that handles EINTR signals and
// calls MapErrorCode() to map errno to net error codes.
int ReadFile(base::PlatformFile file, char* buf, int buf_len) {
  base::ThreadRestrictions::AssertIOAllowed();
  // read(..., 0) returns 0 to indicate end-of-file.

  // Loop in the case of getting interrupted by a signal.
  ssize_t res = HANDLE_EINTR(read(file, buf, static_cast<size_t>(buf_len)));
  if (res == static_cast<ssize_t>(-1))
    return MapErrorCode(errno);
  return static_cast<int>(res);
}

void ReadFileTask(base::PlatformFile file,
                  char* buf,
                  int buf_len,
                  CompletionCallback* callback) {
  callback->Run(ReadFile(file, buf, buf_len));
}

// WriteFile() is a simple wrapper around write() that handles EINTR signals and
// calls MapErrorCode() to map errno to net error codes.  It tries to write to
// completion.
int WriteFile(base::PlatformFile file, const char* buf, int buf_len) {
  base::ThreadRestrictions::AssertIOAllowed();
  ssize_t res = HANDLE_EINTR(write(file, buf, buf_len));
  if (res == -1)
    return MapErrorCode(errno);
  return res;
}

void WriteFileTask(base::PlatformFile file,
                   const char* buf,
                   int buf_len,
                   CompletionCallback* callback) {
  callback->Run(WriteFile(file, buf, buf_len));
}

// FlushFile() is a simple wrapper around fsync() that handles EINTR signals and
// calls MapErrorCode() to map errno to net error codes.  It tries to flush to
// completion.
int FlushFile(base::PlatformFile file) {
  base::ThreadRestrictions::AssertIOAllowed();
  ssize_t res = HANDLE_EINTR(fsync(file));
  if (res == -1)
    return MapErrorCode(errno);
  return res;
}

}  // namespace

// CancelableCallbackTask takes ownership of the Callback.  This task gets
// posted to the MessageLoopForIO instance.
class CancelableCallbackTask : public CancelableTask {
 public:
  explicit CancelableCallbackTask(Callback0::Type* callback)
      : canceled_(false), callback_(callback) {}

  virtual void Run() {
    if (!canceled_)
      callback_->Run();
  }

  virtual void Cancel() {
    canceled_ = true;
  }

 private:
  bool canceled_;
  scoped_ptr<Callback0::Type> callback_;
};

// FileStream::AsyncContext ----------------------------------------------

class FileStream::AsyncContext {
 public:
  AsyncContext();
  ~AsyncContext();

  // These methods post synchronous read() and write() calls to a WorkerThread.
  void InitiateAsyncRead(
      base::PlatformFile file, char* buf, int buf_len,
      CompletionCallback* callback);
  void InitiateAsyncWrite(
      base::PlatformFile file, const char* buf, int buf_len,
      CompletionCallback* callback);

  CompletionCallback* callback() const { return callback_; }

  // Called by the WorkerPool thread executing the IO after the IO completes.
  // This method queues RunAsynchronousCallback() on the MessageLoop and signals
  // |background_io_completed_callback_|, in case the destructor is waiting.  In
  // that case, the destructor will call RunAsynchronousCallback() instead, and
  // cancel |message_loop_task_|.
  // |result| is the result of the Read/Write task.
  void OnBackgroundIOCompleted(int result);

 private:
  // Always called on the IO thread, either directly by a task on the
  // MessageLoop or by ~AsyncContext().
  void RunAsynchronousCallback();

  // The MessageLoopForIO that this AsyncContext is running on.
  MessageLoopForIO* const message_loop_;
  CompletionCallback* callback_;  // The user provided callback.

  // A callback wrapper around OnBackgroundIOCompleted().  Run by the WorkerPool
  // thread doing the background IO on our behalf.
  CompletionCallbackImpl<AsyncContext> background_io_completed_callback_;

  // This is used to synchronize between the AsyncContext destructor (which runs
  // on the IO thread and OnBackgroundIOCompleted() which runs on the WorkerPool
  // thread.
  base::WaitableEvent background_io_completed_;

  // These variables are only valid when background_io_completed is signaled.
  int result_;
  CancelableCallbackTask* message_loop_task_;

  bool is_closing_;

  DISALLOW_COPY_AND_ASSIGN(AsyncContext);
};

FileStream::AsyncContext::AsyncContext()
    : message_loop_(MessageLoopForIO::current()),
      callback_(NULL),
      background_io_completed_callback_(
          this, &AsyncContext::OnBackgroundIOCompleted),
      background_io_completed_(true, false),
      message_loop_task_(NULL),
      is_closing_(false) {}

FileStream::AsyncContext::~AsyncContext() {
  is_closing_ = true;
  if (callback_) {
    // If |callback_| is non-NULL, that implies either the worker thread is
    // still running the IO task, or the completion callback is queued up on the
    // MessageLoopForIO, but AsyncContext() got deleted before then.
    const bool need_to_wait = !background_io_completed_.IsSignaled();
    base::TimeTicks start = base::TimeTicks::Now();
    RunAsynchronousCallback();
    if (need_to_wait) {
      // We want to see if we block the message loop for too long.
      UMA_HISTOGRAM_TIMES("AsyncIO.FileStreamClose",
                          base::TimeTicks::Now() - start);
    }
  }
}

void FileStream::AsyncContext::InitiateAsyncRead(
    base::PlatformFile file, char* buf, int buf_len,
    CompletionCallback* callback) {
  DCHECK(!callback_);
  callback_ = callback;

  base::WorkerPool::PostTask(FROM_HERE,
                             NewRunnableFunction(
                                 &ReadFileTask,
                                 file, buf, buf_len,
                                 &background_io_completed_callback_),
                             true /* task_is_slow */);
}

void FileStream::AsyncContext::InitiateAsyncWrite(
    base::PlatformFile file, const char* buf, int buf_len,
    CompletionCallback* callback) {
  DCHECK(!callback_);
  callback_ = callback;

  base::WorkerPool::PostTask(FROM_HERE,
                             NewRunnableFunction(
                                 &WriteFileTask,
                                 file, buf, buf_len,
                                 &background_io_completed_callback_),
                             true /* task_is_slow */);
}

void FileStream::AsyncContext::OnBackgroundIOCompleted(int result) {
  result_ = result;
  message_loop_task_ = new CancelableCallbackTask(
      NewCallback(this, &AsyncContext::RunAsynchronousCallback));
  message_loop_->PostTask(FROM_HERE, message_loop_task_);
  background_io_completed_.Signal();
}

void FileStream::AsyncContext::RunAsynchronousCallback() {
  // Wait() here ensures that all modifications from the WorkerPool thread are
  // now visible.
  background_io_completed_.Wait();

  // Either we're in the MessageLoop's task, in which case Cancel() doesn't do
  // anything, or we're in ~AsyncContext(), in which case this prevents the call
  // from happening again.  Must do it here after calling Wait().
  message_loop_task_->Cancel();
  message_loop_task_ = NULL;

  if (is_closing_) {
    callback_ = NULL;
    return;
  }

  DCHECK(callback_);
  CompletionCallback* temp = NULL;
  std::swap(temp, callback_);
  background_io_completed_.Reset();
  temp->Run(result_);
}

// FileStream ------------------------------------------------------------

FileStream::FileStream()
    : file_(base::kInvalidPlatformFileValue),
      open_flags_(0),
      auto_closed_(true) {
  DCHECK(!IsOpen());
}

FileStream::FileStream(base::PlatformFile file, int flags)
    : file_(file),
      open_flags_(flags),
      auto_closed_(false) {
  // If the file handle is opened with base::PLATFORM_FILE_ASYNC, we need to
  // make sure we will perform asynchronous File IO to it.
  if (flags & base::PLATFORM_FILE_ASYNC) {
    async_context_.reset(new AsyncContext());
  }
}

FileStream::~FileStream() {
  if (auto_closed_)
    Close();
}

void FileStream::Close() {
  // Abort any existing asynchronous operations.
  async_context_.reset();

  if (file_ != base::kInvalidPlatformFileValue) {
    if (close(file_) != 0) {
      NOTREACHED();
    }
    file_ = base::kInvalidPlatformFileValue;
  }
}

int FileStream::Open(const FilePath& path, int open_flags) {
  if (IsOpen()) {
    DLOG(FATAL) << "File is already open!";
    return ERR_UNEXPECTED;
  }

  open_flags_ = open_flags;
  file_ = base::CreatePlatformFile(path, open_flags_, NULL, NULL);
  if (file_ == base::kInvalidPlatformFileValue) {
    return MapErrorCode(errno);
  }

  if (open_flags_ & base::PLATFORM_FILE_ASYNC) {
    async_context_.reset(new AsyncContext());
  }

  return OK;
}

bool FileStream::IsOpen() const {
  return file_ != base::kInvalidPlatformFileValue;
}

int64 FileStream::Seek(Whence whence, int64 offset) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  // If we're in async, make sure we don't have a request in flight.
  DCHECK(!async_context_.get() || !async_context_->callback());

  off_t res = lseek(file_, static_cast<off_t>(offset),
                    static_cast<int>(whence));
  if (res == static_cast<off_t>(-1))
    return MapErrorCode(errno);

  return res;
}

int64 FileStream::Available() {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  int64 cur_pos = Seek(FROM_CURRENT, 0);
  if (cur_pos < 0)
    return cur_pos;

  struct stat info;
  if (fstat(file_, &info) != 0)
    return MapErrorCode(errno);

  int64 size = static_cast<int64>(info.st_size);
  DCHECK_GT(size, cur_pos);

  return size - cur_pos;
}

int FileStream::Read(
    char* buf, int buf_len, CompletionCallback* callback) {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  // read(..., 0) will return 0, which indicates end-of-file.
  DCHECK(buf_len > 0);
  DCHECK(open_flags_ & base::PLATFORM_FILE_READ);

  if (async_context_.get()) {
    DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
    // If we're in async, make sure we don't have a request in flight.
    DCHECK(!async_context_->callback());
    async_context_->InitiateAsyncRead(file_, buf, buf_len, callback);
    return ERR_IO_PENDING;
  } else {
    return ReadFile(file_, buf, buf_len);
  }
}

int FileStream::ReadUntilComplete(char *buf, int buf_len) {
  int to_read = buf_len;
  int bytes_total = 0;

  do {
    int bytes_read = Read(buf, to_read, NULL);
    if (bytes_read <= 0) {
      if (bytes_total == 0)
        return bytes_read;

      return bytes_total;
    }

    bytes_total += bytes_read;
    buf += bytes_read;
    to_read -= bytes_read;
  } while (bytes_total < buf_len);

  return bytes_total;
}

int FileStream::Write(
    const char* buf, int buf_len, CompletionCallback* callback) {
  // write(..., 0) will return 0, which indicates end-of-file.
  DCHECK_GT(buf_len, 0);

  if (!IsOpen())
    return ERR_UNEXPECTED;

  if (async_context_.get()) {
    DCHECK(open_flags_ & base::PLATFORM_FILE_ASYNC);
    // If we're in async, make sure we don't have a request in flight.
    DCHECK(!async_context_->callback());
    async_context_->InitiateAsyncWrite(file_, buf, buf_len, callback);
    return ERR_IO_PENDING;
  } else {
    return WriteFile(file_, buf, buf_len);
  }
}

int64 FileStream::Truncate(int64 bytes) {
  base::ThreadRestrictions::AssertIOAllowed();

  if (!IsOpen())
    return ERR_UNEXPECTED;

  // We better be open for reading.
  DCHECK(open_flags_ & base::PLATFORM_FILE_WRITE);

  // Seek to the position to truncate from.
  int64 seek_position = Seek(FROM_BEGIN, bytes);
  if (seek_position != bytes)
    return ERR_UNEXPECTED;

  // And truncate the file.
  int result = ftruncate(file_, bytes);
  return result == 0 ? seek_position : MapErrorCode(errno);
}

int FileStream::Flush() {
  if (!IsOpen())
    return ERR_UNEXPECTED;

  return FlushFile(file_);
}

}  // namespace net
<|endoftext|>


<commit_before>// lerc.cc
//
// Copyright (c) 2016 Frank Lin (lin.xiaoe.f@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "lerc_util.h"

#include "tiffio.h"

#include "Lerc/Lerc.h"

NS_GAGO_BEGIN

////////////////////////////////////////////////////////////////////////////////
// Lerc, public:

// Tiff --------------------------------------------------------

bool LercUtil::EncodeTiffOrDie(const std::string& path_to_file, const std::string& output_path,
                               double max_z_error, LercVersion lerc_ver, DataType data_type,
                               uint16_t band, bool signed_type) {
  Logger::LogD("Encoding %s", path_to_file.c_str());
  TIFF* tif = TIFFOpen(path_to_file.c_str(), "r");
  if (tif == nullptr) {
    Logger::LogD("ERROR when TIFFOpen %s\n", path_to_file.c_str());
    return false;
  }

  uint32_t width = 0;
  uint32_t height = 0;
  tdata_t buf;

  uint32_t tiff_dt = 0;

  uint32_t bits_per_sample = 0;

  TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
  TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
  TIFFGetField(tif, TIFFTAG_DATATYPE, &tiff_dt);
  TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);

  uint32_t type_size = 0;
  if (tiff_dt == SAMPLEFORMAT_INT) {
    if (bits_per_sample == 8) {
      data_type = signed_type ? DataType::CHAR : DataType::BYTE;
      type_size = sizeof(int8_t);
    } else if (bits_per_sample == 16) {
      data_type = signed_type ? DataType::SHORT : DataType::USHORT;
      type_size = sizeof(int16_t);
    } else if (bits_per_sample == 32) {
      data_type = signed_type ? DataType::INT : DataType::UINT;
      type_size = sizeof(int32_t);
    } else {
      Logger::LogD("Unknown bits per sample %s", path_to_file.c_str());
    }
  } else if (tiff_dt == SAMPLEFORMAT_IEEEFP) {
    data_type = DataType::FLOAT;
    type_size = 4;
  } else {
    Logger::LogD("Unsupported TIFF data format %s", path_to_file.c_str());
    return false;
  }

  // data
  unsigned char* data = new unsigned char[width * height * type_size];

  size_t line_size = TIFFScanlineSize(tif);

  for (int row = 0; row < height; ++row) {
    buf = _TIFFmalloc(line_size);
    TIFFReadScanline(tif, buf, row, bits_per_sample);

    memcpy(data + width * row * type_size, buf, line_size);

    _TIFFfree(buf);
  }

  TIFFClose(tif);

  // compress float buffer to lerc
  size_t num_bytes_needed = 0;
  size_t num_bytes_written = 0;
  LercNS::Lerc lerc;

  // convert data type to proper one
  LercNS::Lerc::DataType lerc_dt = static_cast<LercNS::Lerc::DataType>(data_type);
  if (lerc_dt == LercNS::Lerc::DataType::DT_Double ||
      lerc_dt == LercNS::Lerc::DataType::DT_Char ||
      lerc_dt == LercNS::Lerc::DataType::DT_Short ||
      lerc_dt == LercNS::Lerc::DataType::DT_UShort ||
      lerc_dt == LercNS::Lerc::DataType::DT_Undefined) {
    Logger::LogD("ERROR input data type %s\n", path_to_file.c_str());
    return false;
  }

  if (!lerc.ComputeBufferSize((void*)data,                   // raw image data, row by row, band by band
                              lerc_dt,
                              width, height, band,
                              0,                             // set 0 if all pixels are valid
                              max_z_error,                   // max coding error per pixel, or precision
                              num_bytes_needed)) {           // size of outgoing Lerc blob
    Logger::LogD("ERROR when ComputeBufferSize %s\n", path_to_file.c_str());
    return false;
  }

  size_t num_bytes_blob = num_bytes_needed;
  LercNS::Byte* lerc_buffer = new LercNS::Byte[num_bytes_blob];

  if (!lerc.Encode((void*)data,            // raw image data, row by row, band by band
                   lerc_dt,
                   width, height, band,
                   0,                      // 0 if all pixels are valid
                   max_z_error,            // max coding error per pixel, or precision
                   lerc_buffer,            // buffer to write to, function will fail if buffer too small
                   num_bytes_blob,         // buffer size
                   num_bytes_written)) {   // num bytes written to buffer
    Logger::LogD("ERROR when Encode %s\n", path_to_file.c_str());
    return false;
  }

  // write to file
  FILE* file = fopen(output_path.c_str(), "wb");
  fwrite(lerc_buffer, 1, num_bytes_written, file); // write bytes
  fclose(file);

  // clean memory
  delete[] data;

  return true;
}

NS_GAGO_END
<commit_msg>Add missing stdio.h include.<commit_after>// lerc.cc
//
// Copyright (c) 2016 Frank Lin (lin.xiaoe.f@gmail.com)
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.

#include "lerc_util.h"

#include <stdio.h>

#include "tiffio.h"

#include "Lerc/Lerc.h"

NS_GAGO_BEGIN

////////////////////////////////////////////////////////////////////////////////
// Lerc, public:

// Tiff --------------------------------------------------------

bool LercUtil::EncodeTiffOrDie(const std::string& path_to_file, const std::string& output_path,
                               double max_z_error, LercVersion lerc_ver, DataType data_type,
                               uint16_t band, bool signed_type) {
  Logger::LogD("Encoding %s", path_to_file.c_str());
  TIFF* tif = TIFFOpen(path_to_file.c_str(), "r");
  if (tif == nullptr) {
    Logger::LogD("ERROR when TIFFOpen %s\n", path_to_file.c_str());
    return false;
  }

  uint32_t width = 0;
  uint32_t height = 0;
  tdata_t buf;

  uint32_t tiff_dt = 0;

  uint32_t bits_per_sample = 0;

  TIFFGetField(tif, TIFFTAG_IMAGEWIDTH, &width);
  TIFFGetField(tif, TIFFTAG_IMAGELENGTH, &height);
  TIFFGetField(tif, TIFFTAG_DATATYPE, &tiff_dt);
  TIFFGetField(tif, TIFFTAG_BITSPERSAMPLE, &bits_per_sample);

  uint32_t type_size = 0;
  if (tiff_dt == SAMPLEFORMAT_INT) {
    if (bits_per_sample == 8) {
      data_type = signed_type ? DataType::CHAR : DataType::BYTE;
      type_size = sizeof(int8_t);
    } else if (bits_per_sample == 16) {
      data_type = signed_type ? DataType::SHORT : DataType::USHORT;
      type_size = sizeof(int16_t);
    } else if (bits_per_sample == 32) {
      data_type = signed_type ? DataType::INT : DataType::UINT;
      type_size = sizeof(int32_t);
    } else {
      Logger::LogD("Unknown bits per sample %s", path_to_file.c_str());
    }
  } else if (tiff_dt == SAMPLEFORMAT_IEEEFP) {
    data_type = DataType::FLOAT;
    type_size = 4;
  } else {
    Logger::LogD("Unsupported TIFF data format %s", path_to_file.c_str());
    return false;
  }

  // data
  unsigned char* data = new unsigned char[width * height * type_size];

  size_t line_size = TIFFScanlineSize(tif);

  for (int row = 0; row < height; ++row) {
    buf = _TIFFmalloc(line_size);
    TIFFReadScanline(tif, buf, row, bits_per_sample);

    memcpy(data + width * row * type_size, buf, line_size);

    _TIFFfree(buf);
  }

  TIFFClose(tif);

  // compress float buffer to lerc
  size_t num_bytes_needed = 0;
  size_t num_bytes_written = 0;
  LercNS::Lerc lerc;

  // convert data type to proper one
  LercNS::Lerc::DataType lerc_dt = static_cast<LercNS::Lerc::DataType>(data_type);
  if (lerc_dt == LercNS::Lerc::DataType::DT_Double ||
      lerc_dt == LercNS::Lerc::DataType::DT_Char ||
      lerc_dt == LercNS::Lerc::DataType::DT_Short ||
      lerc_dt == LercNS::Lerc::DataType::DT_UShort ||
      lerc_dt == LercNS::Lerc::DataType::DT_Undefined) {
    Logger::LogD("ERROR input data type %s\n", path_to_file.c_str());
    return false;
  }

  if (!lerc.ComputeBufferSize((void*)data,                   // raw image data, row by row, band by band
                              lerc_dt,
                              width, height, band,
                              0,                             // set 0 if all pixels are valid
                              max_z_error,                   // max coding error per pixel, or precision
                              num_bytes_needed)) {           // size of outgoing Lerc blob
    Logger::LogD("ERROR when ComputeBufferSize %s\n", path_to_file.c_str());
    return false;
  }

  size_t num_bytes_blob = num_bytes_needed;
  LercNS::Byte* lerc_buffer = new LercNS::Byte[num_bytes_blob];

  if (!lerc.Encode((void*)data,            // raw image data, row by row, band by band
                   lerc_dt,
                   width, height, band,
                   0,                      // 0 if all pixels are valid
                   max_z_error,            // max coding error per pixel, or precision
                   lerc_buffer,            // buffer to write to, function will fail if buffer too small
                   num_bytes_blob,         // buffer size
                   num_bytes_written)) {   // num bytes written to buffer
    Logger::LogD("ERROR when Encode %s\n", path_to_file.c_str());
    return false;
  }

  // write to file
  FILE* file = fopen(output_path.c_str(), "wb");
  fwrite(lerc_buffer, 1, num_bytes_written, file); // write bytes
  fclose(file);

  // clean memory
  delete[] data;

  return true;
}

NS_GAGO_END
<|endoftext|>


<commit_before>/******************************************************************************
The MIT License(MIT)

Embedded Template Library.
https://github.com/ETLCPP/etl
http://www.etlcpp.com

Copyright(c) 2014 jwellbelove

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/

#include <UnitTest++/UnitTest++.h>

#include <iterator>
#include <string>
#include <vector>
#include <stdint.h>

#include "../bsd_checksum.h"
#include "../endian.h"

template <typename TSum, typename TIterator>
TSum reference_checksum(TIterator begin, TIterator end)
{
  typedef typename std::iterator_traits<TIterator>::value_type value_type;
  TSum checksum = 0;

  while (begin != end)
  {
    value_type value = *begin++;

    for (int i = 0; i < sizeof(value_type); ++i)
    {
      uint8_t byte = (value >> (i * 8)) & 0xFF;
      checksum = etl::rotate_right(checksum) + byte;
    }
  }

  return checksum;
}

namespace
{
  SUITE(test_checksum)
  {
    //*************************************************************************
    TEST(test_checksum_constructor)
    {
      std::string data("123456789");

      uint8_t sum     = etl::bsd_checksum<uint8_t>(data.begin(), data.end());
      uint8_t compare = reference_checksum<uint8_t>(data.begin(), data.end());

      CHECK_EQUAL(int(compare), int(sum));
    }

    //*************************************************************************
    TEST(test_checksum_add_values8_add)
    {
      std::string data("123456789");

      etl::bsd_checksum<uint8_t> checksum_calculator;

      for (size_t i = 0; i < data.size(); ++i)
      {
        checksum_calculator.add(data[i]);
      }

      uint8_t sum     = checksum_calculator;
      uint8_t compare = reference_checksum<uint8_t>(data.begin(), data.end());

      CHECK_EQUAL(int(compare), int(sum));
    }

    //*************************************************************************
    TEST(test_checksum_add_values8_operator_plus_equals)
    {
      std::string data("123456789");

      etl::bsd_checksum<uint8_t> checksum_calculator;

      for (size_t i = 0; i < data.size(); ++i)
      {
        checksum_calculator.add(data[i]);
      }

      uint8_t sum     = checksum_calculator;
      uint8_t compare = reference_checksum<uint8_t>(data.begin(), data.end());

      CHECK_EQUAL(int(compare), int(sum));
    }

    //*************************************************************************
    TEST(test_checksum_add_range)
    {
      std::string data("123456789");

      etl::bsd_checksum<uint8_t> checksum_calculator;

      checksum_calculator.add(data.begin(), data.end());

      uint8_t sum     = checksum_calculator.value();
      uint8_t compare = reference_checksum<uint8_t>(data.begin(), data.end());

      CHECK_EQUAL(int(compare), int(sum));
    }

    //*************************************************************************
    TEST(test_checksum_add_range_sum32)
    {
      std::string data("1");

      etl::bsd_checksum<uint32_t> checksum_calculator;

      checksum_calculator.add(data.begin(), data.end());

      uint32_t sum     = checksum_calculator.value();
      uint32_t compare = reference_checksum<uint32_t>(data.begin(), data.end());

      CHECK_EQUAL(compare, sum);
    }

    //*************************************************************************
    TEST(test_checksum_add_range_endian)
    {
      std::vector<uint8_t>  data1 = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
      std::vector<uint32_t> data2 = { 0x04030201, 0x08070605 };
      std::vector<uint8_t>  data3 = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };

      uint64_t hash1 = etl::bsd_checksum<uint8_t>(data1.begin(), data1.end());
      uint64_t hash2 = etl::bsd_checksum<uint8_t>((uint8_t*)&data2[0], (uint8_t*)&data2[0] + (data2.size() * sizeof(uint32_t)));
      uint64_t hash3 = etl::bsd_checksum<uint8_t>(data3.rbegin(), data3.rend());
      CHECK_EQUAL(hash1, hash2);
      CHECK_EQUAL(hash1, hash3);
    }
  };
}

<commit_msg>Modified checksum class to be easily customised. Added sum, bsd & xor policies. Deleted bsd_checksum.h<commit_after>/******************************************************************************
The MIT License(MIT)

Embedded Template Library.
https://github.com/ETLCPP/etl
http://www.etlcpp.com

Copyright(c) 2014 jwellbelove

Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files(the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and / or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions :

The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.

THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
******************************************************************************/

#include <UnitTest++/UnitTest++.h>

#include <iterator>
#include <string>
#include <vector>
#include <stdint.h>

#include "../checksum.h"

namespace
{
  template <typename TSum, typename TIterator>
  TSum reference_checksum(TIterator begin, TIterator end)
  {
    typedef typename std::iterator_traits<TIterator>::value_type value_type;
    TSum checksum = 0;

    while (begin != end)
    {
      value_type value = *begin++;

      for (int i = 0; i < sizeof(value_type); ++i)
      {
        uint8_t byte = (value >> (i * 8)) & 0xFF;
        checksum = etl::rotate_right(checksum) + byte;
      }
    }

    return checksum;
  }

  SUITE(test_checksum)
  {
    //*************************************************************************
    TEST(test_checksum_constructor)
    {
      std::string data("123456789");

      uint8_t sum     = etl::bsd_checksum<uint8_t>(data.begin(), data.end());
      uint8_t compare = reference_checksum<uint8_t>(data.begin(), data.end());

      CHECK_EQUAL(int(compare), int(sum));
    }

    //*************************************************************************
    TEST(test_checksum_add_values8_add)
    {
      std::string data("123456789");

      etl::bsd_checksum<uint8_t> checksum_calculator;

      for (size_t i = 0; i < data.size(); ++i)
      {
        checksum_calculator.add(data[i]);
      }

      uint8_t sum     = checksum_calculator;
      uint8_t compare = reference_checksum<uint8_t>(data.begin(), data.end());

      CHECK_EQUAL(int(compare), int(sum));
    }

    //*************************************************************************
    TEST(test_checksum_add_values8_operator_plus_equals)
    {
      std::string data("123456789");

      etl::bsd_checksum<uint8_t> checksum_calculator;

      for (size_t i = 0; i < data.size(); ++i)
      {
        checksum_calculator.add(data[i]);
      }

      uint8_t sum     = checksum_calculator;
      uint8_t compare = reference_checksum<uint8_t>(data.begin(), data.end());

      CHECK_EQUAL(int(compare), int(sum));
    }

    //*************************************************************************
    TEST(test_checksum_add_range)
    {
      std::string data("123456789");

      etl::bsd_checksum<uint8_t> checksum_calculator;

      checksum_calculator.add(data.begin(), data.end());

      uint8_t sum     = checksum_calculator.value();
      uint8_t compare = reference_checksum<uint8_t>(data.begin(), data.end());

      CHECK_EQUAL(int(compare), int(sum));
    }

    //*************************************************************************
    TEST(test_checksum_add_range_sum32)
    {
      std::string data("1");

      etl::bsd_checksum<uint32_t> checksum_calculator;

      checksum_calculator.add(data.begin(), data.end());

      uint32_t sum     = checksum_calculator.value();
      uint32_t compare = reference_checksum<uint32_t>(data.begin(), data.end());

      CHECK_EQUAL(compare, sum);
    }

    //*************************************************************************
    TEST(test_checksum_add_range_endian)
    {
      std::vector<uint8_t>  data1 = { 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08 };
      std::vector<uint32_t> data2 = { 0x04030201, 0x08070605 };
      std::vector<uint8_t>  data3 = { 0x08, 0x07, 0x06, 0x05, 0x04, 0x03, 0x02, 0x01 };

      uint64_t hash1 = etl::bsd_checksum<uint8_t>(data1.begin(), data1.end());
      uint64_t hash2 = etl::bsd_checksum<uint8_t>((uint8_t*)&data2[0], (uint8_t*)&data2[0] + (data2.size() * sizeof(uint32_t)));
      uint64_t hash3 = etl::bsd_checksum<uint8_t>(data3.rbegin(), data3.rend());
      CHECK_EQUAL(hash1, hash2);
      CHECK_EQUAL(hash1, hash3);
    }
  };
}

<|endoftext|>


<commit_before>/* tcpstream.cpp
   Copyright (C) 2003-2005 Tommi Maekitalo

This file is part of cxxtools.

Cxxtools is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

Cxxtools is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Cxxtools; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA  02111-1307  USA
*/

#include "cxxtools/tcpstream.h"
#include <stdexcept>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/poll.h>
#include <errno.h>
#include <netdb.h>

#undef log_warn
#undef log_debug

#define log_warn(expr)
#define log_debug(expr)
//#define log_warn(expr)   do { std::cerr << "WARN: " << expr << std::endl; } while(false)
//#define log_debug(expr)  do { std::cerr << "DEBUG: " << expr << std::endl; } while(false)

namespace cxxtools
{

namespace tcp
{
  using namespace std;

  Exception::Exception(int Errno, const string& msg)
    : runtime_error(msg + ": " + strerror(Errno)),
      m_Errno(Errno)
    { }

  Exception::Exception(const string& msg)
    : runtime_error(msg + ": " + strerror(errno)),
      m_Errno(errno)
    { }

  ////////////////////////////////////////////////////////////////////////
  // implementation of Socket
  //
  Socket::Socket(int domain, int type, int protocol) throw (Exception)
    : m_timeout(-1)
  {
    if ((m_sockFd = ::socket(domain, type, protocol)) < 0)
      throw Exception("cannot create socket");
  }

  Socket::~Socket()
  {
    if (m_sockFd >= 0)
    {
      if (::close(m_sockFd) < 0)
        fprintf(stderr, "error in close(%d)\n", (int)m_sockFd);
    }
  }

  void Socket::create(int domain, int type, int protocol) throw (Exception)
  {
    close();

    if ((m_sockFd = ::socket(domain, type, protocol)) < 0)
      throw Exception("cannot create socket");
  }

  void Socket::close()
  {
    if (m_sockFd >= 0)
    {
      ::close(m_sockFd);
      m_sockFd = -1;
    }
  }

  struct sockaddr Socket::getSockAddr() const throw (Exception)
  {
    struct sockaddr ret;

    socklen_t slen = sizeof(ret);
    if (::getsockname(getFd(), &ret, &slen) < 0)
      throw Exception("error in getsockname");

    return ret;
  }

  void Socket::setTimeout(int t)
  {
    m_timeout = t;

    if (getFd() >= 0)
    {
      long a = m_timeout >= 0 ? O_NONBLOCK : 0;
      log_debug("fcntl(" << getFd() << ", F_SETFL, " << a << ')');
      fcntl(getFd(), F_SETFL, a);
    }
  }

  ////////////////////////////////////////////////////////////////////////
  // implementation of Server
  //
  Server::Server()
    : Socket(AF_INET, SOCK_STREAM, 0)
  { }

  Server::Server(const std::string& ipaddr, unsigned short int port, int backlog)
                 throw (Exception)
    : Socket(AF_INET, SOCK_STREAM, 0)
  {
    Listen(ipaddr, port, backlog);
  }

  Server::Server(const char* ipaddr, unsigned short int port,
      int backlog) throw (Exception)
    : Socket(AF_INET, SOCK_STREAM, 0)
  {
    Listen(ipaddr, port, backlog);
  }

  void Server::Listen(const char* ipaddr, unsigned short int port,
      int backlog) throw (Exception)
  {
    struct hostent* host = ::gethostbyname(ipaddr);
    if (host == 0)
      throw Exception(std::string("invalid ipaddress ") + ipaddr);

    memset(&servaddr.sockaddr_in, 0, sizeof(servaddr.sockaddr_in));

    servaddr.sockaddr_in.sin_family = AF_INET;
    servaddr.sockaddr_in.sin_port = htons(port);

    memmove(&(servaddr.sockaddr_in.sin_addr.s_addr), host->h_addr, host->h_length);
    int reuseAddr = 1;
    if (::setsockopt(getFd(), SOL_SOCKET, SO_REUSEADDR,
        &reuseAddr, sizeof(reuseAddr)) < 0)
      throw Exception("error in setsockopt");

    if (::bind(getFd(),
               (struct sockaddr *)&servaddr.sockaddr_in,
               sizeof(servaddr.sockaddr_in)) < 0)
      throw Exception("error in bind");

    if (::listen(getFd(), backlog) < 0)
      throw Exception("error in listen");
  }

  ////////////////////////////////////////////////////////////////////////
  // implementation of Stream
  //
  Stream::Stream()
    { }

  Stream::Stream(const Server& server)
  {
    Accept(server);
  }

  Stream::Stream(const string& ipaddr, unsigned short int port)
    : Socket(AF_INET, SOCK_STREAM, 0)
  {
    Connect(ipaddr, port);
  }

  Stream::Stream(const char* ipaddr, unsigned short int port)
    : Socket(AF_INET, SOCK_STREAM, 0)
  {
    Connect(ipaddr, port);
  }

  void Stream::Accept(const Server& server)
  {
    close();

    socklen_t peeraddr_len;
    peeraddr_len = sizeof(peeraddr);
    setFd(accept(server.getFd(), &peeraddr.sockaddr, &peeraddr_len));
    if (bad())
      throw Exception("error in accept");

    setTimeout(getTimeout());
  }

  void Stream::Connect(const char* ipaddr, unsigned short int port)
  {
    if (getFd() < 0)
      create(AF_INET, SOCK_STREAM, 0);

    struct hostent* host = ::gethostbyname(ipaddr);
    if (host == 0)
      throw Exception(std::string("invalid ipaddress ") + ipaddr);

    memset(&peeraddr, 0, sizeof(peeraddr));
    peeraddr.sockaddr_in.sin_family = AF_INET;
    peeraddr.sockaddr_in.sin_port = htons(port);

    memmove(&(peeraddr.sockaddr_in.sin_addr.s_addr), host->h_addr, host->h_length);

    if (::connect(getFd(), &peeraddr.sockaddr,
        sizeof(peeraddr)) < 0)
      throw Exception("error in connect");

    setTimeout(getTimeout());
  }

  Stream::size_type Stream::Read(char* buffer, Stream::size_type bufsize) const
  {
    ssize_t n;

    if (getTimeout() < 0)
    {
      // blocking read
      log_debug("blocking read");
      n = ::read(getFd(), buffer, bufsize);
      log_debug("blocking read ready, return " << n);
      if (n < 0)
      {
        int errnum = errno;
        throw Exception(strerror(errnum));
      }
    }
    else
    {
      // non-blocking read

      // try reading without timeout
      log_debug("non blocking read fd=" << getFd());
      n = ::read(getFd(), buffer, bufsize);
      log_debug("non blocking read returns " << n);

      if (n < 0)
      {
        // no data available

        if (errno == EAGAIN)
        {
          if (getTimeout() == 0)
          {
            log_warn("timeout");
            throw Timeout();
          }

          struct pollfd fds;
          fds.fd = getFd();
          fds.events = POLLIN;
          log_debug("poll timeout " << getTimeout());
          int p = poll(&fds, 1, getTimeout());
          log_debug("poll returns " << p);
          if (p < 0)
          {
            int errnum = errno;
            throw Exception(strerror(errnum));
          }
          else if (p == 0)
            throw Timeout();

          log_debug("read");
          n = ::read(getFd(), buffer, bufsize);
          log_debug("read returns " << n);
        }
        else
        {
          int errnum = errno;
          throw Exception(strerror(errnum));
        }
      }

    }

    return n;
  }

  Stream::size_type Stream::Write(const char* buffer,
                                  Stream::size_type bufsize) const
  {
    size_t n = ::write(getFd(), buffer, bufsize);
    if (n <= 0)
      // au weia - das ging schief
      throw Exception("tcp::Stream: error in write");

    while (n < bufsize)
    {
      buffer += n;
      bufsize -= n;

      struct pollfd fds;
      fds.fd = getFd();
      fds.events = POLLOUT;
      int p = poll(&fds, 1, -1);

      if (p < 0)
      {
        int errnum = errno;
        throw Exception(strerror(errnum));
      }
      else if (p == 0)
        throw Timeout();

      n = ::write(getFd(), buffer, bufsize);
    }

    return n;
  }

  streambuf::streambuf(Stream& stream, unsigned bufsize, int timeout)
    : m_stream(stream),
      m_bufsize(bufsize),
      m_buffer(new char_type[bufsize])
  {
    setTimeout(timeout);
  }

  streambuf::int_type streambuf::overflow(streambuf::int_type c)
  {
    if (pptr() != pbase())
    {
      int n = m_stream.Write(pbase(), pptr() - pbase());
      if (n <= 0)
        return traits_type::eof();
    }

    setp(m_buffer, m_buffer + m_bufsize);
    if (c != traits_type::eof())
    {
      *pptr() = (char_type)c;
      pbump(1);
    }

    return 0;
  }

  streambuf::int_type streambuf::underflow()
  {
    Stream::size_type n = m_stream.Read(m_buffer, m_bufsize);
    if (n <= 0)
      return traits_type::eof();

    setg(m_buffer, m_buffer, m_buffer + n);
    return (int_type)(unsigned char)m_buffer[0];
  }

  int streambuf::sync()
  {
    if (pptr() != pbase())
    {
      int n = m_stream.Write(pbase(), pptr() - pbase());
      if (n <= 0)
        return -1;
      else
        setp(m_buffer, m_buffer + m_bufsize);
    }
    return 0;
  }

} // namespace tcp

} // namespace cxxtools
<commit_msg>simplified Write-method<commit_after>/* tcpstream.cpp
   Copyright (C) 2003-2005 Tommi Maekitalo

This file is part of cxxtools.

Cxxtools is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

Cxxtools is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with Cxxtools; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330,
Boston, MA  02111-1307  USA
*/

#include "cxxtools/tcpstream.h"
#include <stdexcept>
#include <sys/types.h>
#include <sys/socket.h>
#include <unistd.h>
#include <netinet/in.h>
#include <arpa/inet.h>
#include <fcntl.h>
#include <sys/poll.h>
#include <errno.h>
#include <netdb.h>

#undef log_warn
#undef log_debug

#define log_warn(expr)
#define log_debug(expr)
//#define log_warn(expr)   do { std::cerr << "WARN: " << expr << std::endl; } while(false)
//#define log_debug(expr)  do { std::cerr << "DEBUG: " << expr << std::endl; } while(false)

namespace cxxtools
{

namespace tcp
{
  using namespace std;

  Exception::Exception(int Errno, const string& msg)
    : runtime_error(msg + ": " + strerror(Errno)),
      m_Errno(Errno)
    { }

  Exception::Exception(const string& msg)
    : runtime_error(msg + ": " + strerror(errno)),
      m_Errno(errno)
    { }

  ////////////////////////////////////////////////////////////////////////
  // implementation of Socket
  //
  Socket::Socket(int domain, int type, int protocol) throw (Exception)
    : m_timeout(-1)
  {
    if ((m_sockFd = ::socket(domain, type, protocol)) < 0)
      throw Exception("cannot create socket");
  }

  Socket::~Socket()
  {
    if (m_sockFd >= 0)
    {
      if (::close(m_sockFd) < 0)
        fprintf(stderr, "error in close(%d)\n", (int)m_sockFd);
    }
  }

  void Socket::create(int domain, int type, int protocol) throw (Exception)
  {
    close();

    if ((m_sockFd = ::socket(domain, type, protocol)) < 0)
      throw Exception("cannot create socket");
  }

  void Socket::close()
  {
    if (m_sockFd >= 0)
    {
      ::close(m_sockFd);
      m_sockFd = -1;
    }
  }

  struct sockaddr Socket::getSockAddr() const throw (Exception)
  {
    struct sockaddr ret;

    socklen_t slen = sizeof(ret);
    if (::getsockname(getFd(), &ret, &slen) < 0)
      throw Exception("error in getsockname");

    return ret;
  }

  void Socket::setTimeout(int t)
  {
    m_timeout = t;

    if (getFd() >= 0)
    {
      long a = m_timeout >= 0 ? O_NONBLOCK : 0;
      log_debug("fcntl(" << getFd() << ", F_SETFL, " << a << ')');
      fcntl(getFd(), F_SETFL, a);
    }
  }

  ////////////////////////////////////////////////////////////////////////
  // implementation of Server
  //
  Server::Server()
    : Socket(AF_INET, SOCK_STREAM, 0)
  { }

  Server::Server(const std::string& ipaddr, unsigned short int port, int backlog)
                 throw (Exception)
    : Socket(AF_INET, SOCK_STREAM, 0)
  {
    Listen(ipaddr, port, backlog);
  }

  Server::Server(const char* ipaddr, unsigned short int port,
      int backlog) throw (Exception)
    : Socket(AF_INET, SOCK_STREAM, 0)
  {
    Listen(ipaddr, port, backlog);
  }

  void Server::Listen(const char* ipaddr, unsigned short int port,
      int backlog) throw (Exception)
  {
    struct hostent* host = ::gethostbyname(ipaddr);
    if (host == 0)
      throw Exception(std::string("invalid ipaddress ") + ipaddr);

    memset(&servaddr.sockaddr_in, 0, sizeof(servaddr.sockaddr_in));

    servaddr.sockaddr_in.sin_family = AF_INET;
    servaddr.sockaddr_in.sin_port = htons(port);

    memmove(&(servaddr.sockaddr_in.sin_addr.s_addr), host->h_addr, host->h_length);
    int reuseAddr = 1;
    if (::setsockopt(getFd(), SOL_SOCKET, SO_REUSEADDR,
        &reuseAddr, sizeof(reuseAddr)) < 0)
      throw Exception("error in setsockopt");

    if (::bind(getFd(),
               (struct sockaddr *)&servaddr.sockaddr_in,
               sizeof(servaddr.sockaddr_in)) < 0)
      throw Exception("error in bind");

    if (::listen(getFd(), backlog) < 0)
      throw Exception("error in listen");
  }

  ////////////////////////////////////////////////////////////////////////
  // implementation of Stream
  //
  Stream::Stream()
    { }

  Stream::Stream(const Server& server)
  {
    Accept(server);
  }

  Stream::Stream(const string& ipaddr, unsigned short int port)
    : Socket(AF_INET, SOCK_STREAM, 0)
  {
    Connect(ipaddr, port);
  }

  Stream::Stream(const char* ipaddr, unsigned short int port)
    : Socket(AF_INET, SOCK_STREAM, 0)
  {
    Connect(ipaddr, port);
  }

  void Stream::Accept(const Server& server)
  {
    close();

    socklen_t peeraddr_len;
    peeraddr_len = sizeof(peeraddr);
    setFd(accept(server.getFd(), &peeraddr.sockaddr, &peeraddr_len));
    if (bad())
      throw Exception("error in accept");

    setTimeout(getTimeout());
  }

  void Stream::Connect(const char* ipaddr, unsigned short int port)
  {
    if (getFd() < 0)
      create(AF_INET, SOCK_STREAM, 0);

    struct hostent* host = ::gethostbyname(ipaddr);
    if (host == 0)
      throw Exception(std::string("invalid ipaddress ") + ipaddr);

    memset(&peeraddr, 0, sizeof(peeraddr));
    peeraddr.sockaddr_in.sin_family = AF_INET;
    peeraddr.sockaddr_in.sin_port = htons(port);

    memmove(&(peeraddr.sockaddr_in.sin_addr.s_addr), host->h_addr, host->h_length);

    if (::connect(getFd(), &peeraddr.sockaddr,
        sizeof(peeraddr)) < 0)
      throw Exception("error in connect");

    setTimeout(getTimeout());
  }

  Stream::size_type Stream::Read(char* buffer, Stream::size_type bufsize) const
  {
    ssize_t n;

    if (getTimeout() < 0)
    {
      // blocking read
      log_debug("blocking read");
      n = ::read(getFd(), buffer, bufsize);
      log_debug("blocking read ready, return " << n);
      if (n < 0)
      {
        int errnum = errno;
        throw Exception(strerror(errnum));
      }
    }
    else
    {
      // non-blocking read

      // try reading without timeout
      log_debug("non blocking read fd=" << getFd());
      n = ::read(getFd(), buffer, bufsize);
      log_debug("non blocking read returns " << n);

      if (n < 0)
      {
        // no data available

        if (errno == EAGAIN)
        {
          if (getTimeout() == 0)
          {
            log_warn("timeout");
            throw Timeout();
          }

          struct pollfd fds;
          fds.fd = getFd();
          fds.events = POLLIN;
          log_debug("poll timeout " << getTimeout());
          int p = poll(&fds, 1, getTimeout());
          log_debug("poll returns " << p);
          if (p < 0)
          {
            int errnum = errno;
            throw Exception(strerror(errnum));
          }
          else if (p == 0)
            throw Timeout();

          log_debug("read");
          n = ::read(getFd(), buffer, bufsize);
          log_debug("read returns " << n);
        }
        else
        {
          int errnum = errno;
          throw Exception(strerror(errnum));
        }
      }

    }

    return n;
  }

  Stream::size_type Stream::Write(const char* buffer,
                                  Stream::size_type bufsize) const
  {
    size_t n = 0;
    size_type s = bufsize;

    while (n < s)
    {
      n = ::write(getFd(), buffer, s);
      if (n <= 0)
        // au weia - das ging schief
        throw Exception("tcp::Stream: error in write");

      buffer += n;
      s -= n;

      if (s == 0)
        break;

      struct pollfd fds;
      fds.fd = getFd();
      fds.events = POLLOUT;
      int p = poll(&fds, 1, -1);

      if (p < 0)
      {
        int errnum = errno;
        throw Exception(strerror(errnum));
      }
      else if (p == 0)
        throw Timeout();
    }

    return bufsize;
  }

  streambuf::streambuf(Stream& stream, unsigned bufsize, int timeout)
    : m_stream(stream),
      m_bufsize(bufsize),
      m_buffer(new char_type[bufsize])
  {
    setTimeout(timeout);
  }

  streambuf::int_type streambuf::overflow(streambuf::int_type c)
  {
    if (pptr() != pbase())
    {
      int n = m_stream.Write(pbase(), pptr() - pbase());
      if (n <= 0)
        return traits_type::eof();
    }

    setp(m_buffer, m_buffer + m_bufsize);
    if (c != traits_type::eof())
    {
      *pptr() = (char_type)c;
      pbump(1);
    }

    return 0;
  }

  streambuf::int_type streambuf::underflow()
  {
    Stream::size_type n = m_stream.Read(m_buffer, m_bufsize);
    if (n <= 0)
      return traits_type::eof();

    setg(m_buffer, m_buffer, m_buffer + n);
    return (int_type)(unsigned char)m_buffer[0];
  }

  int streambuf::sync()
  {
    if (pptr() != pbase())
    {
      int n = m_stream.Write(pbase(), pptr() - pbase());
      if (n <= 0)
        return -1;
      else
        setp(m_buffer, m_buffer + m_bufsize);
    }
    return 0;
  }

} // namespace tcp

} // namespace cxxtools
<|endoftext|>


<commit_before>#include <functional>
#include <iostream>
#include <fstream>
#include <queue>
#include <tuple>
#include <vector>

#include <libfuzzymatch/levenshteinLimit.h>
#include <libfuzzymatch/util.h>

#include "../common/pairwise.h"
#include "../common/plain_index.h"
#include "../common/timer.h"

int main(int argc, char *argv[]) {
    if (argc != 4) {
        std::cerr << "Usage: \n\t query-index <index> <query-file> <threshold>" << std::endl;
        exit(EXIT_FAILURE);
    }

    std::vector<std::string> queries;
    std::ifstream file(argv[2]);
    for (std::string line; std::getline(file, line);) {
        queries.push_back(line);
    }
    file.close();

    std::vector<std::vector<uint32_t>> index;
    loadIndex(argv[1], index);

    const uint32_t threshold(atoi(argv[3]));

    Timer timer;

    benchLevenshtein(queries, index, [=](const std::vector<uint32_t> &s, const std::vector<uint32_t> &t) {
        return levenshteinLimit(s, t, threshold);
    });
    std::cout << "Took " << timer.getAndReset() << "s to execute the queries." << std::endl;
    std::cout << "RESULT algo=limit threshold=" << threshold << " index=" << argv[1] << " queries=" << argv[2] << std::endl;
}
<commit_msg>print time in limited levenshtein benchmark<commit_after>#include <functional>
#include <iostream>
#include <fstream>
#include <queue>
#include <tuple>
#include <vector>

#include <libfuzzymatch/levenshteinLimit.h>
#include <libfuzzymatch/util.h>

#include "../common/pairwise.h"
#include "../common/plain_index.h"
#include "../common/timer.h"

int main(int argc, char *argv[]) {
    if (argc != 4) {
        std::cerr << "Usage: \n\t query-index <index> <query-file> <threshold>" << std::endl;
        exit(EXIT_FAILURE);
    }

    std::vector<std::string> queries;
    std::ifstream file(argv[2]);
    for (std::string line; std::getline(file, line);) {
        queries.push_back(line);
    }
    file.close();

    std::vector<std::vector<uint32_t>> index;
    loadIndex(argv[1], index);

    const uint32_t threshold(atoi(argv[3]));

    Timer timer;

    benchLevenshtein(queries, index, [=](const std::vector<uint32_t> &s, const std::vector<uint32_t> &t) {
        return levenshteinLimit(s, t, threshold);
    });
    auto t = timer.get();
    std::cout << "Took " << t << "s to execute the queries." << std::endl;
    std::cout << "RESULT algo=limit threshold=" << threshold << " index=" << argv[1] << " queries=" << argv[2] << " time=" << t << std::endl;
}
<|endoftext|>


<commit_before>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

#include "base/logging.h"
#include "base/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "chrome/browser/safe_browsing/protocol_manager.h"

// Ensure that we respect section 5 of the SafeBrowsing protocol specification.
TEST(SafeBrowsingProtocolManagerTest, TestBackOffTimes) {
  SafeBrowsingProtocolManager pm(NULL, NULL, "", "");
  pm.next_update_sec_ = 1800;
  DCHECK(pm.back_off_fuzz_ >= 0.0 && pm.back_off_fuzz_ <= 1.0);

  // No errors received so far.
  EXPECT_EQ(pm.GetNextUpdateTime(false), 1800 * 1000);

  // 1 error.
  EXPECT_EQ(pm.GetNextUpdateTime(true), 60 * 1000);

  // 2 errors.
  int next_time = pm.GetNextUpdateTime(true) / (60 * 1000);  // Minutes
  EXPECT_TRUE(next_time >= 30 && next_time <= 60);

  // 3 errors.
  next_time = pm.GetNextUpdateTime(true) / (60 * 1000);
  EXPECT_TRUE(next_time >= 60 && next_time <= 120);

  // 4 errors.
  next_time = pm.GetNextUpdateTime(true) / (60 * 1000);
  EXPECT_TRUE(next_time >= 120 && next_time <= 240);

  // 5 errors.
  next_time = pm.GetNextUpdateTime(true) / (60 * 1000);
  EXPECT_TRUE(next_time >= 240 && next_time <= 480);

  // 6 errors, reached max backoff.
  EXPECT_EQ(pm.GetNextUpdateTime(true), 480 * 60 * 1000);

  // 7 errors.
  EXPECT_EQ(pm.GetNextUpdateTime(true), 480 * 60 * 1000);

  // Received a successful response.
  EXPECT_EQ(pm.GetNextUpdateTime(false), 1800 * 1000);
}

// Test string combinations with and without MAC.
TEST(SafeBrowsingProtocolManagerTest, TestChunkStrings) {
  SafeBrowsingProtocolManager pm(NULL, NULL, "", "");

  // Add and Sub chunks.
  SBListChunkRanges phish("goog-phish-shavar");
  phish.adds = "1,4,6,8-20,99";
  phish.subs = "16,32,64-96";
  EXPECT_EQ(pm.FormatList(phish, false),
            "goog-phish-shavar;a:1,4,6,8-20,99:s:16,32,64-96\n");
  EXPECT_EQ(pm.FormatList(phish, true),
            "goog-phish-shavar;a:1,4,6,8-20,99:s:16,32,64-96:mac\n");

  // Add chunks only.
  phish.subs = "";
  EXPECT_EQ(pm.FormatList(phish, false),
            "goog-phish-shavar;a:1,4,6,8-20,99\n");
  EXPECT_EQ(pm.FormatList(phish, true),
            "goog-phish-shavar;a:1,4,6,8-20,99:mac\n");

  // Sub chunks only.
  phish.adds = "";
  phish.subs = "16,32,64-96";
  EXPECT_EQ(pm.FormatList(phish, false), "goog-phish-shavar;s:16,32,64-96\n");
  EXPECT_EQ(pm.FormatList(phish, true), "goog-phish-shavar;s:16,32,64-96:mac\n");

  // No chunks of either type.
  phish.adds = "";
  phish.subs = "";
  EXPECT_EQ(pm.FormatList(phish, false), "goog-phish-shavar;\n");
  EXPECT_EQ(pm.FormatList(phish, true), "goog-phish-shavar;mac\n");
}

TEST(SafeBrowsingProtocolManagerTest, TestGetHashBackOffTimes) {
  SafeBrowsingProtocolManager pm(NULL, NULL, "", "");

  // No errors or back off time yet.
  EXPECT_EQ(pm.gethash_error_count_, 0);
  EXPECT_TRUE(pm.next_gethash_time_.is_null());

  Time now = Time::Now();

  // 1 error.
  pm.HandleGetHashError();
  EXPECT_EQ(pm.gethash_error_count_, 1);
  TimeDelta margin = TimeDelta::FromSeconds(5);  // Fudge factor.
  Time future = now + TimeDelta::FromMinutes(1);
  EXPECT_TRUE(pm.next_gethash_time_ >= future - margin &&
              pm.next_gethash_time_ <= future + margin);

  // 2 errors.
  pm.HandleGetHashError();
  EXPECT_EQ(pm.gethash_error_count_, 2);
  EXPECT_TRUE(pm.next_gethash_time_ >= now + TimeDelta::FromMinutes(30));
  EXPECT_TRUE(pm.next_gethash_time_ <= now + TimeDelta::FromMinutes(60));

  // 3 errors.
  pm.HandleGetHashError();
  EXPECT_EQ(pm.gethash_error_count_, 3);
  EXPECT_TRUE(pm.next_gethash_time_ >= now + TimeDelta::FromMinutes(60));
  EXPECT_TRUE(pm.next_gethash_time_ <= now + TimeDelta::FromMinutes(120));

  // 4 errors.
  pm.HandleGetHashError();
  EXPECT_EQ(pm.gethash_error_count_, 4);
  EXPECT_TRUE(pm.next_gethash_time_ >= now + TimeDelta::FromMinutes(120));
  EXPECT_TRUE(pm.next_gethash_time_ <= now + TimeDelta::FromMinutes(240));

  // 5 errors.
  pm.HandleGetHashError();
  EXPECT_EQ(pm.gethash_error_count_, 5);
  EXPECT_TRUE(pm.next_gethash_time_ >= now + TimeDelta::FromMinutes(240));
  EXPECT_TRUE(pm.next_gethash_time_ <= now + TimeDelta::FromMinutes(480));

  // 6 errors, reached max backoff.
  pm.HandleGetHashError();
  EXPECT_EQ(pm.gethash_error_count_, 6);
  EXPECT_TRUE(pm.next_gethash_time_ == now + TimeDelta::FromMinutes(480));

  // 7 errors.
  pm.HandleGetHashError();
  EXPECT_EQ(pm.gethash_error_count_, 7);
  EXPECT_TRUE(pm.next_gethash_time_== now + TimeDelta::FromMinutes(480));
}

<commit_msg>Disable a flakey test. BUG=http://code.google.com/p/chromium/issues/detail?id=1880 Review URL: http://codereview.chromium.org/1816<commit_after>// Copyright (c) 2006-2008 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.
//

#include "base/logging.h"
#include "base/time.h"
#include "testing/gtest/include/gtest/gtest.h"
#include "chrome/browser/safe_browsing/protocol_manager.h"

// Ensure that we respect section 5 of the SafeBrowsing protocol specification.
TEST(SafeBrowsingProtocolManagerTest, TestBackOffTimes) {
  SafeBrowsingProtocolManager pm(NULL, NULL, "", "");
  pm.next_update_sec_ = 1800;
  DCHECK(pm.back_off_fuzz_ >= 0.0 && pm.back_off_fuzz_ <= 1.0);

  // No errors received so far.
  EXPECT_EQ(pm.GetNextUpdateTime(false), 1800 * 1000);

  // 1 error.
  EXPECT_EQ(pm.GetNextUpdateTime(true), 60 * 1000);

  // 2 errors.
  int next_time = pm.GetNextUpdateTime(true) / (60 * 1000);  // Minutes
  EXPECT_TRUE(next_time >= 30 && next_time <= 60);

  // 3 errors.
  next_time = pm.GetNextUpdateTime(true) / (60 * 1000);
  EXPECT_TRUE(next_time >= 60 && next_time <= 120);

  // 4 errors.
  next_time = pm.GetNextUpdateTime(true) / (60 * 1000);
  EXPECT_TRUE(next_time >= 120 && next_time <= 240);

  // 5 errors.
  next_time = pm.GetNextUpdateTime(true) / (60 * 1000);
  EXPECT_TRUE(next_time >= 240 && next_time <= 480);

  // 6 errors, reached max backoff.
  EXPECT_EQ(pm.GetNextUpdateTime(true), 480 * 60 * 1000);

  // 7 errors.
  EXPECT_EQ(pm.GetNextUpdateTime(true), 480 * 60 * 1000);

  // Received a successful response.
  EXPECT_EQ(pm.GetNextUpdateTime(false), 1800 * 1000);
}

// Test string combinations with and without MAC.
TEST(SafeBrowsingProtocolManagerTest, TestChunkStrings) {
  SafeBrowsingProtocolManager pm(NULL, NULL, "", "");

  // Add and Sub chunks.
  SBListChunkRanges phish("goog-phish-shavar");
  phish.adds = "1,4,6,8-20,99";
  phish.subs = "16,32,64-96";
  EXPECT_EQ(pm.FormatList(phish, false),
            "goog-phish-shavar;a:1,4,6,8-20,99:s:16,32,64-96\n");
  EXPECT_EQ(pm.FormatList(phish, true),
            "goog-phish-shavar;a:1,4,6,8-20,99:s:16,32,64-96:mac\n");

  // Add chunks only.
  phish.subs = "";
  EXPECT_EQ(pm.FormatList(phish, false),
            "goog-phish-shavar;a:1,4,6,8-20,99\n");
  EXPECT_EQ(pm.FormatList(phish, true),
            "goog-phish-shavar;a:1,4,6,8-20,99:mac\n");

  // Sub chunks only.
  phish.adds = "";
  phish.subs = "16,32,64-96";
  EXPECT_EQ(pm.FormatList(phish, false), "goog-phish-shavar;s:16,32,64-96\n");
  EXPECT_EQ(pm.FormatList(phish, true), "goog-phish-shavar;s:16,32,64-96:mac\n");

  // No chunks of either type.
  phish.adds = "";
  phish.subs = "";
  EXPECT_EQ(pm.FormatList(phish, false), "goog-phish-shavar;\n");
  EXPECT_EQ(pm.FormatList(phish, true), "goog-phish-shavar;mac\n");
}

// Flakey, see http://code.google.com/p/chromium/issues/detail?id=1880
TEST(SafeBrowsingProtocolManagerTest, DISABLED_TestGetHashBackOffTimes) {
  SafeBrowsingProtocolManager pm(NULL, NULL, "", "");

  // No errors or back off time yet.
  EXPECT_EQ(pm.gethash_error_count_, 0);
  EXPECT_TRUE(pm.next_gethash_time_.is_null());

  Time now = Time::Now();

  // 1 error.
  pm.HandleGetHashError();
  EXPECT_EQ(pm.gethash_error_count_, 1);
  TimeDelta margin = TimeDelta::FromSeconds(5);  // Fudge factor.
  Time future = now + TimeDelta::FromMinutes(1);
  EXPECT_TRUE(pm.next_gethash_time_ >= future - margin &&
              pm.next_gethash_time_ <= future + margin);

  // 2 errors.
  pm.HandleGetHashError();
  EXPECT_EQ(pm.gethash_error_count_, 2);
  EXPECT_TRUE(pm.next_gethash_time_ >= now + TimeDelta::FromMinutes(30));
  EXPECT_TRUE(pm.next_gethash_time_ <= now + TimeDelta::FromMinutes(60));

  // 3 errors.
  pm.HandleGetHashError();
  EXPECT_EQ(pm.gethash_error_count_, 3);
  EXPECT_TRUE(pm.next_gethash_time_ >= now + TimeDelta::FromMinutes(60));
  EXPECT_TRUE(pm.next_gethash_time_ <= now + TimeDelta::FromMinutes(120));

  // 4 errors.
  pm.HandleGetHashError();
  EXPECT_EQ(pm.gethash_error_count_, 4);
  EXPECT_TRUE(pm.next_gethash_time_ >= now + TimeDelta::FromMinutes(120));
  EXPECT_TRUE(pm.next_gethash_time_ <= now + TimeDelta::FromMinutes(240));

  // 5 errors.
  pm.HandleGetHashError();
  EXPECT_EQ(pm.gethash_error_count_, 5);
  EXPECT_TRUE(pm.next_gethash_time_ >= now + TimeDelta::FromMinutes(240));
  EXPECT_TRUE(pm.next_gethash_time_ <= now + TimeDelta::FromMinutes(480));

  // 6 errors, reached max backoff.
  pm.HandleGetHashError();
  EXPECT_EQ(pm.gethash_error_count_, 6);
  EXPECT_TRUE(pm.next_gethash_time_ == now + TimeDelta::FromMinutes(480));

  // 7 errors.
  pm.HandleGetHashError();
  EXPECT_EQ(pm.gethash_error_count_, 7);
  EXPECT_TRUE(pm.next_gethash_time_== now + TimeDelta::FromMinutes(480));
}
<|endoftext|>