<commit_before>// Copyright (c) 2011 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 "webkit/plugins/ppapi/quota_file_io.h"

#include <algorithm>

#include "base/bind.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop_proxy.h"
#include "base/stl_util.h"
#include "webkit/plugins/ppapi/host_globals.h"
#include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
#include "webkit/plugins/ppapi/resource_helper.h"

using base::PlatformFile;
using base::PlatformFileError;
using quota::StorageType;

namespace webkit {
namespace ppapi {

namespace {
StorageType PPFileSystemTypeToQuotaStorageType(PP_FileSystemType type) {
  switch (type) {
    case PP_FILESYSTEMTYPE_LOCALPERSISTENT:
      return quota::kStorageTypePersistent;
    case PP_FILESYSTEMTYPE_LOCALTEMPORARY:
      return quota::kStorageTypeTemporary;
    default:
      return quota::kStorageTypeUnknown;
  }
  NOTREACHED();
  return quota::kStorageTypeUnknown;
}
}  // namespace

class QuotaFileIO::PendingOperationBase {
 public:
  virtual ~PendingOperationBase() {}

  // Either one of Run() or DidFail() is called (the latter is called when
  // there was more than one error during quota queries).
  virtual void Run() = 0;
  virtual void DidFail(PlatformFileError error) = 0;

 protected:
  PendingOperationBase(QuotaFileIO* quota_io, bool is_will_operation)
      : quota_io_(quota_io), is_will_operation_(is_will_operation) {
    DCHECK(quota_io_);
    quota_io_->WillUpdate();
  }

  QuotaFileIO* quota_io_;
  const bool is_will_operation_;
};

class QuotaFileIO::WriteOperation : public PendingOperationBase {
 public:
  WriteOperation(QuotaFileIO* quota_io,
                 bool is_will_operation,
                 int64_t offset,
                 const char* buffer,
                 int32_t bytes_to_write,
                 const WriteCallback& callback)
      : PendingOperationBase(quota_io, is_will_operation),
        offset_(offset),
        bytes_to_write_(bytes_to_write),
        callback_(callback),
        finished_(false),
        status_(base::PLATFORM_FILE_OK),
        bytes_written_(0),
        ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
    if (!is_will_operation) {
      // TODO(kinuko): Check the API convention if we really need to keep a copy
      // of the buffer during the async write operations.
      buffer_.reset(new char[bytes_to_write]);
      memcpy(buffer_.get(), buffer, bytes_to_write);
    }
  }
  virtual ~WriteOperation() {}
  virtual void Run() OVERRIDE {
    DCHECK(quota_io_);
    if (quota_io_->CheckIfExceedsQuota(offset_ + bytes_to_write_)) {
      DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE);
      return;
    }
    if (is_will_operation_) {
      // Assuming the write will succeed.
      DidFinish(base::PLATFORM_FILE_OK, bytes_to_write_);
      return;
    }
    DCHECK(buffer_.get());

    PluginDelegate* plugin_delegate = quota_io_->GetPluginDelegate();
    if (!plugin_delegate) {
      DidFail(base::PLATFORM_FILE_ERROR_FAILED);
      return;
    }

    if (!base::FileUtilProxy::Write(
            plugin_delegate->GetFileThreadMessageLoopProxy(),
            quota_io_->file_, offset_, buffer_.get(), bytes_to_write_,
            base::Bind(&WriteOperation::DidFinish,
                       weak_factory_.GetWeakPtr()))) {
      DidFail(base::PLATFORM_FILE_ERROR_FAILED);
      return;
    }
  }

  virtual void DidFail(PlatformFileError error) OVERRIDE {
    DidFinish(error, 0);
  }

  bool finished() const { return finished_; }

  virtual void WillRunCallback() {
    base::MessageLoopProxy::current()->PostTask(
        FROM_HERE,
        base::Bind(&WriteOperation::RunCallback, weak_factory_.GetWeakPtr()));
  }

 private:
  void DidFinish(PlatformFileError status, int bytes_written) {
    finished_ = true;
    status_ = status;
    bytes_written_ = bytes_written;
    int64_t max_offset =
        (status != base::PLATFORM_FILE_OK) ? 0 : offset_ + bytes_written;
    // This may delete itself by calling RunCallback.
    quota_io_->DidWrite(this, max_offset);
  }

  virtual void RunCallback() {
    DCHECK_EQ(false, callback_.is_null());
    callback_.Run(status_, bytes_written_);
    delete this;
  }

  const int64_t offset_;
  scoped_array<char> buffer_;
  const int32_t bytes_to_write_;
  WriteCallback callback_;
  bool finished_;
  PlatformFileError status_;
  int64_t bytes_written_;
  base::WeakPtrFactory<WriteOperation> weak_factory_;
};

class QuotaFileIO::SetLengthOperation : public PendingOperationBase {
 public:
  SetLengthOperation(QuotaFileIO* quota_io,
                     bool is_will_operation,
                     int64_t length,
                     const StatusCallback& callback)
      : PendingOperationBase(quota_io, is_will_operation),
        length_(length),
        callback_(callback),
        ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {}

  virtual ~SetLengthOperation() {}

  virtual void Run() OVERRIDE {
    DCHECK(quota_io_);
    if (quota_io_->CheckIfExceedsQuota(length_)) {
      DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE);
      return;
    }
    if (is_will_operation_) {
      DidFinish(base::PLATFORM_FILE_OK);
      return;
    }

    PluginDelegate* plugin_delegate = quota_io_->GetPluginDelegate();
    if (!plugin_delegate) {
      DidFail(base::PLATFORM_FILE_ERROR_FAILED);
      return;
    }

    if (!base::FileUtilProxy::Truncate(
            plugin_delegate->GetFileThreadMessageLoopProxy(),
            quota_io_->file_, length_,
            base::Bind(&SetLengthOperation::DidFinish,
                       weak_factory_.GetWeakPtr()))) {
      DidFail(base::PLATFORM_FILE_ERROR_FAILED);
      return;
    }
  }

  virtual void DidFail(PlatformFileError error) OVERRIDE {
    DidFinish(error);
  }

 private:
  void DidFinish(PlatformFileError status) {
    quota_io_->DidSetLength(status, length_);
    DCHECK_EQ(false, callback_.is_null());
    callback_.Run(status);
    delete this;
  }

  int64_t length_;
  StatusCallback callback_;
  base::WeakPtrFactory<SetLengthOperation> weak_factory_;
};

// QuotaFileIO --------------------------------------------------------------

QuotaFileIO::QuotaFileIO(
    PP_Instance instance,
    PlatformFile file,
    const GURL& file_url,
    PP_FileSystemType type)
    : pp_instance_(instance),
      file_(file),
      file_url_(file_url),
      storage_type_(PPFileSystemTypeToQuotaStorageType(type)),
      cached_file_size_(0),
      cached_available_space_(0),
      outstanding_quota_queries_(0),
      outstanding_errors_(0),
      max_written_offset_(0),
      inflight_operations_(0),
      ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
  DCHECK_NE(base::kInvalidPlatformFileValue, file_);
  DCHECK_NE(quota::kStorageTypeUnknown, storage_type_);
}

QuotaFileIO::~QuotaFileIO() {
  // Note that this doesn't dispatch pending callbacks.
  STLDeleteContainerPointers(pending_operations_.begin(),
                             pending_operations_.end());
  STLDeleteContainerPointers(pending_callbacks_.begin(),
                             pending_callbacks_.end());
}

bool QuotaFileIO::Write(
    int64_t offset, const char* buffer, int32_t bytes_to_write,
    const WriteCallback& callback) {
  if (bytes_to_write <= 0)
    return false;

  WriteOperation* op = new WriteOperation(
      this, false, offset, buffer, bytes_to_write, callback);
  return RegisterOperationForQuotaChecks(op);
}

bool QuotaFileIO::SetLength(int64_t length, const StatusCallback& callback) {
  DCHECK(pending_operations_.empty());
  SetLengthOperation* op = new SetLengthOperation(
      this, false, length, callback);
  return RegisterOperationForQuotaChecks(op);
}

bool QuotaFileIO::WillWrite(
    int64_t offset, int32_t bytes_to_write, const WriteCallback& callback) {
  WriteOperation* op = new WriteOperation(
      this, true, offset, NULL, bytes_to_write, callback);
  return RegisterOperationForQuotaChecks(op);
}

bool QuotaFileIO::WillSetLength(int64_t length,
                                const StatusCallback& callback) {
  DCHECK(pending_operations_.empty());
  SetLengthOperation* op = new SetLengthOperation(this, true, length, callback);
  return RegisterOperationForQuotaChecks(op);
}

PluginDelegate* QuotaFileIO::GetPluginDelegate() const {
  PluginInstance* instance = HostGlobals::Get()->GetInstance(pp_instance_);
  if (instance)
    return instance->delegate();
  return NULL;
}

bool QuotaFileIO::RegisterOperationForQuotaChecks(
    PendingOperationBase* op_ptr) {
  scoped_ptr<PendingOperationBase> op(op_ptr);
  if (pending_operations_.empty()) {
    // This is the first pending quota check. Run querying the file size
    // and available space.
    outstanding_quota_queries_ = 0;
    outstanding_errors_ = 0;

    PluginDelegate* plugin_delegate = GetPluginDelegate();
    if (!plugin_delegate)
      return false;

    // Query the file size.
    ++outstanding_quota_queries_;
    if (!base::FileUtilProxy::GetFileInfoFromPlatformFile(
            plugin_delegate->GetFileThreadMessageLoopProxy(), file_,
            base::Bind(&QuotaFileIO::DidQueryInfoForQuota,
                       weak_factory_.GetWeakPtr()))) {
      // This makes the call fail synchronously; we do not fire the callback
      // here but just delete the operation and return false.
      return false;
    }

    // Query the current available space.
    ++outstanding_quota_queries_;
    plugin_delegate->QueryAvailableSpace(
        GURL(file_url_.path()).GetOrigin(), storage_type_,
        base::Bind(&QuotaFileIO::DidQueryAvailableSpace,
                   weak_factory_.GetWeakPtr()));
  }
  pending_operations_.push_back(op.release());
  return true;
}

void QuotaFileIO::DidQueryInfoForQuota(
    base::PlatformFileError error_code,
    const base::PlatformFileInfo& file_info) {
  if (error_code != base::PLATFORM_FILE_OK)
    ++outstanding_errors_;
  cached_file_size_ = file_info.size;
  DCHECK_GT(outstanding_quota_queries_, 0);
  if (--outstanding_quota_queries_ == 0)
    DidQueryForQuotaCheck();
}

void QuotaFileIO::DidQueryAvailableSpace(int64_t avail_space) {
  cached_available_space_ = avail_space;
  DCHECK_GT(outstanding_quota_queries_, 0);
  if (--outstanding_quota_queries_ == 0)
    DidQueryForQuotaCheck();
}

void QuotaFileIO::DidQueryForQuotaCheck() {
  DCHECK(!pending_operations_.empty());
  DCHECK_GT(inflight_operations_, 0);
  while (!pending_operations_.empty()) {
    PendingOperationBase* op = pending_operations_.front();
    pending_operations_.pop_front();
    pending_callbacks_.push_back(op);
    if (outstanding_errors_ > 0) {
      op->DidFail(base::PLATFORM_FILE_ERROR_FAILED);
      continue;
    }
    op->Run();
  }
}

bool QuotaFileIO::CheckIfExceedsQuota(int64_t new_file_size) const {
  DCHECK_GE(cached_file_size_, 0);
  DCHECK_GE(cached_available_space_, 0);
  return new_file_size - cached_file_size_ > cached_available_space_;
}

void QuotaFileIO::WillUpdate() {
  if (inflight_operations_++ == 0) {
    PluginDelegate* plugin_delegate = GetPluginDelegate();
    if (plugin_delegate)
      plugin_delegate->WillUpdateFile(file_url_);
    DCHECK_EQ(0, max_written_offset_);
  }
}

void QuotaFileIO::DidWrite(WriteOperation* op,
                           int64_t written_offset_end) {
  max_written_offset_ = std::max(max_written_offset_, written_offset_end);
  DCHECK_GT(inflight_operations_, 0);
  DCHECK(!pending_callbacks_.empty());
  // Fire callbacks for finished operations.
  while (!pending_callbacks_.empty()) {
    WriteOperation* op = static_cast<WriteOperation*>(
        pending_callbacks_.front());
    if (!op->finished())
      break;
    pending_callbacks_.pop_front();
    op->WillRunCallback();
  }
  // If we have no more pending writes, notify the browser that we did
  // update the file.
  if (--inflight_operations_ == 0) {
    DCHECK(pending_operations_.empty());
    int64_t growth = max_written_offset_ - cached_file_size_;
    growth = growth < 0 ? 0 : growth;

    PluginDelegate* plugin_delegate = GetPluginDelegate();
    if (plugin_delegate)
      plugin_delegate->DidUpdateFile(file_url_, growth);
    max_written_offset_ = 0;
  }
}

void QuotaFileIO::DidSetLength(PlatformFileError error, int64_t new_file_size) {
  DCHECK_EQ(1, inflight_operations_);
  pending_callbacks_.pop_front();
  DCHECK(pending_callbacks_.empty());
  int64_t delta = (error != base::PLATFORM_FILE_OK) ? 0 :
      new_file_size - cached_file_size_;

  PluginDelegate* plugin_delegate = GetPluginDelegate();
  if (plugin_delegate)
    plugin_delegate->DidUpdateFile(file_url_, delta);
  inflight_operations_ = 0;
}

}  // namespace ppapi
}  // namespace webkit
<commit_msg>Fix Local Storage Issues. Changes in GURL file system URL parsing cause quota queries to fail. Fix URL handling to work with the new GURL code. BUG=122776 TEST=manual (Native Client Example app from Chrome Webstore)<commit_after>// Copyright (c) 2012 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 "webkit/plugins/ppapi/quota_file_io.h"

#include <algorithm>

#include "base/bind.h"
#include "base/memory/weak_ptr.h"
#include "base/message_loop_proxy.h"
#include "base/stl_util.h"
#include "webkit/plugins/ppapi/host_globals.h"
#include "webkit/plugins/ppapi/ppapi_plugin_instance.h"
#include "webkit/plugins/ppapi/resource_helper.h"

using base::PlatformFile;
using base::PlatformFileError;
using quota::StorageType;

namespace webkit {
namespace ppapi {

namespace {
StorageType PPFileSystemTypeToQuotaStorageType(PP_FileSystemType type) {
  switch (type) {
    case PP_FILESYSTEMTYPE_LOCALPERSISTENT:
      return quota::kStorageTypePersistent;
    case PP_FILESYSTEMTYPE_LOCALTEMPORARY:
      return quota::kStorageTypeTemporary;
    default:
      return quota::kStorageTypeUnknown;
  }
  NOTREACHED();
  return quota::kStorageTypeUnknown;
}
}  // namespace

class QuotaFileIO::PendingOperationBase {
 public:
  virtual ~PendingOperationBase() {}

  // Either one of Run() or DidFail() is called (the latter is called when
  // there was more than one error during quota queries).
  virtual void Run() = 0;
  virtual void DidFail(PlatformFileError error) = 0;

 protected:
  PendingOperationBase(QuotaFileIO* quota_io, bool is_will_operation)
      : quota_io_(quota_io), is_will_operation_(is_will_operation) {
    DCHECK(quota_io_);
    quota_io_->WillUpdate();
  }

  QuotaFileIO* quota_io_;
  const bool is_will_operation_;
};

class QuotaFileIO::WriteOperation : public PendingOperationBase {
 public:
  WriteOperation(QuotaFileIO* quota_io,
                 bool is_will_operation,
                 int64_t offset,
                 const char* buffer,
                 int32_t bytes_to_write,
                 const WriteCallback& callback)
      : PendingOperationBase(quota_io, is_will_operation),
        offset_(offset),
        bytes_to_write_(bytes_to_write),
        callback_(callback),
        finished_(false),
        status_(base::PLATFORM_FILE_OK),
        bytes_written_(0),
        ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
    if (!is_will_operation) {
      // TODO(kinuko): Check the API convention if we really need to keep a copy
      // of the buffer during the async write operations.
      buffer_.reset(new char[bytes_to_write]);
      memcpy(buffer_.get(), buffer, bytes_to_write);
    }
  }
  virtual ~WriteOperation() {}
  virtual void Run() OVERRIDE {
    DCHECK(quota_io_);
    if (quota_io_->CheckIfExceedsQuota(offset_ + bytes_to_write_)) {
      DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE);
      return;
    }
    if (is_will_operation_) {
      // Assuming the write will succeed.
      DidFinish(base::PLATFORM_FILE_OK, bytes_to_write_);
      return;
    }
    DCHECK(buffer_.get());

    PluginDelegate* plugin_delegate = quota_io_->GetPluginDelegate();
    if (!plugin_delegate) {
      DidFail(base::PLATFORM_FILE_ERROR_FAILED);
      return;
    }

    if (!base::FileUtilProxy::Write(
            plugin_delegate->GetFileThreadMessageLoopProxy(),
            quota_io_->file_, offset_, buffer_.get(), bytes_to_write_,
            base::Bind(&WriteOperation::DidFinish,
                       weak_factory_.GetWeakPtr()))) {
      DidFail(base::PLATFORM_FILE_ERROR_FAILED);
      return;
    }
  }

  virtual void DidFail(PlatformFileError error) OVERRIDE {
    DidFinish(error, 0);
  }

  bool finished() const { return finished_; }

  virtual void WillRunCallback() {
    base::MessageLoopProxy::current()->PostTask(
        FROM_HERE,
        base::Bind(&WriteOperation::RunCallback, weak_factory_.GetWeakPtr()));
  }

 private:
  void DidFinish(PlatformFileError status, int bytes_written) {
    finished_ = true;
    status_ = status;
    bytes_written_ = bytes_written;
    int64_t max_offset =
        (status != base::PLATFORM_FILE_OK) ? 0 : offset_ + bytes_written;
    // This may delete itself by calling RunCallback.
    quota_io_->DidWrite(this, max_offset);
  }

  virtual void RunCallback() {
    DCHECK_EQ(false, callback_.is_null());
    callback_.Run(status_, bytes_written_);
    delete this;
  }

  const int64_t offset_;
  scoped_array<char> buffer_;
  const int32_t bytes_to_write_;
  WriteCallback callback_;
  bool finished_;
  PlatformFileError status_;
  int64_t bytes_written_;
  base::WeakPtrFactory<WriteOperation> weak_factory_;
};

class QuotaFileIO::SetLengthOperation : public PendingOperationBase {
 public:
  SetLengthOperation(QuotaFileIO* quota_io,
                     bool is_will_operation,
                     int64_t length,
                     const StatusCallback& callback)
      : PendingOperationBase(quota_io, is_will_operation),
        length_(length),
        callback_(callback),
        ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {}

  virtual ~SetLengthOperation() {}

  virtual void Run() OVERRIDE {
    DCHECK(quota_io_);
    if (quota_io_->CheckIfExceedsQuota(length_)) {
      DidFail(base::PLATFORM_FILE_ERROR_NO_SPACE);
      return;
    }
    if (is_will_operation_) {
      DidFinish(base::PLATFORM_FILE_OK);
      return;
    }

    PluginDelegate* plugin_delegate = quota_io_->GetPluginDelegate();
    if (!plugin_delegate) {
      DidFail(base::PLATFORM_FILE_ERROR_FAILED);
      return;
    }

    if (!base::FileUtilProxy::Truncate(
            plugin_delegate->GetFileThreadMessageLoopProxy(),
            quota_io_->file_, length_,
            base::Bind(&SetLengthOperation::DidFinish,
                       weak_factory_.GetWeakPtr()))) {
      DidFail(base::PLATFORM_FILE_ERROR_FAILED);
      return;
    }
  }

  virtual void DidFail(PlatformFileError error) OVERRIDE {
    DidFinish(error);
  }

 private:
  void DidFinish(PlatformFileError status) {
    quota_io_->DidSetLength(status, length_);
    DCHECK_EQ(false, callback_.is_null());
    callback_.Run(status);
    delete this;
  }

  int64_t length_;
  StatusCallback callback_;
  base::WeakPtrFactory<SetLengthOperation> weak_factory_;
};

// QuotaFileIO --------------------------------------------------------------

QuotaFileIO::QuotaFileIO(
    PP_Instance instance,
    PlatformFile file,
    const GURL& file_url,
    PP_FileSystemType type)
    : pp_instance_(instance),
      file_(file),
      file_url_(file_url),
      storage_type_(PPFileSystemTypeToQuotaStorageType(type)),
      cached_file_size_(0),
      cached_available_space_(0),
      outstanding_quota_queries_(0),
      outstanding_errors_(0),
      max_written_offset_(0),
      inflight_operations_(0),
      ALLOW_THIS_IN_INITIALIZER_LIST(weak_factory_(this)) {
  DCHECK_NE(base::kInvalidPlatformFileValue, file_);
  DCHECK_NE(quota::kStorageTypeUnknown, storage_type_);
}

QuotaFileIO::~QuotaFileIO() {
  // Note that this doesn't dispatch pending callbacks.
  STLDeleteContainerPointers(pending_operations_.begin(),
                             pending_operations_.end());
  STLDeleteContainerPointers(pending_callbacks_.begin(),
                             pending_callbacks_.end());
}

bool QuotaFileIO::Write(
    int64_t offset, const char* buffer, int32_t bytes_to_write,
    const WriteCallback& callback) {
  if (bytes_to_write <= 0)
    return false;

  WriteOperation* op = new WriteOperation(
      this, false, offset, buffer, bytes_to_write, callback);
  return RegisterOperationForQuotaChecks(op);
}

bool QuotaFileIO::SetLength(int64_t length, const StatusCallback& callback) {
  DCHECK(pending_operations_.empty());
  SetLengthOperation* op = new SetLengthOperation(
      this, false, length, callback);
  return RegisterOperationForQuotaChecks(op);
}

bool QuotaFileIO::WillWrite(
    int64_t offset, int32_t bytes_to_write, const WriteCallback& callback) {
  WriteOperation* op = new WriteOperation(
      this, true, offset, NULL, bytes_to_write, callback);
  return RegisterOperationForQuotaChecks(op);
}

bool QuotaFileIO::WillSetLength(int64_t length,
                                const StatusCallback& callback) {
  DCHECK(pending_operations_.empty());
  SetLengthOperation* op = new SetLengthOperation(this, true, length, callback);
  return RegisterOperationForQuotaChecks(op);
}

PluginDelegate* QuotaFileIO::GetPluginDelegate() const {
  PluginInstance* instance = HostGlobals::Get()->GetInstance(pp_instance_);
  if (instance)
    return instance->delegate();
  return NULL;
}

bool QuotaFileIO::RegisterOperationForQuotaChecks(
    PendingOperationBase* op_ptr) {
  scoped_ptr<PendingOperationBase> op(op_ptr);
  if (pending_operations_.empty()) {
    // This is the first pending quota check. Run querying the file size
    // and available space.
    outstanding_quota_queries_ = 0;
    outstanding_errors_ = 0;

    PluginDelegate* plugin_delegate = GetPluginDelegate();
    if (!plugin_delegate)
      return false;

    // Query the file size.
    ++outstanding_quota_queries_;
    if (!base::FileUtilProxy::GetFileInfoFromPlatformFile(
            plugin_delegate->GetFileThreadMessageLoopProxy(), file_,
            base::Bind(&QuotaFileIO::DidQueryInfoForQuota,
                       weak_factory_.GetWeakPtr()))) {
      // This makes the call fail synchronously; we do not fire the callback
      // here but just delete the operation and return false.
      return false;
    }

    // Query the current available space.
    ++outstanding_quota_queries_;
    plugin_delegate->QueryAvailableSpace(
        file_url_.GetOrigin(), storage_type_,
        base::Bind(&QuotaFileIO::DidQueryAvailableSpace,
                   weak_factory_.GetWeakPtr()));
  }
  pending_operations_.push_back(op.release());
  return true;
}

void QuotaFileIO::DidQueryInfoForQuota(
    base::PlatformFileError error_code,
    const base::PlatformFileInfo& file_info) {
  if (error_code != base::PLATFORM_FILE_OK)
    ++outstanding_errors_;
  cached_file_size_ = file_info.size;
  DCHECK_GT(outstanding_quota_queries_, 0);
  if (--outstanding_quota_queries_ == 0)
    DidQueryForQuotaCheck();
}

void QuotaFileIO::DidQueryAvailableSpace(int64_t avail_space) {
  cached_available_space_ = avail_space;
  DCHECK_GT(outstanding_quota_queries_, 0);
  if (--outstanding_quota_queries_ == 0)
    DidQueryForQuotaCheck();
}

void QuotaFileIO::DidQueryForQuotaCheck() {
  DCHECK(!pending_operations_.empty());
  DCHECK_GT(inflight_operations_, 0);
  while (!pending_operations_.empty()) {
    PendingOperationBase* op = pending_operations_.front();
    pending_operations_.pop_front();
    pending_callbacks_.push_back(op);
    if (outstanding_errors_ > 0) {
      op->DidFail(base::PLATFORM_FILE_ERROR_FAILED);
      continue;
    }
    op->Run();
  }
}

bool QuotaFileIO::CheckIfExceedsQuota(int64_t new_file_size) const {
  DCHECK_GE(cached_file_size_, 0);
  DCHECK_GE(cached_available_space_, 0);
  return new_file_size - cached_file_size_ > cached_available_space_;
}

void QuotaFileIO::WillUpdate() {
  if (inflight_operations_++ == 0) {
    PluginDelegate* plugin_delegate = GetPluginDelegate();
    if (plugin_delegate)
      plugin_delegate->WillUpdateFile(file_url_);
    DCHECK_EQ(0, max_written_offset_);
  }
}

void QuotaFileIO::DidWrite(WriteOperation* op,
                           int64_t written_offset_end) {
  max_written_offset_ = std::max(max_written_offset_, written_offset_end);
  DCHECK_GT(inflight_operations_, 0);
  DCHECK(!pending_callbacks_.empty());
  // Fire callbacks for finished operations.
  while (!pending_callbacks_.empty()) {
    WriteOperation* op = static_cast<WriteOperation*>(
        pending_callbacks_.front());
    if (!op->finished())
      break;
    pending_callbacks_.pop_front();
    op->WillRunCallback();
  }
  // If we have no more pending writes, notify the browser that we did
  // update the file.
  if (--inflight_operations_ == 0) {
    DCHECK(pending_operations_.empty());
    int64_t growth = max_written_offset_ - cached_file_size_;
    growth = growth < 0 ? 0 : growth;

    PluginDelegate* plugin_delegate = GetPluginDelegate();
    if (plugin_delegate)
      plugin_delegate->DidUpdateFile(file_url_, growth);
    max_written_offset_ = 0;
  }
}

void QuotaFileIO::DidSetLength(PlatformFileError error, int64_t new_file_size) {
  DCHECK_EQ(1, inflight_operations_);
  pending_callbacks_.pop_front();
  DCHECK(pending_callbacks_.empty());
  int64_t delta = (error != base::PLATFORM_FILE_OK) ? 0 :
      new_file_size - cached_file_size_;

  PluginDelegate* plugin_delegate = GetPluginDelegate();
  if (plugin_delegate)
    plugin_delegate->DidUpdateFile(file_url_, delta);
  inflight_operations_ = 0;
}

}  // namespace ppapi
}  // namespace webkit
<|endoftext|>


<commit_before>#include	"FTGLTextureFont.h"
#include	"FTGlyphContainer.h"
#include	"FTTextureGlyph.h"

using namespace std;

inline GLuint NextPowerOf2( GLuint in)
{
     in -= 1;

     in |= in >> 16;
     in |= in >> 8;
     in |= in >> 4;
     in |= in >> 2;
     in |= in >> 1;

     return in + 1;
}

FTGLTextureFont::FTGLTextureFont()
:	maxTextSize(0),
	textureWidth(0),
	textureHeight(0),
	numTextures(1),
	textMem(0),
	glyphHeight(0),
	glyphWidth(0),
	padding(1)
{}

FTGLTextureFont::~FTGLTextureFont()
{
	glDeleteTextures( numTextures, (const GLuint*)glTextureID);
}

bool FTGLTextureFont::MakeGlyphList()
{
	if( !maxTextSize)
		glGetIntegerv( GL_MAX_TEXTURE_SIZE, (GLint*)&maxTextSize);

	glyphHeight = ( charSize.Height()) + padding;
	glyphWidth = ( charSize.Width()) + padding;

	GetSize();
	GLuint totalMem;

	if( textureHeight > maxTextSize)
	{
		numTextures = static_cast<int>( textureHeight / maxTextSize) + 1;
		if( numTextures > 15) // FIXME
			numTextures = 15;

		GLsizei heightRemain = NextPowerOf2( textureHeight % maxTextSize);
		totalMem = ((maxTextSize * ( numTextures - 1)) + heightRemain) * textureWidth;

		glGenTextures( numTextures, (GLuint*)&glTextureID[0]);

		textMem = new unsigned char[totalMem]; // GL_ALPHA texture;
		memset( textMem, 0, totalMem);

		unsigned int glyphNum = 0;
		unsigned char* currTextPtr = textMem;

		for( int x = 0; x < numTextures - 1; ++x)
		{
			glyphNum = FillGlyphs( glyphNum, glTextureID[x], textureWidth, maxTextSize, currTextPtr);

			CreateTexture( x, textureWidth, maxTextSize, currTextPtr);

			currTextPtr += ( textureWidth * maxTextSize);
			++glyphNum;
		}

		glyphNum = FillGlyphs( glyphNum, glTextureID[numTextures - 1], textureWidth, heightRemain, currTextPtr);
		CreateTexture( numTextures - 1, textureWidth, heightRemain, currTextPtr);
	}
	else
	{
		textureHeight = NextPowerOf2( textureHeight);
		totalMem = textureWidth * textureHeight;

		glGenTextures( numTextures, (GLuint*)&glTextureID[0]);

		textMem = new unsigned char[totalMem]; // GL_ALPHA texture;
		memset( textMem, 0, totalMem);

		FillGlyphs( 0, glTextureID[0], textureWidth, textureHeight, textMem);
		CreateTexture( 0, textureWidth, textureHeight, textMem);
	}

	delete [] textMem;
	return !err;
}

unsigned int FTGLTextureFont::FillGlyphs( unsigned int glyphStart, GLuint id, GLsizei width, GLsizei height, unsigned char* textdata)
{
	int currentTextX = padding;
	int currentTextY = padding;// + padding;

	float currTextU = (float)padding / (float)width;
	float currTextV = (float)padding / (float)height;

	unsigned int n;

	for( n = glyphStart; n <= numGlyphs; ++n)
	{
		FT_Glyph* ftGlyph = face.Glyph( n, FT_LOAD_NO_HINTING);

		if( ftGlyph)
		{
			unsigned char* data = textdata + (( currentTextY * width) + currentTextX);

			currTextU = (float)currentTextX / (float)width;

			FTTextureGlyph* tempGlyph = new FTTextureGlyph( *ftGlyph, id, data, width, height, currTextU, currTextV);
			glyphList->Add( tempGlyph);

			currentTextX += glyphWidth;
			if( currentTextX > ( width - glyphWidth))
			{
				currentTextY += glyphHeight;
				if( currentTextY > ( height - glyphHeight))
					return n;

				currentTextX = padding;
				currTextV = (float)currentTextY / (float)height;
			}
		}
		else
		{
			err = face.Error();
		}
	}

	return n;
}

void FTGLTextureFont::GetSize()
{
	//work out the max width. Most likely maxTextSize
	textureWidth = NextPowerOf2( numGlyphs * glyphWidth);
	if( textureWidth > maxTextSize)
	{
		textureWidth = maxTextSize;
	}

	int h = static_cast<int>( textureWidth / glyphWidth);
	textureHeight = (( numGlyphs / h) + 1) * glyphHeight;
}

void FTGLTextureFont::CreateTexture( GLuint id, GLsizei width, GLsizei height, unsigned char* data)
{
	glPixelStorei( GL_UNPACK_ALIGNMENT, 1); //What does this do exactly?
	glBindTexture( GL_TEXTURE_2D, glTextureID[id]);
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data);
}

void FTGLTextureFont::render( const char* string)
{
	glPushAttrib( GL_ENABLE_BIT | GL_HINT_BIT | GL_LINE_BIT | GL_PIXEL_MODE_BIT);

	glEnable(GL_BLEND);
 	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE

 	FTFont::render( string);

	glPopAttrib();
}

void FTGLTextureFont::render( const wchar_t* string)
{
	glPushAttrib( GL_ENABLE_BIT | GL_HINT_BIT | GL_LINE_BIT | GL_PIXEL_MODE_BIT);

	glEnable(GL_BLEND);
 	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE

 	FTFont::render( string);

	glPopAttrib();
}

<commit_msg>Added padding to size calculations<commit_after>#include	"FTGLTextureFont.h"
#include	"FTGlyphContainer.h"
#include	"FTTextureGlyph.h"

using namespace std;

inline GLuint NextPowerOf2( GLuint in)
{
     in -= 1;

     in |= in >> 16;
     in |= in >> 8;
     in |= in >> 4;
     in |= in >> 2;
     in |= in >> 1;

     return in + 1;
}

FTGLTextureFont::FTGLTextureFont()
:	maxTextSize(0),
	textureWidth(0),
	textureHeight(0),
	numTextures(1),
	textMem(0),
	glyphHeight(0),
	glyphWidth(0),
	padding(1)
{}

FTGLTextureFont::~FTGLTextureFont()
{
	glDeleteTextures( numTextures, (const GLuint*)glTextureID);
}

bool FTGLTextureFont::MakeGlyphList()
{
	if( !maxTextSize)
		glGetIntegerv( GL_MAX_TEXTURE_SIZE, (GLint*)&maxTextSize);

	glyphHeight = ( charSize.Height()) + padding;
	glyphWidth = ( charSize.Width()) + padding;

	GetSize();
	GLuint totalMem;

	if( textureHeight > (maxTextSize-padding * 2))
	{
		numTextures = static_cast<int>( textureHeight / (maxTextSize-padding * 2)) + 1;
		if( numTextures > 15) // FIXME
			numTextures = 15;

		GLsizei heightRemain = NextPowerOf2( textureHeight % (maxTextSize-padding * 2));
		totalMem = ((maxTextSize * ( numTextures - 1)) + heightRemain) * textureWidth;

		glGenTextures( numTextures, (GLuint*)&glTextureID[0]);

		textMem = new unsigned char[totalMem]; // GL_ALPHA texture;
		memset( textMem, 0, totalMem);

		unsigned int glyphNum = 0;
		unsigned char* currTextPtr = textMem;

		for( int x = 0; x < numTextures - 1; ++x)
		{
			glyphNum = FillGlyphs( glyphNum, glTextureID[x], textureWidth, maxTextSize, currTextPtr);

			CreateTexture( x, textureWidth, maxTextSize, currTextPtr);

			currTextPtr += ( textureWidth * maxTextSize);
			++glyphNum;
		}

		glyphNum = FillGlyphs( glyphNum, glTextureID[numTextures - 1], textureWidth, heightRemain, currTextPtr);
		CreateTexture( numTextures - 1, textureWidth, heightRemain, currTextPtr);
	}
	else
	{

		textureHeight = NextPowerOf2( textureHeight+padding * 2);
		totalMem = textureWidth * textureHeight;

		glGenTextures( numTextures, (GLuint*)&glTextureID[0]);

		textMem = new unsigned char[totalMem]; // GL_ALPHA texture;
		memset( textMem, 0, totalMem);

		FillGlyphs( 0, glTextureID[0], textureWidth, textureHeight, textMem);
		CreateTexture( 0, textureWidth, textureHeight, textMem);
	}

	delete [] textMem;
	return !err;
}

unsigned int FTGLTextureFont::FillGlyphs( unsigned int glyphStart, GLuint id, GLsizei width, GLsizei height, unsigned char* textdata)
{
	int currentTextX = padding;
	int currentTextY = padding;// + padding;

	float currTextU = (float)padding / (float)width;
	float currTextV = (float)padding / (float)height;

	unsigned int n;

	for( n = glyphStart; n <= numGlyphs; ++n)
	{
		FT_Glyph* ftGlyph = face.Glyph( n, FT_LOAD_NO_HINTING);

		if( ftGlyph)
		{
			unsigned char* data = textdata + (( currentTextY * width) + currentTextX);

			currTextU = (float)currentTextX / (float)width;

			FTTextureGlyph* tempGlyph = new FTTextureGlyph( *ftGlyph, id, data, width, height, currTextU, currTextV);
			glyphList->Add( tempGlyph);

			currentTextX += glyphWidth;
			if( currentTextX > ( width - glyphWidth))
			{
				currentTextY += glyphHeight;
				if( currentTextY > ( height - glyphHeight))
					return n;

				currentTextX = padding;
				currTextV = (float)currentTextY / (float)height;
			}
		}
		else
		{
			err = face.Error();
		}
	}

	return n;
}

void FTGLTextureFont::GetSize()
{
	//work out the max width. Most likely maxTextSize
	textureWidth = NextPowerOf2( (numGlyphs * glyphWidth) + padding * 2);
	if( textureWidth > maxTextSize)
	{
		textureWidth = maxTextSize;
	}

	int h = static_cast<int>( (textureWidth-padding * 2) / glyphWidth);

	textureHeight = (( numGlyphs / h) + 1) * glyphHeight;
}

void FTGLTextureFont::CreateTexture( GLuint id, GLsizei width, GLsizei height, unsigned char* data)
{
	glPixelStorei( GL_UNPACK_ALIGNMENT, 1); //What does this do exactly?
	glBindTexture( GL_TEXTURE_2D, glTextureID[id]);
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP);
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP);
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
	glTexParameteri( GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);

	glTexImage2D( GL_TEXTURE_2D, 0, GL_ALPHA, width, height, 0, GL_ALPHA, GL_UNSIGNED_BYTE, data);
}

void FTGLTextureFont::render( const char* string)
{
	glPushAttrib( GL_ENABLE_BIT | GL_HINT_BIT | GL_LINE_BIT | GL_PIXEL_MODE_BIT);

	glEnable(GL_BLEND);
 	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE

 	FTFont::render( string);

	glPopAttrib();
}

void FTGLTextureFont::render( const wchar_t* string)
{
	glPushAttrib( GL_ENABLE_BIT | GL_HINT_BIT | GL_LINE_BIT | GL_PIXEL_MODE_BIT);

	glEnable(GL_BLEND);
 	glBlendFunc( GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); // GL_ONE

 	FTFont::render( string);

	glPopAttrib();
}

<|endoftext|>


<commit_before><commit_msg>src/GSvar/PRSWidget.cpp: Bugfix: added special handling for CanRisk PRS scores<commit_after><|endoftext|>


<commit_before>/*
 *  readit.cpp
 *
 *  Copyright (c) 2010 Motiejus Jakštys
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 3.

 *  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <math.h>
#include <algorithm>
#include <stdlib.h>
#include <cstdio>
#include <map>
#include <set>
#include <list>
#include <vector>
#include <string>
#include <string.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <jack/jack.h>

using namespace std;

#define SRC_WAV 0
#define SRC_JACK_ONE 1
#define SRC_JACK_AUTO 2
#define ACTION_DUMP 0
#define ACTION_CATCH 1

#define BUFFERSIZE 1

#define ACTION_FN_ARGS int w, double place, double len, unsigned long int b
#define ACTION_FN(func) void (*func)(ACTION_FN_ARGS)

void fatal(void * r) {
    char * msg = (char*) r;
    printf (msg);
    exit (1);
};
char errmsg[200];   // Temporary message

struct sVolumes {
    unsigned long head, tail;
	jack_default_audio_sample_t min, max;
    bool proc;
};

typedef struct {
    jack_default_audio_sample_t * buf;
    jack_nframes_t nframes;
} buffer;

class SoundPatty;
class Input {
    public:
        int SAMPLE_RATE, DATA_SIZE;
        virtual buffer * giveInput(buffer *) {
            fatal((void*)"This should never be called!!!");
        };
        virtual void test() {
            printf("Called Input\n");
        }
    protected:
        SoundPatty * _sp_inst;
};

class SoundPatty {
    public:
        SoundPatty(const char * fn) {
            gSCounter = gMCounter = 0;
            read_cfg(fn);
        };
        map<string, double> cfg;
        virtual void Error(void*);
        int setInput(int, void*);
        int go(int, ACTION_FN(callback));
        int WAVE, CHUNKSIZE;
        unsigned long gMCounter, // How many matches we found
                      gSCounter; // How many samples we skipped
        void search_patterns (jack_default_audio_sample_t * buf, jack_nframes_t nframes, ACTION_FN(callback));
        vector<sVolumes> volume;
    private:
        Input * _input;
        int read_cfg(const char*);
        int source_app;
        char *input_params;
};

class WavInput : public Input {
    public:
        WavInput(SoundPatty * inst, void * args) {
            _sp_inst = inst;
            char * filename = (char*) args;
            process_headers(filename);
            // ------------------------------------------------------------
            // Adjust _sp_ volume
            // Jack has float (-1..1) while M$ WAV has (-2^15..2^15)
            //
            for (vector<sVolumes>::iterator vol = _sp_inst->volume.begin(); vol != _sp_inst->volume.end(); vol++) {
                vol->min *= (1<<15);
                vol->max *= (1<<15);
            }
        }

        buffer * giveInput(buffer *buf_prop) {
            int16_t buf [SAMPLE_RATE * BUFFERSIZE]; // Process buffer every BUFFERSIZE secs
            if (feof(_fh)) {
                return NULL;
            }
            size_t read_size = fread(buf, 2, SAMPLE_RATE * BUFFERSIZE, _fh);

            // :HACK: fix this, do not depend on jack types where you don't need!
            jack_default_audio_sample_t buf2 [SAMPLE_RATE * BUFFERSIZE];
            for(int i = 0; i < read_size; i++) {
                buf2[i] = (jack_default_audio_sample_t)buf[i];
            }
            buf_prop->buf = buf2;
            buf_prop->nframes = read_size;
            return buf_prop;
        }
    protected:
        int process_headers(const char * infile) {/*{{{*/

            _fh = fopen(infile, "rb");
            if (_fh == NULL) {
                sprintf(errmsg, "Failed to open file %s, exiting\n", infile);
                fatal((void*)errmsg);
            }

            // Read bytes [0-3] and [8-11], they should be "RIFF" and "WAVE" in ASCII
            char header[5];
            fread(header, 1, 4, _fh);

            char sample[] = "RIFF";
            if (! check_sample(sample, header) ) {
                sprintf(errmsg, "RIFF header not found in %s, exiting\n", infile);
                fatal((void*)errmsg);
            }
            // Checking for compression code (21'st byte is 01, 22'nd - 00, little-endian notation
            uint16_t tmp[2]; // two-byte integer
            fseek(_fh, 0x14, 0); // offset = 20 bytes
            fread(&tmp, 2, 2, _fh); // Reading two two-byte samples (comp. code and no. of channels)
            if ( tmp[0] != 1 ) {
                sprintf(errmsg, "Only PCM(1) supported, compression code given: %d\n", tmp[0]);
                fatal ((void*)errmsg);
            }
            // Number of channels must be "MONO"
            if ( tmp[1] != 1 ) {
                sprintf(errmsg, "Only MONO supported, given number of channels: %d\n", tmp[1]);
                fatal ((void*)errmsg);
            }
            fread(&SAMPLE_RATE, 2, 1, _fh); // Single two-byte sample
            _sp_inst->WAVE = (int)SAMPLE_RATE * _sp_inst->cfg["minwavelen"];
            _sp_inst->CHUNKSIZE = _sp_inst->cfg["chunklen"] * (int)SAMPLE_RATE;
            fseek(_fh, 0x22, 0);
            uint16_t BitsPerSample;
            fread(&BitsPerSample, 1, 2, _fh);
            if (BitsPerSample != 16) {
                sprintf(errmsg, "Only 16-bit WAVs supported, given: %d\n", BitsPerSample);
                fatal((void*)errmsg);
            }
            // Get data chunk size here
            fread(header, 1, 4, _fh);
            strcpy(sample, "data");

            if (! check_sample(sample, header)) {
                fatal ((void*)"data chunk not found in byte offset=36, file corrupted.");
            }
            int DATA_SIZE;
            fread(&DATA_SIZE, 4, 1, _fh); // Single two-byte sample
            return 0;
        }

        bool check_sample (const char * sample, const char * b) { // My STRCPY.
            for(int i = 0; sample[i] != '\0'; i++) {
                if (sample[i] != b[i]) {
                    return false;
                }
            }
            return true;
        }/*}}}*/
    private:
        FILE *_fh;

};
void SoundPatty::Error(void * msg) {/*{{{*/
    char * mesg = (char*) msg;
    printf(mesg);
    exit(0);
}/*}}}*/
int SoundPatty::read_cfg (const char * filename) {/*{{{*/
    ifstream file;
    file.open(filename);
    string line;
    int x;
    while (! file.eof() ) {
        getline(file, line);
        x = line.find(":");
        if (x == -1) break; // Last line, exit
        istringstream i(line.substr(x+2));
        double tmp; i >> tmp;
        cfg[line.substr(0,x)] = tmp;
    }
    // Change cfg["treshold\d+_(min|max)"] to
    // something more compatible with sVolumes map
    sVolumes tmp;
    tmp.head = tmp.tail = tmp.max = tmp.min = tmp.proc = 0;
    volume.assign(cfg.size(), tmp); // Make a bit more then nescesarry
    int max_index = 0; // Number of different tresholds
    for(map<string, double>::iterator C = cfg.begin(); C != cfg.end(); C++) {
        // Failed to use boost::regex :(
        if (C->first.find("treshold") == 0) {
            istringstream tmp(C->first.substr(8));
            int i; tmp >> i;
            max_index = max(max_index, i);
            // C->second and volume[i].m{in,ax} are double
            if (C->first.find("_min") != -1) {
                volume[i].min = C->second;
            } else {
                volume[i].max = C->second;
            }
        }
    }
    volume.assign(volume.begin(), volume.begin()+max_index+1);
    return 0;
}/*}}}*/
int SoundPatty::setInput(const int source_app, void * input_params) {/*{{{*/
    if (0 <= source_app && source_app <= 2) {
        this->source_app = source_app;
    }
    switch(this->source_app) {
        case SRC_WAV:
            _input = new WavInput(this, input_params);
            break;
    }
    return 0;
}/*}}}*/

int SoundPatty::go(const int action, ACTION_FN(callback)) {
    string which_timeout (action == ACTION_DUMP?"sampletimeout" : "catchtimeout");
    buffer buf;

    buf.buf = NULL;
    buf.nframes = 0;
    while (_input->giveInput(&buf) != NULL) { // Have pointer to data

        search_patterns(buf.buf, buf.nframes, callback);
        if (gSCounter/_input->SAMPLE_RATE > cfg[which_timeout]) {
            return 0;
        }
    }
}

void SoundPatty::search_patterns (jack_default_audio_sample_t * buf, jack_nframes_t nframes, ACTION_FN(callback)) {
    for (int i = 0; i < nframes; gSCounter++, i++) {
        jack_default_audio_sample_t cur = buf[i]<0?-buf[i]:buf[i];

        int v = 0; // Counter for volume
        for (vector<sVolumes>::iterator V = volume.begin(); V != volume.end(); V++, v++) {
            if (V->min <= cur && cur <= V->max) {
                // ------------------------------------------------------------
                // If it's first item in this wave (proc = processing started)
                //
                if (!V->proc) {
                    V->tail = gSCounter;
                    V->proc = true;
                }
                // ------------------------------------------------------------
                // Here we are just normally in the wave.
                //
                V->head = gSCounter;
            } else { // We are not in the wave
                if (V->proc && (V->min < 0.001 || gSCounter - V->head > WAVE)) {

                    //------------------------------------------------------------
                    // This wave is over
                    //
                    if (gSCounter - V->tail >= CHUNKSIZE) {
                        // ------------------------------------------------------------
                        // The previous chunk is big enough to be noticed
                        //
                        callback(v, (double)V->tail/_input->SAMPLE_RATE, (double)(V->head - V->tail)/_input->SAMPLE_RATE, gMCounter++);
                    }
                    // ------------------------------------------------------------
                    // Else it is too small, but we don't want to do anything in that case
                    // So therefore we just say that wave processing is over
                    //
                    V->proc = false;
                }
            }
        }
    }
}

void dump_out(ACTION_FN_ARGS) {
    printf ("%d;%.6f;%.6f\n", w, place, len);
}

int main (int argc, char *argv[]) {
    if (argc < 3) {
        fatal ((void*)"Usage: ./readit config.cfg sample.wav\nor\n"
                "./readit config.cfg samplefile.txt catchable.wav\n"
                "./readit config.cfg samplefile.txt jack jack\n");
    }
    if (argc == 3) {
        SoundPatty * pat = new SoundPatty(argv[1]); // usually config.cfg
        pat->setInput(SRC_WAV, argv[2]);
        switch (pat->go(ACTION_DUMP, dump_out)) {
            case 0: // It's just over. Either timeout or eof reached
                exit(0);
        }
    }
    exit(0);
}
<commit_msg>Restructurized do_checking and search_patterns, better without callbacks<commit_after>/*
 *  readit.cpp
 *
 *  Copyright (c) 2010 Motiejus Jakštys
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License version 3.

 *  This program 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 this program.  If not, see <http://www.gnu.org/licenses/>.
 *
 */

#include <math.h>
#include <algorithm>
#include <stdlib.h>
#include <cstdio>
#include <map>
#include <set>
#include <list>
#include <vector>
#include <string>
#include <string.h>
#include <iostream>
#include <sstream>
#include <fstream>
#include <jack/jack.h>

using namespace std;

#define SRC_WAV 0
#define SRC_JACK_ONE 1
#define SRC_JACK_AUTO 2
#define ACTION_DUMP 0
#define ACTION_CATCH 1

#define BUFFERSIZE 1

void fatal(void * r) {
    char * msg = (char*) r;
    printf (msg);
    exit (1);
};

char errmsg[200];   // Temporary message

void its_over(double place) {
    printf("FOUND, processed %.6f sec\n", place);
    exit(0);
}
class Range {/*{{{*/
    public:
        Range() { tm = tmin = tmax = 0; };
        Range(const double & a) { tm = a; tmin = a * 0.89; tmax = a * 1.11; }
        Range(const double & tmin, const double &tm, const double &tmax) { this->tmin = tmin; this->tm = tm; this->tmax = tmax; }
        Range(const double & tmin, const double &tmax) { this->tmin = tmin; this->tmax = tmax; }
        Range operator = (const double i) { return Range(i); }
        bool operator == (const double & i) const { return tmin < i && i < tmax; }
        bool operator == (const Range & r) const { return r == tm; }
        bool operator > (const double & i) const { return i > tmax; }
        bool operator > (const Range & r) const { return r > tm; }
        bool operator < (const double & i) const { return i < tmin; }
        bool operator < (const Range & r) const { return r < tm; }
        double tmin, tm, tmax;
};
typedef struct {
    jack_default_audio_sample_t * buf;
    jack_nframes_t nframes;
} buffer;

class workitm {
    public:
        int len,a;
        unsigned long b;

        workitm(int, unsigned long);
        list<pair<int, unsigned long> > trace;
};

workitm::workitm(const int a, const unsigned long b) {
    this->a = a; this->b = b;
    len = 0;
    trace.push_back(pair<int,unsigned long>(a,b));
};

struct sVolumes {
    unsigned long head, tail;
	jack_default_audio_sample_t min, max;
    bool proc;
};

struct valsitm_t {
    int c; // Counter in map
    double place;
};
struct treshold_t {
    int r;
    double place, sec;
    unsigned long b;
};

typedef multimap<pair<int, Range>, valsitm_t> vals_t;/*}}}*/

class SoundPatty;
class Input {
    public:
        int SAMPLE_RATE, DATA_SIZE;
        virtual buffer * giveInput(buffer *) {
            fatal((void*)"This should never be called!!!");
        };
        virtual void test() {
            printf("Called Input\n");
        }
    protected:
        SoundPatty * _sp_inst;
};

class SoundPatty {
    public:
        SoundPatty(const char * fn) {
            gSCounter = gMCounter = 0;
            read_cfg(fn);
        };
        void setAction(int action) {
            _action = action;
        }
        void setAction(int action, void (*fn)(double)) {
            _action = action;
            _callback = fn; // What to do when we catch a pattern
        }
        static void dump_out(const treshold_t args) {/*{{{*/
            printf ("%d;%.6f;%.6f\n", args.r, args.place, args.sec);
        }/*}}}*/
        treshold_t * do_checking(const treshold_t args);
        map<string, double> cfg;
        virtual void Error(void*);
        int setInput(int, void*);
        int go();
        int WAVE, CHUNKSIZE;
        unsigned long gMCounter, // How many matches we found
                      gSCounter; // How many samples we skipped
        int search_patterns (jack_default_audio_sample_t cur, treshold_t *);
        vector<sVolumes> volume;
    private:
        int _action;
        void (*_callback)(double);
        list<workitm> work;
        vals_t vals;
        Input * _input;
        int read_cfg(const char*);
        int source_app;
        char *input_params;
};

class WavInput : public Input {
    public:
        WavInput(SoundPatty * inst, void * args) {
            _sp_inst = inst;
            char * filename = (char*) args;
            process_headers(filename);
            // ------------------------------------------------------------
            // Adjust _sp_ volume
            // Jack has float (-1..1) while M$ WAV has (-2^15..2^15)
            //
            for (vector<sVolumes>::iterator vol = _sp_inst->volume.begin(); vol != _sp_inst->volume.end(); vol++) {
                vol->min *= (1<<15);
                vol->max *= (1<<15);
            }
        }

        buffer * giveInput(buffer *buf_prop) {
            int16_t buf [SAMPLE_RATE * BUFFERSIZE]; // Process buffer every BUFFERSIZE secs
            if (feof(_fh)) {
                return NULL;
            }
            size_t read_size = fread(buf, 2, SAMPLE_RATE * BUFFERSIZE, _fh);

            // :HACK: fix this, do not depend on jack types where you don't need!
            jack_default_audio_sample_t buf2 [SAMPLE_RATE * BUFFERSIZE];
            for(int i = 0; i < read_size; i++) {
                buf2[i] = (jack_default_audio_sample_t)buf[i];
            }
            buf_prop->buf = buf2;
            buf_prop->nframes = read_size;
            return buf_prop;
        }
    protected:
        int process_headers(const char * infile) {/*{{{*/

            _fh = fopen(infile, "rb");
            if (_fh == NULL) {
                sprintf(errmsg, "Failed to open file %s, exiting\n", infile);
                fatal((void*)errmsg);
            }

            // Read bytes [0-3] and [8-11], they should be "RIFF" and "WAVE" in ASCII
            char header[5];
            fread(header, 1, 4, _fh);

            char sample[] = "RIFF";
            if (! check_sample(sample, header) ) {
                sprintf(errmsg, "RIFF header not found in %s, exiting\n", infile);
                fatal((void*)errmsg);
            }
            // Checking for compression code (21'st byte is 01, 22'nd - 00, little-endian notation
            uint16_t tmp[2]; // two-byte integer
            fseek(_fh, 0x14, 0); // offset = 20 bytes
            fread(&tmp, 2, 2, _fh); // Reading two two-byte samples (comp. code and no. of channels)
            if ( tmp[0] != 1 ) {
                sprintf(errmsg, "Only PCM(1) supported, compression code given: %d\n", tmp[0]);
                fatal ((void*)errmsg);
            }
            // Number of channels must be "MONO"
            if ( tmp[1] != 1 ) {
                sprintf(errmsg, "Only MONO supported, given number of channels: %d\n", tmp[1]);
                fatal ((void*)errmsg);
            }
            fread(&SAMPLE_RATE, 2, 1, _fh); // Single two-byte sample
            _sp_inst->WAVE = (int)SAMPLE_RATE * _sp_inst->cfg["minwavelen"];
            _sp_inst->CHUNKSIZE = _sp_inst->cfg["chunklen"] * (int)SAMPLE_RATE;
            fseek(_fh, 0x22, 0);
            uint16_t BitsPerSample;
            fread(&BitsPerSample, 1, 2, _fh);
            if (BitsPerSample != 16) {
                sprintf(errmsg, "Only 16-bit WAVs supported, given: %d\n", BitsPerSample);
                fatal((void*)errmsg);
            }
            // Get data chunk size here
            fread(header, 1, 4, _fh);
            strcpy(sample, "data");

            if (! check_sample(sample, header)) {
                fatal ((void*)"data chunk not found in byte offset=36, file corrupted.");
            }
            int DATA_SIZE;
            fread(&DATA_SIZE, 4, 1, _fh); // Single two-byte sample
            return 0;
        }

        bool check_sample (const char * sample, const char * b) { // My STRCPY.
            for(int i = 0; sample[i] != '\0'; i++) {
                if (sample[i] != b[i]) {
                    return false;
                }
            }
            return true;
        }/*}}}*/
    private:
        FILE *_fh;

};
void SoundPatty::Error(void * msg) {/*{{{*/
    char * mesg = (char*) msg;
    printf(mesg);
    exit(0);
}/*}}}*/
int SoundPatty::read_cfg (const char * filename) {/*{{{*/
    ifstream file;
    file.open(filename);
    string line;
    int x;
    while (! file.eof() ) {
        getline(file, line);
        x = line.find(":");
        if (x == -1) break; // Last line, exit
        istringstream i(line.substr(x+2));
        double tmp; i >> tmp;
        cfg[line.substr(0,x)] = tmp;
    }
    // Change cfg["treshold\d+_(min|max)"] to
    // something more compatible with sVolumes map
    sVolumes tmp;
    tmp.head = tmp.tail = tmp.max = tmp.min = tmp.proc = 0;
    volume.assign(cfg.size(), tmp); // Make a bit more then nescesarry
    int max_index = 0; // Number of different tresholds
    for(map<string, double>::iterator C = cfg.begin(); C != cfg.end(); C++) {
        // Failed to use boost::regex :(
        if (C->first.find("treshold") == 0) {
            istringstream tmp(C->first.substr(8));
            int i; tmp >> i;
            max_index = max(max_index, i);
            // C->second and volume[i].m{in,ax} are double
            if (C->first.find("_min") != -1) {
                volume[i].min = C->second;
            } else {
                volume[i].max = C->second;
            }
        }
    }
    volume.assign(volume.begin(), volume.begin()+max_index+1);
    return 0;
}/*}}}*/
int SoundPatty::setInput(const int source_app, void * input_params) {/*{{{*/
    if (0 <= source_app && source_app <= 2) {
        this->source_app = source_app;
    }
    switch(this->source_app) {
        case SRC_WAV:
            _input = new WavInput(this, input_params);
            break;
    }
    return 0;
}/*}}}*/

int SoundPatty::go() {
    string which_timeout (_action == ACTION_DUMP ? "sampletimeout" : "catchtimeout");
    buffer buf;

    while (_input->giveInput(&buf) != NULL) { // Have pointer to data
        treshold_t ret;

        for (int i = 0; i < buf.nframes; gSCounter++, i++) {
            jack_default_audio_sample_t cur = buf.buf[i]<0?-buf.buf[i]:buf.buf[i];
            if (search_patterns(cur, &ret))
            {
                if (_action == ACTION_DUMP) {
                    SoundPatty::dump_out(ret);
                }
                if (_action == ACTION_CATCH) {
                    SoundPatty::do_checking(ret);
                }
            }
        }

        if ((double)gSCounter/_input->SAMPLE_RATE > cfg[which_timeout]) {
            //printf ("Timed out. Seconds passed: %.6f\n", (double)gSCounter/_input->SAMPLE_RATE);
            return 0;
        }
    }
}
int SoundPatty::search_patterns (jack_default_audio_sample_t cur, treshold_t * ret) {/*{{{*/
    int v = 0; // Counter for volume
    for (vector<sVolumes>::iterator V = volume.begin(); V != volume.end(); V++, v++) {
        if (V->min <= cur && cur <= V->max) {
            // ------------------------------------------------------------
            // If it's first item in this wave (proc = processing started)
            //
            if (!V->proc) {
                V->tail = gSCounter;
                V->proc = true;
            }
            // ------------------------------------------------------------
            // Here we are just normally in the wave.
            //
            V->head = gSCounter;
        } else { // We are not in the wave
            if (V->proc && (V->min < 0.001 || gSCounter - V->head > WAVE)) {

                //------------------------------------------------------------
                // This wave is over
                //
                V->proc = false; // Stop processing for both cases: found and not

                if (gSCounter - V->tail >= CHUNKSIZE) {
                    // ------------------------------------------------------------
                    // The previous chunk is big enough to be noticed
                    //
                    ret -> r = v;
                    ret -> place = (double)V->tail/_input->SAMPLE_RATE;
                    ret -> sec = (double)(V->head - V->tail)/_input->SAMPLE_RATE;
                    ret -> b = gMCounter++;
                    //callback(v, (double)V->tail/_input->SAMPLE_RATE, (double)(V->head - V->tail)/_input->SAMPLE_RATE, gMCounter++);
                    return 1;
                }
                // ------------------------------------------------------------
                // Else it is too small, but we don't want to do anything in that case
                // So therefore we just say that wave processing is over
                //
            }
        }
    }
    return 0;
}/*}}}*/
// --------------------------------------------------------------------------------/*{{{*/
// This gets called every time there is a treshold found.
// Work array is global
//
// int r - id of treshold found (in config.cfg: treshold_(<?r>\d)_(min|max))
// double place - place of sample from the stream start (sec)
// double sec - length of a found sample (sec)
// int b - index (overall) of sample found
///*}}}*/
treshold_t * SoundPatty::do_checking(const treshold_t tr) {/*{{{*/

    //pair<vals_t::iterator, vals_t::iterator> pa = vals.equal_range(pair<int,double>(r,sec));
    // Manually searching for matching values because with that pairs equal_range doesnt work
    // Iterate through pa

    vals_t fina; // FoundInA

    Range demorange(tr.sec);
    pair<int,Range> sample(tr.r,demorange);
    for (vals_t::iterator it1 = vals.begin(); it1 != vals.end(); it1++) {
        if (it1->first == sample)
            fina.insert(*it1);
    }
    //------------------------------------------------------------
    // We put a indexes here that we use for continued threads
    // (we don't want to create a new "thread" with already
    // used length of a sample)
    //
    set<int> used_a;

    //------------------------------------------------------------
    // Iterating through samples that match the found sample
    //
    for (vals_t::iterator in_a = fina.begin(); in_a != fina.end(); in_a++)
    {
        //printf("%d %.6f matches %.6f (%d)\n", in_a->first.first, sec, in_a->first.second.tm, in_a->second.c);
        int a = in_a->second.c, b = tr.b;
        //------------------------------------------------------------
        // Check if it exists in our work array
        //
        for (list<workitm>::iterator w = work.begin(); w != work.end();) {
            if (b - w->b > round(cfg["maxsteps"])) {
                work.erase(w); w = work.begin(); continue;
            }
            if (b == w->b || a - w->a > round(cfg["maxsteps"]) || w->a >= a) { w++; continue; }
            // ------------------------------------------------------------
            // We fit the "region" here. We either finished,
            // or just increasing len
            //
            w->a = a; w->b = b;
            w->trace.push_back(pair<int,unsigned long>(a,b));
            if (++(w->len) < round(cfg["matchme"])) { // Proceeding with the "thread"
                used_a.insert(a);
                //printf ("Thread expanded to %d\n", w->len);
            } else { // This means the treshold is reached

                // This kind of function is called when the pattern is recognized
                //void(*end_fn)(workitm *, double) = (void*)(workitm *, double) _callback;
                _callback (tr.place + tr.sec);
            }
            w++;
            // End of work iteration array
        }
        if (used_a.find(a) == used_a.end()) {
            work.push_back(workitm(a,b));
            //printf ("Pushed back %d %d\n", a,b);
        }
    }
}/*}}}*/

int main (int argc, char *argv[]) {
    if (argc < 3) {
        fatal ((void*)"Usage: ./readit config.cfg sample.wav\nor\n"
                "./readit config.cfg samplefile.txt catchable.wav\n"
                "./readit config.cfg samplefile.txt jack jack\n");
    }
    SoundPatty * pat = new SoundPatty(argv[1]); // usually config.cfg
    if (argc == 3 || argc == 4) { // WAV
        pat->setInput(SRC_WAV, argv[argc - 1]);
    }
    if (argc == 3) { // Dump out via WAV
        pat->setAction(ACTION_DUMP);
    }
    if (argc == 4) { // Catch
        pat->setAction(ACTION_CATCH, its_over);
    }
    pat->go();

    exit(0);
}
<|endoftext|>


<commit_before>/*
 * SWE_Plane_TS_l_cn_na_sl_nd_settls.cpp
 *
 *  Created on: 29 May 2017
 *      Author: Martin Schreiber <SchreiberX@gmail.com>
 *
 *  Changelog:
 *  	2017-05-29: Based on source swe_plane.cpp
 *					which was also written by Pedro Peixoto
 */

#include "../swe_plane_timeintegrators/SWE_Plane_TS_l_cn_na_sl_nd_settls.hpp"

/**
 * Solve  SWE with Crank-Nicolson implicit time stepping
 *  (spectral formulation for Helmholtz eq) with semi-Lagrangian
 *   SL-SI-SP
 *
 * U_t = L U(0)
 *
 * Fully implicit version:
 *
 * (U(tau) - U(0)) / tau = 0.5*(L U(tau) + L U(0))
 *
 * <=> U(tau) - U(0) =  tau * 0.5*(L U(tau) + L U(0))
 *
 * <=> U(tau) - 0.5* L tau U(tau) = U(0) + tau * 0.5*L U(0)
 *
 * <=> (1 - 0.5 L tau) U(tau) = (1 + tau*0.5*L) U(0)
 *
 * <=> (2/tau - L) U(tau) = (2/tau + L) U(0)
 *
 * <=> U(tau) = (2/tau - L)^{-1} (2/tau + L) U(0)
 *
 * Semi-implicit has Coriolis term as totally explicit
 *
 * Semi-Lagrangian:
 *   U(tau) is on arrival points
 *   U(0) is on departure points
 *
 * Nonlinear term is added following Hortal (2002)
 * http://onlinelibrary.wiley.com/doi/10.1002/qj.200212858314/pdf
 *
 */
void SWE_Plane_TS_l_cn_na_sl_nd_settls::run_timestep(
		PlaneData_Spectral &io_h,	///< prognostic variables
		PlaneData_Spectral &io_u,	///< prognostic variables
		PlaneData_Spectral &io_v,	///< prognostic variables

		double i_dt,
		double i_simulation_timestamp
)
{
	if (i_dt <= 0)
		SWEETError("SWE_Plane_TS_l_cn_na_sl_nd_settls: Only constant time step size allowed (Please set --dt)");

	if (i_simulation_timestamp == 0)
	{
		/*
		 * First time step
		 */
		h_prev = io_h;
		u_prev = io_u;
		v_prev = io_v;
	}

	// Out vars
	PlaneData_Spectral h(io_h.planeDataConfig);
	PlaneData_Spectral u(io_h.planeDataConfig);
	PlaneData_Spectral v(io_h.planeDataConfig);

	// Departure points and arrival points
	ScalarDataArray posx_d = posx_a;
	ScalarDataArray posy_d = posy_a;

	// Parameters
	double h_bar = simVars.sim.h0;
	double g = simVars.sim.gravitation;
	double f0 = simVars.sim.plane_rotating_f0;
	double dt = i_dt;
	double alpha = 2.0/dt;
	double kappa = alpha*alpha;
	double kappa_bar = kappa;
	kappa += f0*f0;
	kappa_bar -= f0*f0;

	Staggering staggering;
	assert(staggering.staggering_type == 'a');

	// Calculate departure points
	semiLagrangian.semi_lag_departure_points_settls(
			u_prev.toPhys(),	v_prev.toPhys(),
			io_u.toPhys(),		io_v.toPhys(),
			posx_a,	posy_a,
			dt,
			posx_d,	posy_d,
			simVars.sim.plane_domain_size,
			&staggering,
			simVars.disc.timestepping_order,

			simVars.disc.semi_lagrangian_max_iterations,
			simVars.disc.semi_lagrangian_convergence_threshold

	);

	// Calculate Divergence and vorticity spectrally
	PlaneData_Spectral div = op.diff_c_x(io_u) + op.diff_c_y(io_v);

	// This could be pre-stored
	PlaneData_Spectral div_prev = op.diff_c_x(u_prev) + op.diff_c_y(v_prev);

	/**
	 * Calculate the RHS
	 *
	 * The terms related to alpha include the current solution.
	 *
	 * In this implementation, the original formulation is rearranged to
	 *
	 *    U + 1/2 dt L U + dt N(U)
	 *
	 *    = 1/2 * dt (2.0/dt U + L U + 2.0 * N(U))
	 */
	PlaneData_Spectral rhs_u = alpha * io_u + f0 * io_v    - g * op.diff_c_x(io_h);
	PlaneData_Spectral rhs_v =  - f0 * io_u + alpha * io_v - g * op.diff_c_y(io_h);
	PlaneData_Spectral rhs_h = alpha * io_h - h_bar * div;

	std::cout << "div " << div.toPhys().physical_reduce_sum() << std::endl;
	std::cout << "rhs_u " << rhs_u.toPhys().physical_reduce_sum() << std::endl;
	std::cout << "rhs_v " << rhs_v.toPhys().physical_reduce_sum() << std::endl;
	std::cout << "rhs_h " << rhs_h.toPhys().physical_reduce_sum() << std::endl;

	// All the RHS are to be evaluated at the departure points
	PlaneData_Physical rhs_u_phys = rhs_u.toPhys();
	PlaneData_Physical rhs_v_phys = rhs_v.toPhys();
	PlaneData_Physical rhs_h_phys = rhs_h.toPhys();
	rhs_u = sampler2D.bicubic_scalar(rhs_u_phys, posx_d, posy_d, -0.5, -0.5);
	rhs_v = sampler2D.bicubic_scalar(rhs_v_phys, posx_d, posy_d, -0.5, -0.5);
	rhs_h = sampler2D.bicubic_scalar(rhs_h_phys, posx_d, posy_d, -0.5, -0.5);

	std::cout << "rhs_u2 " << rhs_u.toPhys().physical_reduce_sum() << std::endl;
	std::cout << "rhs_v2 " << rhs_v.toPhys().physical_reduce_sum() << std::endl;
	std::cout << "rhs_h2 " << rhs_h.toPhys().physical_reduce_sum() << std::endl;
///	// Get data in spectral space
///	rhs_u.request_data_spectral();
///	rhs_v.request_data_spectral();
///	rhs_h.request_data_spectral();

	// Calculate nonlinear term at half timestep and add to RHS of h eq.

	if (!use_only_linear_divergence) //full nonlinear case
	{
		// Extrapolation
		PlaneData_Spectral hdiv = 2.0 * io_h * div - h_prev * div_prev;
		PlaneData_Spectral nonlin(io_h.planeDataConfig);
		if(simVars.misc.use_nonlinear_only_visc != 0)
		{
#if !SWEET_USE_PLANE_SPECTRAL_SPACE
			SWEETError("Implicit diffusion only supported with spectral space activated");
#else
			// Add diffusion (stabilisation)
			hdiv = op.implicit_diffusion(hdiv, simVars.timecontrol.current_timestep_size*simVars.sim.viscosity, simVars.sim.viscosity_order);
#endif
		}
		// Average
	        PlaneData_Physical hdiv_phys = hdiv.toPhys();
		nonlin = 0.5*(io_h*div) + 0.5*sampler2D.bicubic_scalar(hdiv_phys, posx_d, posy_d, -0.5, -0.5);

		// Add to RHS h (TODO (2020-03-16): No clue why there's a -2.0)
		rhs_h = rhs_h - 2.0*nonlin;

		std::cout << "hdiv " << hdiv.toPhys().physical_reduce_sum() << std::endl;
		std::cout << "nonlin " << nonlin.toPhys().physical_reduce_sum() << std::endl;
		std::cout << "rhsh3 " << rhs_h.toPhys().physical_reduce_sum() << std::endl;
	}

	// Build Helmholtz eq.
	PlaneData_Spectral rhs_div = op.diff_c_x(rhs_u)+op.diff_c_y(rhs_v);
	PlaneData_Spectral rhs_vort = op.diff_c_x(rhs_v)-op.diff_c_y(rhs_u);
	PlaneData_Spectral rhs     = kappa* rhs_h / alpha - h_bar * rhs_div - f0 * h_bar * rhs_vort / alpha;

	std::cout << "rhs_div " << rhs_div.toPhys().physical_reduce_sum() << std::endl;
	std::cout << "rhs_vort " << rhs_vort.toPhys().physical_reduce_sum() << std::endl;
	std::cout << "rhs " << rhs.toPhys().physical_reduce_sum() << std::endl;

	// Helmholtz solver
	helmholtz_spectral_solver(kappa, g*h_bar, rhs, h);

	// Update u and v
	u = (1/kappa)*
			( alpha *rhs_u + f0 * rhs_v
					- g * alpha * op.diff_c_x(h)
					- g * f0 * op.diff_c_y(h))
					;

	v = (1/kappa)*
			( alpha *rhs_v - f0 * rhs_u
					+ g * f0 * op.diff_c_x(h)
					- g * alpha * op.diff_c_y(h))
					;

	std::cout << "u " << u.toPhys().physical_reduce_sum() << std::endl;
	std::cout << "v " << v.toPhys().physical_reduce_sum() << std::endl;
	std::cout << "h " << h.toPhys().physical_reduce_sum() << std::endl;

	// Set time (n) as time (n-1)
	h_prev = io_h;
	u_prev = io_u;
	v_prev = io_v;

	// output data
	io_h = h;
	io_u = u;
	io_v = v;
}

/*
 * Setup
 */
void SWE_Plane_TS_l_cn_na_sl_nd_settls::setup(
		bool i_use_only_linear_divergence
)
{
	use_only_linear_divergence = i_use_only_linear_divergence;

	if (simVars.disc.space_grid_use_c_staggering)
		SWEETError("SWE_Plane_TS_l_cn_na_sl_nd_settls: Staggering not supported for l_cn_na_sl_nd_settls");

	// Setup sampler for future interpolations
	sampler2D.setup(simVars.sim.plane_domain_size, op.planeDataConfig);

	// Setup semi-lag
	semiLagrangian.setup(simVars.sim.plane_domain_size, op.planeDataConfig);

	PlaneData_Physical tmp_x(op.planeDataConfig);
	tmp_x.physical_update_lambda_array_indices(
			[&](int i, int j, double &io_data)
			{
		io_data = ((double)i)*simVars.sim.plane_domain_size[0]/(double)simVars.disc.space_res_physical[0];
			},
			false
	);
	PlaneData_Physical tmp_y(op.planeDataConfig);
	tmp_y.physical_update_lambda_array_indices(
			[&](int i, int j, double &io_data)
			{
		io_data = ((double)j)*simVars.sim.plane_domain_size[1]/(double)simVars.disc.space_res_physical[1];
			},
			false
	);

	//Initialize arrival points with h position
	ScalarDataArray pos_x = Convert_PlaneDataPhysical_To_ScalarDataArray::physical_convert(tmp_x);
	ScalarDataArray pos_y = Convert_PlaneDataPhysical_To_ScalarDataArray::physical_convert(tmp_y);

	double cell_size_x = simVars.sim.plane_domain_size[0]/(double)simVars.disc.space_res_physical[0];
	double cell_size_y = simVars.sim.plane_domain_size[1]/(double)simVars.disc.space_res_physical[1];

	// Initialize arrival points with h position
	posx_a = pos_x+0.5*cell_size_x;
	posy_a = pos_y+0.5*cell_size_y;

}

SWE_Plane_TS_l_cn_na_sl_nd_settls::SWE_Plane_TS_l_cn_na_sl_nd_settls(
		SimulationVariables &i_simVars,
		PlaneOperators &i_op
)	:
		simVars(i_simVars),
		op(i_op),

		h_prev(i_op.planeDataConfig),
		u_prev(i_op.planeDataConfig),
		v_prev(i_op.planeDataConfig),

		posx_a(i_op.planeDataConfig->physical_array_data_number_of_elements),
		posy_a(i_op.planeDataConfig->physical_array_data_number_of_elements),

		posx_d(i_op.planeDataConfig->physical_array_data_number_of_elements),
		posy_d(i_op.planeDataConfig->physical_array_data_number_of_elements)
{
}

SWE_Plane_TS_l_cn_na_sl_nd_settls::~SWE_Plane_TS_l_cn_na_sl_nd_settls()
{
}

<commit_msg>more cleaning<commit_after>/*
 * SWE_Plane_TS_l_cn_na_sl_nd_settls.cpp
 *
 *  Created on: 29 May 2017
 *      Author: Martin Schreiber <SchreiberX@gmail.com>
 *
 *  Changelog:
 *  	2017-05-29: Based on source swe_plane.cpp
 *					which was also written by Pedro Peixoto
 */

#include "../swe_plane_timeintegrators/SWE_Plane_TS_l_cn_na_sl_nd_settls.hpp"

/**
 * Solve  SWE with Crank-Nicolson implicit time stepping
 *  (spectral formulation for Helmholtz eq) with semi-Lagrangian
 *   SL-SI-SP
 *
 * U_t = L U(0)
 *
 * Fully implicit version:
 *
 * (U(tau) - U(0)) / tau = 0.5*(L U(tau) + L U(0))
 *
 * <=> U(tau) - U(0) =  tau * 0.5*(L U(tau) + L U(0))
 *
 * <=> U(tau) - 0.5* L tau U(tau) = U(0) + tau * 0.5*L U(0)
 *
 * <=> (1 - 0.5 L tau) U(tau) = (1 + tau*0.5*L) U(0)
 *
 * <=> (2/tau - L) U(tau) = (2/tau + L) U(0)
 *
 * <=> U(tau) = (2/tau - L)^{-1} (2/tau + L) U(0)
 *
 * Semi-implicit has Coriolis term as totally explicit
 *
 * Semi-Lagrangian:
 *   U(tau) is on arrival points
 *   U(0) is on departure points
 *
 * Nonlinear term is added following Hortal (2002)
 * http://onlinelibrary.wiley.com/doi/10.1002/qj.200212858314/pdf
 *
 */
void SWE_Plane_TS_l_cn_na_sl_nd_settls::run_timestep(
		PlaneData_Spectral &io_h,	///< prognostic variables
		PlaneData_Spectral &io_u,	///< prognostic variables
		PlaneData_Spectral &io_v,	///< prognostic variables

		double i_dt,
		double i_simulation_timestamp
)
{
	if (i_dt <= 0)
		SWEETError("SWE_Plane_TS_l_cn_na_sl_nd_settls: Only constant time step size allowed (Please set --dt)");

	if (i_simulation_timestamp == 0)
	{
		/*
		 * First time step
		 */
		h_prev = io_h;
		u_prev = io_u;
		v_prev = io_v;
	}

	// Out vars
	PlaneData_Spectral h(io_h.planeDataConfig);
	PlaneData_Spectral u(io_h.planeDataConfig);
	PlaneData_Spectral v(io_h.planeDataConfig);

	// Departure points and arrival points
	ScalarDataArray posx_d = posx_a;
	ScalarDataArray posy_d = posy_a;

	// Parameters
	double h_bar = simVars.sim.h0;
	double g = simVars.sim.gravitation;
	double f0 = simVars.sim.plane_rotating_f0;
	double dt = i_dt;
	double alpha = 2.0/dt;
	double kappa = alpha*alpha;
	double kappa_bar = kappa;
	kappa += f0*f0;
	kappa_bar -= f0*f0;

	Staggering staggering;
	assert(staggering.staggering_type == 'a');

	// Calculate departure points
	semiLagrangian.semi_lag_departure_points_settls(
			u_prev.toPhys(),	v_prev.toPhys(),
			io_u.toPhys(),		io_v.toPhys(),
			posx_a,	posy_a,
			dt,
			posx_d,	posy_d,
			simVars.sim.plane_domain_size,
			&staggering,
			simVars.disc.timestepping_order,

			simVars.disc.semi_lagrangian_max_iterations,
			simVars.disc.semi_lagrangian_convergence_threshold

	);

	// Calculate Divergence and vorticity spectrally
	PlaneData_Spectral div = op.diff_c_x(io_u) + op.diff_c_y(io_v);

	// This could be pre-stored
	PlaneData_Spectral div_prev = op.diff_c_x(u_prev) + op.diff_c_y(v_prev);

	/**
	 * Calculate the RHS
	 *
	 * The terms related to alpha include the current solution.
	 *
	 * In this implementation, the original formulation is rearranged to
	 *
	 *    U + 1/2 dt L U + dt N(U)
	 *
	 *    = 1/2 * dt (2.0/dt U + L U + 2.0 * N(U))
	 */
	PlaneData_Spectral rhs_u = alpha * io_u + f0 * io_v    - g * op.diff_c_x(io_h);
	PlaneData_Spectral rhs_v =  - f0 * io_u + alpha * io_v - g * op.diff_c_y(io_h);
	PlaneData_Spectral rhs_h = alpha * io_h - h_bar * div;

	// All the RHS are to be evaluated at the departure points
	PlaneData_Physical rhs_u_phys = rhs_u.toPhys();
	PlaneData_Physical rhs_v_phys = rhs_v.toPhys();
	PlaneData_Physical rhs_h_phys = rhs_h.toPhys();
	rhs_u = sampler2D.bicubic_scalar(rhs_u_phys, posx_d, posy_d, -0.5, -0.5);
	rhs_v = sampler2D.bicubic_scalar(rhs_v_phys, posx_d, posy_d, -0.5, -0.5);
	rhs_h = sampler2D.bicubic_scalar(rhs_h_phys, posx_d, posy_d, -0.5, -0.5);

	// Calculate nonlinear term at half timestep and add to RHS of h eq.

	if (!use_only_linear_divergence) //full nonlinear case
	{
		// Extrapolation
		PlaneData_Spectral hdiv = 2.0 * io_h * div - h_prev * div_prev;
		PlaneData_Spectral nonlin(io_h.planeDataConfig);
		if(simVars.misc.use_nonlinear_only_visc != 0)
		{
#if !SWEET_USE_PLANE_SPECTRAL_SPACE
			SWEETError("Implicit diffusion only supported with spectral space activated");
#else
			// Add diffusion (stabilisation)
			hdiv = op.implicit_diffusion(hdiv, simVars.timecontrol.current_timestep_size*simVars.sim.viscosity, simVars.sim.viscosity_order);
#endif
		}
		// Average
	        PlaneData_Physical hdiv_phys = hdiv.toPhys();
		nonlin = 0.5*(io_h*div) + 0.5*sampler2D.bicubic_scalar(hdiv_phys, posx_d, posy_d, -0.5, -0.5);

		// Add to RHS h (TODO (2020-03-16): No clue why there's a -2.0)
		rhs_h = rhs_h - 2.0*nonlin;

	}

	// Build Helmholtz eq.
	PlaneData_Spectral rhs_div = op.diff_c_x(rhs_u)+op.diff_c_y(rhs_v);
	PlaneData_Spectral rhs_vort = op.diff_c_x(rhs_v)-op.diff_c_y(rhs_u);
	PlaneData_Spectral rhs     = kappa* rhs_h / alpha - h_bar * rhs_div - f0 * h_bar * rhs_vort / alpha;

	// Helmholtz solver
	helmholtz_spectral_solver(kappa, g*h_bar, rhs, h);

	// Update u and v
	u = (1/kappa)*
			( alpha *rhs_u + f0 * rhs_v
					- g * alpha * op.diff_c_x(h)
					- g * f0 * op.diff_c_y(h))
					;

	v = (1/kappa)*
			( alpha *rhs_v - f0 * rhs_u
					+ g * f0 * op.diff_c_x(h)
					- g * alpha * op.diff_c_y(h))
					;

	// Set time (n) as time (n-1)
	h_prev = io_h;
	u_prev = io_u;
	v_prev = io_v;

	// output data
	io_h = h;
	io_u = u;
	io_v = v;
}

/*
 * Setup
 */
void SWE_Plane_TS_l_cn_na_sl_nd_settls::setup(
		bool i_use_only_linear_divergence
)
{
	use_only_linear_divergence = i_use_only_linear_divergence;

	if (simVars.disc.space_grid_use_c_staggering)
		SWEETError("SWE_Plane_TS_l_cn_na_sl_nd_settls: Staggering not supported for l_cn_na_sl_nd_settls");

	// Setup sampler for future interpolations
	sampler2D.setup(simVars.sim.plane_domain_size, op.planeDataConfig);

	// Setup semi-lag
	semiLagrangian.setup(simVars.sim.plane_domain_size, op.planeDataConfig);

	PlaneData_Physical tmp_x(op.planeDataConfig);
	tmp_x.physical_update_lambda_array_indices(
			[&](int i, int j, double &io_data)
			{
		io_data = ((double)i)*simVars.sim.plane_domain_size[0]/(double)simVars.disc.space_res_physical[0];
			},
			false
	);
	PlaneData_Physical tmp_y(op.planeDataConfig);
	tmp_y.physical_update_lambda_array_indices(
			[&](int i, int j, double &io_data)
			{
		io_data = ((double)j)*simVars.sim.plane_domain_size[1]/(double)simVars.disc.space_res_physical[1];
			},
			false
	);

	//Initialize arrival points with h position
	ScalarDataArray pos_x = Convert_PlaneDataPhysical_To_ScalarDataArray::physical_convert(tmp_x);
	ScalarDataArray pos_y = Convert_PlaneDataPhysical_To_ScalarDataArray::physical_convert(tmp_y);

	double cell_size_x = simVars.sim.plane_domain_size[0]/(double)simVars.disc.space_res_physical[0];
	double cell_size_y = simVars.sim.plane_domain_size[1]/(double)simVars.disc.space_res_physical[1];

	// Initialize arrival points with h position
	posx_a = pos_x+0.5*cell_size_x;
	posy_a = pos_y+0.5*cell_size_y;

}

SWE_Plane_TS_l_cn_na_sl_nd_settls::SWE_Plane_TS_l_cn_na_sl_nd_settls(
		SimulationVariables &i_simVars,
		PlaneOperators &i_op
)	:
		simVars(i_simVars),
		op(i_op),

		h_prev(i_op.planeDataConfig),
		u_prev(i_op.planeDataConfig),
		v_prev(i_op.planeDataConfig),

		posx_a(i_op.planeDataConfig->physical_array_data_number_of_elements),
		posy_a(i_op.planeDataConfig->physical_array_data_number_of_elements),

		posx_d(i_op.planeDataConfig->physical_array_data_number_of_elements),
		posy_d(i_op.planeDataConfig->physical_array_data_number_of_elements)
{
}

SWE_Plane_TS_l_cn_na_sl_nd_settls::~SWE_Plane_TS_l_cn_na_sl_nd_settls()
{
}

<|endoftext|>


<commit_before>#pragma once
//=====================================================================//
/*!	@file
	@brief	画像テンプレート
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <vector>
#include <boost/unordered_set.hpp>
#include <boost/foreach.hpp>
#include "utils/vtx.hpp"

namespace img {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief	イメージ・ベース・テンプレート・クラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class PIX>
	struct img_base {

		typedef PIX	value_type;

	private:
		std::vector<PIX>	img_;

		vtx::spos	size_;
		bool		alpha_;

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
		*/
		//-----------------------------------------------------------------//
		img_base() : img_(), size_(0), alpha_(false) { }

		//-----------------------------------------------------------------//
		/*!
			@brief	イメージを確保する
			@param[in]	width	横幅を指定
			@param[in]	height	高さを指定
			@param[in]	alpha	アルファチャネルを有効にする場合に「true」
		*/
		//-----------------------------------------------------------------//
		void create(const vtx::spos& size, bool alpha) {
			img_.clear();
			size_ = size;
			img_.resize(size_.x * size_.y);
			alpha_ = alpha;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	画像サイズを得る
			@return	サイズ
		*/
		//-----------------------------------------------------------------//
		const vtx::spos& size() const { return size_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	アルファ有効か
			@return	有効なら「true」
		*/
		//-----------------------------------------------------------------//
		bool alpha() const { return alpha_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	「空」検査
			@return	「空」なら「true」
		*/
		//-----------------------------------------------------------------//
		bool empty() const { return img_.empty(); }

		//-----------------------------------------------------------------//
		/*!
			@brief	使用している色数の総数
			@return	色数
		*/
		//-----------------------------------------------------------------//
		uint32_t count_color() const {
			boost::unordered_set<PIX> n;
			BOOST_FOREACH(const PIX& c, img_) {
				n.insert(c);
			}
			return static_cast<uint32_t>(n.size());
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	描画エリアか検査
			@return 領域なら「true」
		*/
		//-----------------------------------------------------------------//
		bool area(const vtx::spos& pos) const {
			if(static_cast<uint16_t>(pos.x) < static_cast<uint16_t>(size_.x) &&
			   static_cast<uint16_t>(pos.y) < static_cast<uint16_t>(size_.y)) {
				return true;
			} else {
				return false;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	画素の読み出し参照
			@param[in]	pos	位置
			@return 画素
		*/
		//-----------------------------------------------------------------//
		const PIX& get(const vtx::spos& pos) const {
			if(area(pos)) {
				return img_[size_.x * pos.y + pos.x];
			} else {
				static PIX pix;
				return pix;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	画素の参照
			@param[in]	pos	位置
			@return 画素
		*/
		//-----------------------------------------------------------------//
		PIX& at(const vtx::spos& pos) {
			if(area(pos)) {
				return img_[size_.x * pos.y + pos.x];
			} else {
				static PIX pix;
				return pix;
			}
		}
	};
}

<commit_msg>基本画像テンプレート修正<commit_after>#pragma once
//=====================================================================//
/*!	@file
	@brief	標準イメージを扱うテンプレートクラス
	@author	平松邦仁 (hira@rvf-rc45.net)
*/
//=====================================================================//
#include <vector>
#include <boost/unordered_set.hpp>
#include <boost/foreach.hpp>
#include "i_img.hpp"

namespace img {

	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	/*!
		@brief	任意形式の画像を扱うクラス
	*/
	//+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++//
	template <class T, uint32_t clutsize = 0>
	struct img_basic {
		typedef T	value_type;

	private:
		vtx::spos	size_;
		bool		alpha_;
		std::vector<T>	img_;

		uint32_t			clut_limit_;
		std::vector<rgba8>	clut_;

	public:
		//-----------------------------------------------------------------//
		/*!
			@brief	コンストラクター
		*/
		//-----------------------------------------------------------------//
		img_basic() : size_(0), alpha_(false), img_(),
			clut_limit_(0) {
			clut_.resize(clutsize);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	デストラクター
		*/
		//-----------------------------------------------------------------//
		virtual ~img_basic() { }

		//-----------------------------------------------------------------//
		/*!
			@brief	イメージのタイプを得る。
			@return	イメージタイプ
		*/
		//-----------------------------------------------------------------//
		IMG::type get_type() const { return IMG::FULL8; }

		//-----------------------------------------------------------------//
		/*!
			@brief	イメージを確保する
			@param[in]	size	サイズ
			@param[in]	alpha	アルファチャネルを有効にする場合に「true」
		*/
		//-----------------------------------------------------------------//
		void create(const vtx::spos& size, bool alpha = false) {
			img_.clear();
			size_ = size;
			img_.resize(size_.x * size_.y);
			alpha_ = alpha;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	カラー・ルック・アップ・テーブルを設定
			@param[in]	idx	テーブルの位置
			@param[in]	c	設定するカラー
			@return 正常なら「true」
		*/
		//-----------------------------------------------------------------//
		bool put_clut(uint32_t idx, const rgba8& c) {
			if(idx < clut_.size()) {
				clut_[idx] = c;
				return true;
			}
			return false;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	カラー・ルック・アップ・テーブルを得る
			@param[in]	idx	テーブルの位置
			@param[in]	c	受け取るカラー参照ポイント
			@return 正常なら「true」
		*/
		//-----------------------------------------------------------------//
		bool get_clut(uint32_t idx, rgba8& c) const {
			if(idx < clut_.size()) {
				c = clut_[idx];
				return true;
			}
			return false;
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	イメージに点を描画
			@param[in]	pos	描画位置
			@param[in]	c	描画するカラー
			@return 領域なら「true」
		*/
		//-----------------------------------------------------------------//
		template <class PIX>
		bool put_pixel(const vtx::spos& pos, const PIX& c) {
			if(T::type_ != PIX::type_) return false;
			if(img_.empty()) return false;
			if(pos.x >= 0 && pos.x < size_.x && pos.y >= 0 && pos.y < size_.y) {
				img_[size_.x * pos.y + pos.x] = c;
				return true;
			} else {
				return false;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	イメージの点を得る
			@param[in]	pos	描画位置
			@param[in]	c	描画されたカラーを受け取るリファレンス
			@return 領域なら「true」
		*/
		//-----------------------------------------------------------------//
		template <class PIX>
		bool get_pixel(const vtx::spos& pos, PIX& c) const {
			if(T::type_ != PIX::type_) return false;
			if(img_.empty()) return false;
			if(pos.x >= 0 && pos.x < size_.x && pos.y >= 0 && pos.y < size_.y) {
				c  = img_[size_.x * pos.y + pos.x];
				return true;
			} else {
				return false;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	アルファ合成描画
			@param[in]	pos	描画位置
			@param[in]	c	描画カラー
			@return 領域なら「true」
		*/
		//-----------------------------------------------------------------//
		bool alpha_pixel(const vtx::spos& pos, rgba8& c) {
			if(T::type_ != PIX::type_) return false;
			if(img_.empty()) return false;
			if(pos.x >= 0 && pos.x < size_.x && pos.y >= 0 && pos.y < size_.y) {
				rgba8 s = img_[size_.x * pos.y + pos.x];
				unsigned short i = 256 - c.a;
				unsigned short a = c.a + 1;
				img_[size_.x * pos.y + pos.x].set(((s.r * i) + (c.r * a)) >> 8,
										   ((s.g * i) + (c.g * a)) >> 8,
										   ((s.b * i) + (c.b * a)) >> 8);
				return true;
			} else {
				return false;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	イメージのアドレスを得る。
			@return	イメージのポインター
		*/
		//-----------------------------------------------------------------//
		const void* get_image() const { return static_cast<const void*>(&img_[0]); }

		//-----------------------------------------------------------------//
		/*!
			@brief	イメージのサイズを得る
			@return	イメージのサイズ
		*/
		//-----------------------------------------------------------------//
		const vtx::spos& get_size() const { return size_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	カラー・ルック・アップ・テーブルの最大数を返す
			@return	最大数
		*/
		//-----------------------------------------------------------------//
		int get_clut_limit() const { return clut_limit_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	アルファ・チャネルが有効か調べる
			@return	アルファ・チャネルが有効なら「true」
		*/
		//-----------------------------------------------------------------//
		bool test_alpha() const { return alpha_; }

		//-----------------------------------------------------------------//
		/*!
			@brief	画像が「空」か検査する
			@return	「空」なら「true」
		*/
		//-----------------------------------------------------------------//
		bool empty() const { return img_.empty(); }

		//-----------------------------------------------------------------//
		/*!
			@brief	利用している色数の総数をカウントする
			@return	利用している色数
		*/
		//-----------------------------------------------------------------//
		uint32_t count_color() const {
			boost::unordered_set<T> n;
			BOOST_FOREACH(const T& c, img_) {
				n.insert(c);
			}
			return static_cast<uint32_t>(n.size());
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	イメージの部分コピー
			@param[in]	dst		コピー先
			@param[in]	isrc	ソースイメージ
			@param[in]	rsrc	ソースの領域
		*/
		//-----------------------------------------------------------------//
		void copy(const vtx::spos& dst, const img_rgba8& isrc, const vtx::srect& rsrc) {
			vtx::spos p;
			for(p.y = 0; p.y < rsrc.size.y; ++p.y) {
				for(p.x = 0; p.x < rsrc.size.x; ++p.x) {
					rgba8 c;
					if(isrc.get_pixel(p + rsrc.org, c)) {
						put_pixel(p + dst, c);
					}
				}
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	rgba8 イメージからのコピー
			@param[in]	src	ソースイメージ
		*/
		//-----------------------------------------------------------------//
		void copy(const img_rgba8& src) { copy(vtx::spos(0), src, vtx::srect(vtx::spos(0), src.get_size())); }

		//-----------------------------------------------------------------//
		/*!
			@brief	idx8 イメージからのコピー
			@param[in]	dst		コピー先の位置
			@param[in]	isrc	ソースイメージ
			@param[in]	rsrc	ソースの領域
		*/
		//-----------------------------------------------------------------//
		void copy(const vtx::spos& dst, const img_idx8& isrc, const vtx::srect& rsrc) {
			vtx::spos p;
			for(p.y = 0; p.y < rsrc.size.y; ++p.y) {
				for(p.x = 0; p.x < rsrc.size.x; ++p.x) {
					rgba8 c;
					if(isrc.get_pixel(p + rsrc.org, c)) {
						put_pixel(p + dst, c);
					}
				}
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	交換
			@param[in]	src	ソース・コンテキスト
		*/
		//-----------------------------------------------------------------//
		void swap(img_basic& src) {
			size_.swap(src.size_);
			img_.swap(src.img_);
			std::swap(clut_limit_, src.clut_limit_);
			clut_.swap(src.clut_);
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	単色で塗りつぶす
			@param[in]	c	塗る色
		*/
		//-----------------------------------------------------------------//
		inline void fill(const rgba8& c) {
			for(size_t i = 0; i < img_.size(); ++i) {
				img_[i] = c;
			}
		}

		//-----------------------------------------------------------------//
		/*!
			@brief	イメージを廃棄する
		*/
		//-----------------------------------------------------------------//
		void destroy() {
			size_.set(0);
			alpha_ = false;
			std::vector<T>().swap(img_);
			clut_limit_ = 0;
			std::vector<rgba8>.swap(clut_);
		}
	};
}

<|endoftext|>