<commit_before>// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "bin/vmstats_impl.h"

#include <sstream>

#include "bin/fdutils.h"
#include "bin/file.h"
#include "bin/log.h"
#include "bin/platform.h"
#include "bin/socket.h"
#include "bin/thread.h"
#include "bin/utils.h"
#include "include/dart_debugger_api.h"
#include "platform/json.h"

#define BUFSIZE 8192
#define RETRY_PAUSE 100  // milliseconds

static const char* INDEX_HTML = "index.html";
static const char* VMSTATS_HTML = "vmstats.html";
static const char* DEFAULT_HOST = "localhost";

// Global static pointer used to ensure a single instance of the class.
VmStats* VmStats::instance_ = NULL;
dart::Monitor VmStats::instance_monitor_;
dart::Mutex VmStatusService::mutex_;

void VmStats::Start(int port, const char* root_dir) {
  if (instance_ != NULL) {
    FATAL("VmStats already started.");
  }
  MonitorLocker ml(&instance_monitor_);
  instance_ = new VmStats();
  VmStatusService::InitOnce();
  Socket::Initialize();

  if (root_dir != NULL) {
    instance_->root_directory_ = root_dir;
  }

  // TODO(tball): allow host to be specified.
  char* host = const_cast<char*>(DEFAULT_HOST);
  OSError* os_error;
  const char* host_ip = Socket::LookupIPv4Address(host, &os_error);
  if (host_ip == NULL) {
    Log::PrintErr("Failed IP lookup of VmStats host %s: %s\n",
                  host, os_error->message());
    return;
  }

  const intptr_t BACKLOG = 128;  // Default value from HttpServer.dart
  int64_t address = ServerSocket::CreateBindListen(host_ip, port, BACKLOG);
  if (address < 0) {
    Log::PrintErr("Failed binding VmStats socket: %s:%d\n", host, port);
    return;
  }
  instance_->bind_address_ = address;
  Log::Print(
#if defined(TARGET_ARCH_X64)
      "VmStats URL: http://%s:%ld/\n",
#else
      "VmStats URL: http://%s:%d/\n",
#endif
      host,
             Socket::GetPort(address));

  instance_->running_ = true;
  int errno = dart::Thread::Start(WebServer, address);
  if (errno != 0) {
    Log::PrintErr("Failed starting VmStats thread: %d\n", errno);
    Shutdown();
  }
}

void VmStats::Stop() {
  MonitorLocker ml(&instance_monitor_);
  if (instance_ != NULL) {
    instance_->running_ = false;
  }
}

void VmStats::Shutdown() {
  MonitorLocker ml(&instance_monitor_);
  Socket::Close(instance_->bind_address_);
  delete instance_;
  instance_ = NULL;
}

void VmStats::AddIsolate(IsolateData* isolate_data,
                         Dart_Isolate isolate) {
  MonitorLocker ml(&instance_monitor_);
  if (instance_ != NULL) {
    instance_->isolate_table_[isolate_data] = isolate;
  }
}

void VmStats::RemoveIsolate(IsolateData* isolate_data) {
  MonitorLocker ml(&instance_monitor_);
  if (instance_ != NULL) {
    instance_->isolate_table_.erase(isolate_data);
  }
}

static const char* ContentType(const char* url) {
  const char* suffix = strrchr(url, '.');
  if (suffix != NULL) {
    if (!strcmp(suffix, ".html")) {
      return "text/html; charset=UTF-8";
    }
    if (!strcmp(suffix, ".dart")) {
      return "application/dart; charset=UTF-8";
    }
    if (!strcmp(suffix, ".js")) {
      return "application/javascript; charset=UTF-8";
    }
    if (!strcmp(suffix, ".css")) {
      return "text/css; charset=UTF-8";
    }
    if (!strcmp(suffix, ".gif")) {
      return "image/gif";
    }
    if (!strcmp(suffix, ".png")) {
      return "image/png";
    }
    if (!strcmp(suffix, ".jpg") || !strcmp(suffix, ".jpeg")) {
      return "image/jpeg";
    }
  }
  return "text/plain";
}

void VmStats::WebServer(uword bind_address) {
  while (true) {
    intptr_t socket = ServerSocket::Accept(bind_address);
    if (socket == ServerSocket::kTemporaryFailure) {
      // Not a real failure, woke up but no connection available.

      // Use MonitorLocker.Wait(), since it has finer granularity than sleep().
      dart::Monitor m;
      MonitorLocker ml(&m);
      ml.Wait(RETRY_PAUSE);

      continue;
    }
    if (socket < 0) {
      // Stop() closed the socket.
      return;
    }
    FDUtils::SetBlocking(socket);

    // TODO(tball): rewrite this to use STL, so as to eliminate the static
    // buffer and support resource URLs that are longer than BUFSIZE.

    // Read request.
    // TODO(tball): support partial reads, possibly needed for POST uploads.
    char buffer[BUFSIZE + 1];
    int len = read(socket, buffer, BUFSIZE);
    if (len <= 0) {
      // Invalid HTTP request, ignore.
      continue;
    }
    buffer[len] = '\0';

    // Verify it's a GET request.
    // TODO(tball): support POST requests.
    if (strncmp("GET ", buffer, 4) != 0 && strncmp("get ", buffer, 4) != 0) {
      Log::PrintErr("Unsupported HTTP request type");
      const char* response = "HTTP/1.1 403 Forbidden\n"
          "Content-Length: 120\n"
          "Connection: close\n"
          "Content-Type: text/html\n\n"
          "\n<title>403 Forbidden</title>\n"
          "\n
Forbidden
\nUnsupported HTTP request type\n"
          "\n";
      Socket::Write(socket, response, strlen(response));
      Socket::Close(socket);
      continue;
    }

    // Extract GET URL, and null-terminate URL in case request line has
    // HTTP version.
    for (int i = 4; i < len; i++) {
      if (buffer[i] == ' ') {
        buffer[i] = '\0';
      }
    }
    char* url = &buffer[4];

    Log::Print("vmstats: %s requested\n", url);
    char* content = NULL;

    // Check for VmStats-specific URLs.
    if (strcmp(url, "/isolates") == 0) {
      content = instance_->IsolatesStatus();
    } else {
      // Check plug-ins.
      content = VmStatusService::GetVmStatus(url);
    }

    if (content != NULL) {
      size_t content_len = strlen(content);
      len = snprintf(buffer, BUFSIZE,
#if defined(TARGET_ARCH_X64)
          "HTTP/1.1 200 OK\nContent-Type: application/json; charset=UTF-8\n"
          "Content-Length: %lx\n\n",
#else
          "HTTP/1.1 200 OK\nContent-Type: application/json; charset=UTF-8\n"
          "Content-Length: %d\n\n",
#endif
          content_len);
      Socket::Write(socket, buffer, strlen(buffer));
      Socket::Write(socket, content, content_len);
      Socket::Write(socket, "\n", 1);
      Socket::Write(socket, buffer, strlen(buffer));
      free(content);
    } else {
      // No status content with this URL, return file or resource content.
      std::string path(instance_->root_directory_);
      path.append(url);

      // Expand directory URLs.
      if (strcmp(url, "/") == 0) {
        path.append(VMSTATS_HTML);
      } else if (url[strlen(url) - 1] == '/') {
        path.append(INDEX_HTML);
      }

      bool success = false;
      if (File::Exists(path.c_str())) {
        File* f = File::Open(path.c_str(), File::kRead);
        if (f != NULL) {
          intptr_t len = f->Length();
          char* text_buffer = reinterpret_cast<char*>(malloc(len));
          if (f->ReadFully(text_buffer, len)) {
            const char* content_type = ContentType(path.c_str());
            snprintf(buffer, BUFSIZE,
#if defined(TARGET_ARCH_X64)
                "HTTP/1.1 200 OK\nContent-Type: %s\n"
                "Content-Length: %ld\n\n",
#else
                "HTTP/1.1 200 OK\nContent-Type: %s\n"
                "Content-Length: %d\n\n",
#endif
                content_type, len);
            Socket::Write(socket, buffer, strlen(buffer));
            Socket::Write(socket, text_buffer, len);
            Socket::Write(socket, "\n", 1);
            success = true;
          }
          free(text_buffer);
          delete f;
        }
      } else {
        // TODO(tball): look up linked in resource.
      }
      if (!success) {
        const char* response = "HTTP/1.1 404 Not Found\n\n";
        Socket::Write(socket, response, strlen(response));
      }
    }
    Socket::Close(socket);
  }

  Shutdown();
}

char* VmStats::IsolatesStatus() {
  std::ostringstream stream;
  stream << '{' << std::endl;
  stream << "\"isolates\": [" << std::endl;
  IsolateTable::iterator itr;
  bool first = true;
  for (itr = isolate_table_.begin(); itr != isolate_table_.end(); ++itr) {
    Dart_Isolate isolate = itr->second;
    static char request[512];
    snprintf(request, sizeof(request),
#if defined(TARGET_ARCH_X64)
             "/isolate/0x%lx",
#else
             "/isolate/0x%llx",
#endif
             reinterpret_cast<int64_t>(isolate));
    char* status = VmStatusService::GetVmStatus(request);
    if (status != NULL) {
      stream << status;
      if (!first) {
        stream << "," << std::endl;
      }
      first = false;
    }
    free(status);
  }
  stream << std::endl << "]";
  stream << std::endl << '}' << std::endl;
  return strdup(stream.str().c_str());
}

// Global static pointer used to ensure a single instance of the class.
VmStatusService* VmStatusService::instance_ = NULL;

void VmStatusService::InitOnce() {
  ASSERT(VmStatusService::instance_ == NULL);
  VmStatusService::instance_ = new VmStatusService();

  // Register built-in status plug-ins. RegisterPlugin is not used because
  // this isn't called within an isolate, and because parameter checking
  // isn't necessary.
  instance_->RegisterPlugin(&Dart_GetVmStatus);

  // TODO(tball): dynamically load any additional plug-ins.
}

int VmStatusService::RegisterPlugin(Dart_VmStatusCallback callback) {
  MutexLocker ml(&mutex_);
  if (callback == NULL) {
    return -1;
  }
  VmStatusPlugin* plugin = new VmStatusPlugin(callback);
  VmStatusPlugin* list = instance_->registered_plugin_list_;
  if (list == NULL) {
    instance_->registered_plugin_list_ = plugin;
  } else {
    list->Append(plugin);
  }
  return 0;
}

char* VmStatusService::GetVmStatus(const char* request) {
  VmStatusPlugin* plugin = instance_->registered_plugin_list_;
  while (plugin != NULL) {
    char* result = (plugin->callback())(request);
    if (result != NULL) {
      return result;
    }
    plugin = plugin->next();
  }
  return NULL;
}
<commit_msg>- Fix string formatting. Review URL: https://codereview.chromium.org//12340088<commit_after>// Copyright (c) 2013, the Dart project authors.  Please see the AUTHORS file
// for details. All rights reserved. Use of this source code is governed by a
// BSD-style license that can be found in the LICENSE file.

#include "bin/vmstats_impl.h"

#include <sstream>

#include "bin/fdutils.h"
#include "bin/file.h"
#include "bin/log.h"
#include "bin/platform.h"
#include "bin/socket.h"
#include "bin/thread.h"
#include "bin/utils.h"
#include "include/dart_debugger_api.h"
#include "platform/json.h"

#define BUFSIZE 8192
#define RETRY_PAUSE 100  // milliseconds

static const char* INDEX_HTML = "index.html";
static const char* VMSTATS_HTML = "vmstats.html";
static const char* DEFAULT_HOST = "localhost";

// Global static pointer used to ensure a single instance of the class.
VmStats* VmStats::instance_ = NULL;
dart::Monitor VmStats::instance_monitor_;
dart::Mutex VmStatusService::mutex_;

void VmStats::Start(int port, const char* root_dir) {
  if (instance_ != NULL) {
    FATAL("VmStats already started.");
  }
  MonitorLocker ml(&instance_monitor_);
  instance_ = new VmStats();
  VmStatusService::InitOnce();
  Socket::Initialize();

  if (root_dir != NULL) {
    instance_->root_directory_ = root_dir;
  }

  // TODO(tball): allow host to be specified.
  char* host = const_cast<char*>(DEFAULT_HOST);
  OSError* os_error;
  const char* host_ip = Socket::LookupIPv4Address(host, &os_error);
  if (host_ip == NULL) {
    Log::PrintErr("Failed IP lookup of VmStats host %s: %s\n",
                  host, os_error->message());
    return;
  }

  const intptr_t BACKLOG = 128;  // Default value from HttpServer.dart
  int64_t address = ServerSocket::CreateBindListen(host_ip, port, BACKLOG);
  if (address < 0) {
    Log::PrintErr("Failed binding VmStats socket: %s:%d\n", host, port);
    return;
  }
  instance_->bind_address_ = address;
  Log::Print("VmStats URL: http://%s:%"Pd"/\n", host, Socket::GetPort(address));

  instance_->running_ = true;
  int err = dart::Thread::Start(WebServer, address);
  if (err != 0) {
    Log::PrintErr("Failed starting VmStats thread: %d\n", err);
    Shutdown();
  }
}

void VmStats::Stop() {
  MonitorLocker ml(&instance_monitor_);
  if (instance_ != NULL) {
    instance_->running_ = false;
  }
}

void VmStats::Shutdown() {
  MonitorLocker ml(&instance_monitor_);
  Socket::Close(instance_->bind_address_);
  delete instance_;
  instance_ = NULL;
}

void VmStats::AddIsolate(IsolateData* isolate_data,
                         Dart_Isolate isolate) {
  MonitorLocker ml(&instance_monitor_);
  if (instance_ != NULL) {
    instance_->isolate_table_[isolate_data] = isolate;
  }
}

void VmStats::RemoveIsolate(IsolateData* isolate_data) {
  MonitorLocker ml(&instance_monitor_);
  if (instance_ != NULL) {
    instance_->isolate_table_.erase(isolate_data);
  }
}

static const char* ContentType(const char* url) {
  const char* suffix = strrchr(url, '.');
  if (suffix != NULL) {
    if (!strcmp(suffix, ".html")) {
      return "text/html; charset=UTF-8";
    }
    if (!strcmp(suffix, ".dart")) {
      return "application/dart; charset=UTF-8";
    }
    if (!strcmp(suffix, ".js")) {
      return "application/javascript; charset=UTF-8";
    }
    if (!strcmp(suffix, ".css")) {
      return "text/css; charset=UTF-8";
    }
    if (!strcmp(suffix, ".gif")) {
      return "image/gif";
    }
    if (!strcmp(suffix, ".png")) {
      return "image/png";
    }
    if (!strcmp(suffix, ".jpg") || !strcmp(suffix, ".jpeg")) {
      return "image/jpeg";
    }
  }
  return "text/plain";
}

void VmStats::WebServer(uword bind_address) {
  while (true) {
    intptr_t socket = ServerSocket::Accept(bind_address);
    if (socket == ServerSocket::kTemporaryFailure) {
      // Not a real failure, woke up but no connection available.

      // Use MonitorLocker.Wait(), since it has finer granularity than sleep().
      dart::Monitor m;
      MonitorLocker ml(&m);
      ml.Wait(RETRY_PAUSE);

      continue;
    }
    if (socket < 0) {
      // Stop() closed the socket.
      return;
    }
    FDUtils::SetBlocking(socket);

    // TODO(tball): rewrite this to use STL, so as to eliminate the static
    // buffer and support resource URLs that are longer than BUFSIZE.

    // Read request.
    // TODO(tball): support partial reads, possibly needed for POST uploads.
    char buffer[BUFSIZE + 1];
    int len = read(socket, buffer, BUFSIZE);
    if (len <= 0) {
      // Invalid HTTP request, ignore.
      continue;
    }
    buffer[len] = '\0';

    // Verify it's a GET request.
    // TODO(tball): support POST requests.
    if (strncmp("GET ", buffer, 4) != 0 && strncmp("get ", buffer, 4) != 0) {
      Log::PrintErr("Unsupported HTTP request type");
      const char* response = "HTTP/1.1 403 Forbidden\n"
          "Content-Length: 120\n"
          "Connection: close\n"
          "Content-Type: text/html\n\n"
          "\n<title>403 Forbidden</title>\n"
          "\n
Forbidden
\nUnsupported HTTP request type\n"
          "\n";
      Socket::Write(socket, response, strlen(response));
      Socket::Close(socket);
      continue;
    }

    // Extract GET URL, and null-terminate URL in case request line has
    // HTTP version.
    for (int i = 4; i < len; i++) {
      if (buffer[i] == ' ') {
        buffer[i] = '\0';
      }
    }
    char* url = &buffer[4];

    Log::Print("vmstats: %s requested\n", url);
    char* content = NULL;

    // Check for VmStats-specific URLs.
    if (strcmp(url, "/isolates") == 0) {
      content = instance_->IsolatesStatus();
    } else {
      // Check plug-ins.
      content = VmStatusService::GetVmStatus(url);
    }

    if (content != NULL) {
      size_t content_len = strlen(content);
      len = snprintf(buffer, BUFSIZE,
          "HTTP/1.1 200 OK\nContent-Type: application/json; charset=UTF-8\n"
          "Content-Length: %"Pu"\n\n",
          content_len);
      Socket::Write(socket, buffer, strlen(buffer));
      Socket::Write(socket, content, content_len);
      Socket::Write(socket, "\n", 1);
      Socket::Write(socket, buffer, strlen(buffer));
      free(content);
    } else {
      // No status content with this URL, return file or resource content.
      std::string path(instance_->root_directory_);
      path.append(url);

      // Expand directory URLs.
      if (strcmp(url, "/") == 0) {
        path.append(VMSTATS_HTML);
      } else if (url[strlen(url) - 1] == '/') {
        path.append(INDEX_HTML);
      }

      bool success = false;
      if (File::Exists(path.c_str())) {
        File* f = File::Open(path.c_str(), File::kRead);
        if (f != NULL) {
          intptr_t len = f->Length();
          char* text_buffer = reinterpret_cast<char*>(malloc(len));
          if (f->ReadFully(text_buffer, len)) {
            const char* content_type = ContentType(path.c_str());
            snprintf(buffer, BUFSIZE,
                "HTTP/1.1 200 OK\nContent-Type: %s\n"
                "Content-Length: %"Pu"\n\n",
                content_type, len);
            Socket::Write(socket, buffer, strlen(buffer));
            Socket::Write(socket, text_buffer, len);
            Socket::Write(socket, "\n", 1);
            success = true;
          }
          free(text_buffer);
          delete f;
        }
      } else {
        // TODO(tball): look up linked in resource.
      }
      if (!success) {
        const char* response = "HTTP/1.1 404 Not Found\n\n";
        Socket::Write(socket, response, strlen(response));
      }
    }
    Socket::Close(socket);
  }

  Shutdown();
}

char* VmStats::IsolatesStatus() {
  std::ostringstream stream;
  stream << '{' << std::endl;
  stream << "\"isolates\": [" << std::endl;
  IsolateTable::iterator itr;
  bool first = true;
  for (itr = isolate_table_.begin(); itr != isolate_table_.end(); ++itr) {
    Dart_Isolate isolate = itr->second;
    static char request[512];
    snprintf(request, sizeof(request),
             "/isolate/0x%"Px,
             reinterpret_cast<intptr_t>(isolate));
    char* status = VmStatusService::GetVmStatus(request);
    if (status != NULL) {
      stream << status;
      if (!first) {
        stream << "," << std::endl;
      }
      first = false;
    }
    free(status);
  }
  stream << std::endl << "]";
  stream << std::endl << '}' << std::endl;
  return strdup(stream.str().c_str());
}

// Global static pointer used to ensure a single instance of the class.
VmStatusService* VmStatusService::instance_ = NULL;

void VmStatusService::InitOnce() {
  ASSERT(VmStatusService::instance_ == NULL);
  VmStatusService::instance_ = new VmStatusService();

  // Register built-in status plug-ins. RegisterPlugin is not used because
  // this isn't called within an isolate, and because parameter checking
  // isn't necessary.
  instance_->RegisterPlugin(&Dart_GetVmStatus);

  // TODO(tball): dynamically load any additional plug-ins.
}

int VmStatusService::RegisterPlugin(Dart_VmStatusCallback callback) {
  MutexLocker ml(&mutex_);
  if (callback == NULL) {
    return -1;
  }
  VmStatusPlugin* plugin = new VmStatusPlugin(callback);
  VmStatusPlugin* list = instance_->registered_plugin_list_;
  if (list == NULL) {
    instance_->registered_plugin_list_ = plugin;
  } else {
    list->Append(plugin);
  }
  return 0;
}

char* VmStatusService::GetVmStatus(const char* request) {
  VmStatusPlugin* plugin = instance_->registered_plugin_list_;
  while (plugin != NULL) {
    char* result = (plugin->callback())(request);
    if (result != NULL) {
      return result;
    }
    plugin = plugin->next();
  }
  return NULL;
}
<|endoftext|>


<commit_before>#include <iostream>
#include <thread>
#include <mutex>

// Suppose we have a class:
struct A {
  // That has a variable,
  int m_count;
  // that is accessed simulateously by two threads.
  // Then we need to protect that variable using a mutex, say this one:
  std::mutex m_count_mutex;
  // Because, when we don't use locking, then things go wrong.
};

// For convenience, lets instantiate an object of type A globally,
// even though that is normally evil.
A a;

// Consider this thread that accesses m_count without locking!
void thr_no_lock()
{
  // Loop 100000 times, each loop incrementing m_count by one.
  for (int i = 0; i < 100000; ++i)
  {
    // Read m_count.
    int read = a.m_count;
    // Add 1 and write it back.
    a.m_count = read + 1;
  }
  // If the reading and writing was atomic then
  // this loop will have added precisely 100000.
}

// Also have a thread that does the same but with locking:
void thr_with_lock()
{
  for (int i = 0; i < 100000; ++i)
  {
    std::unique_lock<std::mutex> lk(a.m_count_mutex);
    int read = a.m_count;
    a.m_count = read + 1;
  }
}

int main()
{
  // Do the test without locking first.
  a.m_count = 0;
  {
    std::thread t1(thr_no_lock);
    std::thread t2(thr_with_lock);

    // Wait for t1 and t2 to be finished.
    t1.join();
    t2.join();
  }

  // This result will be LESS THAN 200000!
  std::cout << "Afterwards the value of m_count, without locking, is: " << a.m_count << std::endl;

  // And again, but now both threads use locking.
  a.m_count = 0;
  {
    std::thread t1(thr_with_lock);
    std::thread t2(thr_with_lock);

    t1.join();
    t2.join();
  }

  // This result will be precisely 200000!
  std::cout << "Afterwards the value of m_count, with locking, is: " << a.m_count << std::endl;

  // Can you understand why?
}
<commit_msg>Increase loop count.<commit_after>#include <iostream>
#include <thread>
#include <mutex>

// Suppose we have a class:
struct A {
  // That has a variable,
  int m_count;
  // that is accessed simulateously by two threads.
  // Then we need to protect that variable using a mutex, say this one:
  std::mutex m_count_mutex;
  // Because, when we don't use locking, then things go wrong.
};

// For convenience, lets instantiate an object of type A globally,
// even though that is normally evil.
A a;

// Consider this thread that accesses m_count without locking!
void thr_no_lock()
{
  // Loop 100000 times, each loop incrementing m_count by one.
  for (int i = 0; i < 1000000; ++i)
  {
    // Read m_count.
    int read = a.m_count;
    // Add 1 and write it back.
    a.m_count = read + 1;
  }
  // If the reading and writing was atomic then
  // this loop will have added precisely 100000.
}

// Also have a thread that does the same but with locking:
void thr_with_lock()
{
  for (int i = 0; i < 1000000; ++i)
  {
    std::unique_lock<std::mutex> lk(a.m_count_mutex);
    int read = a.m_count;
    a.m_count = read + 1;
  }
}

int main()
{
  // Do the test without locking first.
  a.m_count = 0;
  {
    std::thread t1(thr_no_lock);
    std::thread t2(thr_with_lock);

    // Wait for t1 and t2 to be finished.
    t1.join();
    t2.join();
  }

  // This result will be LESS THAN 200000!
  std::cout << "Afterwards the value of m_count, without locking, is: " << a.m_count << std::endl;

  // And again, but now both threads use locking.
  a.m_count = 0;
  {
    std::thread t1(thr_with_lock);
    std::thread t2(thr_with_lock);

    t1.join();
    t2.join();
  }

  // This result will be precisely 200000!
  std::cout << "Afterwards the value of m_count, with locking, is: " << a.m_count << std::endl;

  // Can you understand why?
}
<|endoftext|>


<commit_before>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

/**
 * Example 12: Physics Based Preconditioning
 * This example shows how to enable the use of more advanced preconditioning
 * with the optional Kernel::computeQpOffDiagJacobian method and input PBP block
 */

//Moose Includes
#include "MooseInit.h"
#include "Moose.h"
#include "MooseApp.h"

PerfLog Moose::perf_log("Example12: Physics Based Preconditioning");

int main (int argc, char** argv)
{
  MooseInit init (argc, argv);

  MooseApp app(argc, argv);
  app.run();

  return 0;
}
<commit_msg>Examples use ExampleApp now, not MooseApp!<commit_after>/****************************************************************/
/*               DO NOT MODIFY THIS HEADER                      */
/* MOOSE - Multiphysics Object Oriented Simulation Environment  */
/*                                                              */
/*           (c) 2010 Battelle Energy Alliance, LLC             */
/*                   ALL RIGHTS RESERVED                        */
/*                                                              */
/*          Prepared by Battelle Energy Alliance, LLC           */
/*            Under Contract No. DE-AC07-05ID14517              */
/*            With the U. S. Department of Energy               */
/*                                                              */
/*            See COPYRIGHT for full restrictions               */
/****************************************************************/

/**
 * Example 12: Physics Based Preconditioning
 * This example shows how to enable the use of more advanced preconditioning
 * with the optional Kernel::computeQpOffDiagJacobian method and input PBP block
 */

//Moose Includes
#include "MooseInit.h"
#include "Moose.h"
#include "ExampleApp.h"

PerfLog Moose::perf_log("Example12: Physics Based Preconditioning");

int main (int argc, char** argv)
{
  MooseInit init (argc, argv);

  ExampleApp app(argc, argv);
  app.run();

  return 0;
}
<|endoftext|>


<commit_before>/***************************************************************************
 *
 * Project: libLAS -- C/C++ read/write library for LAS LIDAR data
 * Purpose: LAS translation with optional configuration
 * Author:  Howard Butler, hobu.inc at gmail.com
 ***************************************************************************
 * Copyright (c) 2010, Howard Butler, hobu.inc at gmail.com
 *
 * See LICENSE.txt in this source distribution for more information.
 **************************************************************************/

#include <iostream>

#include <pdal/exceptions.hpp>
//#include <pdal/pdal_config.hpp>
//#include <pdal/Bounds.hpp>
//#include <pdal/Color.hpp>
//#include <pdal/Dimension.hpp>
//#include <pdal/Schema.hpp>
#include <pdal/filters/Chipper.hpp>

#include <pdal/filters/ReprojectionFilter.hpp>
#include <pdal/filters/ScalingFilter.hpp>

//#include <pdal/ColorFilter.hpp>
//#include <pdal/MosaicFilter.hpp>
//#include <pdal/FauxReader.hpp>
//#include <pdal/FauxWriter.hpp>
#include <pdal/drivers/las/Reader.hpp>
//#include <pdal/LasHeader.hpp>
#include <pdal/drivers/las/Writer.hpp>
#include <pdal/filters/CacheFilter.hpp>
#include <pdal/filters/ByteSwapFilter.hpp>

#include <pdal/drivers/liblas/Writer.hpp>
#include <pdal/drivers/liblas/Reader.hpp>

#ifdef PDAL_HAVE_ORACLE
#include <pdal/drivers/oci/Writer.hpp>
#include <pdal/drivers/oci/Reader.hpp>
#endif

#include <boost/property_tree/xml_parser.hpp>

#include "Application.hpp"

using namespace pdal;
namespace po = boost::program_options;

class Application_pc2pc : public Application
{
public:
    Application_pc2pc(int argc, char* argv[]);
    int execute();

private:
    void addOptions();
    bool validateOptions();

    std::string m_inputFile;
    std::string m_outputFile;
    std::string m_xml;
    std::string m_srs;
    bool m_bCompress;

};

Application_pc2pc::Application_pc2pc(int argc, char* argv[])
    : Application(argc, argv, "pc2pc")
{
}

bool Application_pc2pc::validateOptions()
{
    if (!hasOption("input"))
    {
        usageError("--input/-i required");
        return false;
    }

    if (!hasOption("output"))
    {
        usageError("--output/-o required");
        return false;
    }

    return true;
}

void Application_pc2pc::addOptions()
{
    po::options_description* file_options = new po::options_description("file options");

    file_options->add_options()
        ("input,i", po::value<std::string>(&m_inputFile), "input file name")
        ("output,o", po::value<std::string>(&m_outputFile), "output file name")
        ("native", "use native LAS classes (not liblas)")
        ("oracle-writer", "Read data from LAS file and write to Oracle")
        ("oracle-reader", "Read data from Oracle and write to LAS")
        ("a_srs", po::value<std::string>(&m_srs)->default_value(""), "Assign output coordinate system")
        ("compress", po::value<bool>(&m_bCompress)->zero_tokens()->implicit_value(true),"Compress output data if available")
        ("xml", po::value<std::string>(&m_xml)->default_value("log.xml"), "XML file to load process (OCI only right now)")
        ;

    addOptionSet(file_options);
}

int Application_pc2pc::execute()
{
    if (!Utils::fileExists(m_inputFile))
    {
        runtimeError("file not found: " + m_inputFile);
        return 1;
    }

    std::ostream* ofs = Utils::createFile(m_outputFile);

    if (hasOption("native"))
    {
        pdal::drivers::las::LasReader reader(m_inputFile);

        const boost::uint64_t numPoints = reader.getNumPoints();

        pdal::drivers::las::LasWriter writer(reader, ofs);

        //BUG: handle laz writer.setCompressed(false);

        //writer.setPointFormat( reader.getPointFormatNumber() );

        writer.initialize();

        writer.write(numPoints);
    }

    else if (hasOption("oracle-writer"))
    {
#ifdef PDAL_HAVE_ORACLE
        try{
        pdal::drivers::las::LasReader reader(m_inputFile);
        reader.initialize();

        const boost::uint64_t numPoints = reader.getNumPoints();

        boost::property_tree::ptree load_tree;

        boost::property_tree::read_xml(m_xml, load_tree);

        boost::property_tree::ptree oracle_options = load_tree.get_child("pdal.drivers.oci.writer");
        boost::property_tree::ptree las_options = load_tree.get_child("pdal.drivers.las");

        pdal::OptionsOld options(oracle_options);

        boost::property_tree::ptree in_srs_options = las_options.get_child("spatialreference");
        std::string in_wkt = in_srs_options.get<std::string>("userinput");
        boost::property_tree::ptree out_srs_options = oracle_options.get_child("spatialreference");
        std::string out_wkt = out_srs_options.get<std::string>("userinput");

        pdal::SpatialReference in_ref(in_wkt);
        pdal::SpatialReference out_ref(out_wkt);

        boost::property_tree::ptree& tree = options.GetPTree();

        boost::uint32_t capacity = tree.get<boost::uint32_t>("capacity");
        double scalex = oracle_options.get<double>("scale.x");
        double scaley = oracle_options.get<double>("scale.y");
        double scalez = oracle_options.get<double>("scale.z");

        double offsetx = oracle_options.get<double>("offset.x");
        double offsety = oracle_options.get<double>("offset.y");
        double offsetz = oracle_options.get<double>("offset.z");

        pdal::filters::CacheFilter cache(reader, 1, capacity);
        pdal::filters::Chipper chipper(cache, capacity);
        pdal::filters::ScalingFilter scalingFilter(chipper);
        pdal::filters::ReprojectionFilter reprojectionFilter(scalingFilter, in_ref, out_ref);
        pdal::filters::DescalingFilter descalingFilter(reprojectionFilter,
                                                       scalex, offsetx,
                                                       scaley, offsety,
                                                       scalez, offsetz);

        // pdal::filters::ByteSwapFilter swapper(descalingFilter);
        pdal::drivers::oci::Writer writer(descalingFilter, options);

        writer.initialize();

        writer.write(numPoints);

        boost::property_tree::ptree output_tree;
        // output_tree.put_child(writer.getName(), options.GetPTree());
        // boost::property_tree::write_xml(m_xml, output_tree);

        } catch (pdal::pdal_error& e)
        {
            std::cerr << "Error writing oracle: " << e.what() << std::endl;

        }
#else
        throw configuration_error("PDAL not compiled with Oracle support");
#endif
    }
        else if (hasOption("oracle-reader"))
        {
    #ifdef PDAL_HAVE_ORACLE
        try{
        boost::property_tree::ptree load_tree;

        boost::property_tree::read_xml(m_xml, load_tree);

        boost::property_tree::ptree oracle_options = load_tree.get_child("pdal.drivers.oci.reader");

        boost::property_tree::ptree las_options = load_tree.get_child("pdal.drivers.las");
        boost::property_tree::ptree srs_options = las_options.get_child("spatialreference");

        double scalex = las_options.get<double>("scale.x");
        double scaley = las_options.get<double>("scale.y");
        double scalez = las_options.get<double>("scale.z");

        double offsetx = las_options.get<double>("offset.x");
        double offsety = las_options.get<double>("offset.y");
        double offsetz = las_options.get<double>("offset.z");

        bool compress = las_options.get<bool>("compress");

        std::string out_wkt = srs_options.get<std::string>("userinput");
        pdal::OptionsOld options(oracle_options);

        pdal::drivers::oci::Reader reader(options);
        reader.initialize();

        pdal::drivers::las::LasWriter* writer;

        pdal::SpatialReference out_ref(out_wkt);
        pdal::SpatialReference in_ref(reader.getSpatialReference());
        if (!(in_ref == out_ref))
        {
            // pdal::filters::ByteSwapFilter swapper(reader);
            pdal::filters::ScalingFilter scalingFilter(reader);
            pdal::filters::ReprojectionFilter reprojectionFilter(scalingFilter, in_ref, out_ref);
            pdal::filters::DescalingFilter descalingFilter(reprojectionFilter,
                                                           scalex, offsetx,
                                                           scaley, offsety,
                                                           scalez, offsetz);

            writer = new pdal::drivers::las::LasWriter(descalingFilter, ofs);
            if (compress)
                writer->setCompressed(true);
            writer->setChunkSize(oracle_options.get<boost::uint32_t>("capacity"));
            writer->setPointFormat(pdal::drivers::las::PointFormat3);

            writer->initialize();

            writer->write(0);
            delete writer;
        }
        else
        {
            writer = new pdal::drivers::las::LasWriter(reader, ofs);
            if (compress)
                writer->setCompressed(true);
            writer->setChunkSize(oracle_options.get<boost::uint32_t>("capacity"));
            writer->setPointFormat(pdal::drivers::las::PointFormat3);

            writer->initialize();

            writer->write(0);
            delete writer;
        }

        } catch (pdal::pdal_error& e)
        {
            std::cerr << "Error reading oracle: " << e.what() << std::endl;
            return 1;

        }

    #else
            throw configuration_error("PDAL not compiled with Oracle support");
    #endif
        }

    else
    {
        pdal::drivers::liblas::LiblasReader reader(m_inputFile);

        const boost::uint64_t numPoints = reader.getNumPoints();

        pdal::drivers::liblas::LiblasWriter writer(reader, ofs);

        //BUG: handle laz writer.setCompressed(false);

        writer.setPointFormat( reader.getPointFormat() );

        writer.initialize();

        writer.write(numPoints);
    }

    Utils::closeFile(ofs);

    return 0;
}

int main(int argc, char* argv[])
{
    Application_pc2pc app(argc, argv);
    return app.run();
}

<commit_msg>remove reader.initialize(), we shouldn't do that<commit_after>/***************************************************************************
 *
 * Project: libLAS -- C/C++ read/write library for LAS LIDAR data
 * Purpose: LAS translation with optional configuration
 * Author:  Howard Butler, hobu.inc at gmail.com
 ***************************************************************************
 * Copyright (c) 2010, Howard Butler, hobu.inc at gmail.com
 *
 * See LICENSE.txt in this source distribution for more information.
 **************************************************************************/

#include <iostream>

#include <pdal/exceptions.hpp>
//#include <pdal/pdal_config.hpp>
//#include <pdal/Bounds.hpp>
//#include <pdal/Color.hpp>
//#include <pdal/Dimension.hpp>
//#include <pdal/Schema.hpp>
#include <pdal/filters/Chipper.hpp>

#include <pdal/filters/ReprojectionFilter.hpp>
#include <pdal/filters/ScalingFilter.hpp>

//#include <pdal/ColorFilter.hpp>
//#include <pdal/MosaicFilter.hpp>
//#include <pdal/FauxReader.hpp>
//#include <pdal/FauxWriter.hpp>
#include <pdal/drivers/las/Reader.hpp>
//#include <pdal/LasHeader.hpp>
#include <pdal/drivers/las/Writer.hpp>
#include <pdal/filters/CacheFilter.hpp>
#include <pdal/filters/ByteSwapFilter.hpp>

#include <pdal/drivers/liblas/Writer.hpp>
#include <pdal/drivers/liblas/Reader.hpp>

#ifdef PDAL_HAVE_ORACLE
#include <pdal/drivers/oci/Writer.hpp>
#include <pdal/drivers/oci/Reader.hpp>
#endif

#include <boost/property_tree/xml_parser.hpp>

#include "Application.hpp"

using namespace pdal;
namespace po = boost::program_options;

class Application_pc2pc : public Application
{
public:
    Application_pc2pc(int argc, char* argv[]);
    int execute();

private:
    void addOptions();
    bool validateOptions();

    std::string m_inputFile;
    std::string m_outputFile;
    std::string m_xml;
    std::string m_srs;
    bool m_bCompress;

};

Application_pc2pc::Application_pc2pc(int argc, char* argv[])
    : Application(argc, argv, "pc2pc")
{
}

bool Application_pc2pc::validateOptions()
{
    if (!hasOption("input"))
    {
        usageError("--input/-i required");
        return false;
    }

    if (!hasOption("output"))
    {
        usageError("--output/-o required");
        return false;
    }

    return true;
}

void Application_pc2pc::addOptions()
{
    po::options_description* file_options = new po::options_description("file options");

    file_options->add_options()
        ("input,i", po::value<std::string>(&m_inputFile), "input file name")
        ("output,o", po::value<std::string>(&m_outputFile), "output file name")
        ("native", "use native LAS classes (not liblas)")
        ("oracle-writer", "Read data from LAS file and write to Oracle")
        ("oracle-reader", "Read data from Oracle and write to LAS")
        ("a_srs", po::value<std::string>(&m_srs)->default_value(""), "Assign output coordinate system")
        ("compress", po::value<bool>(&m_bCompress)->zero_tokens()->implicit_value(true),"Compress output data if available")
        ("xml", po::value<std::string>(&m_xml)->default_value("log.xml"), "XML file to load process (OCI only right now)")
        ;

    addOptionSet(file_options);
}

int Application_pc2pc::execute()
{
    if (!Utils::fileExists(m_inputFile))
    {
        runtimeError("file not found: " + m_inputFile);
        return 1;
    }

    std::ostream* ofs = Utils::createFile(m_outputFile);

    if (hasOption("native"))
    {
        pdal::drivers::las::LasReader reader(m_inputFile);

        const boost::uint64_t numPoints = reader.getNumPoints();

        pdal::drivers::las::LasWriter writer(reader, ofs);

        //BUG: handle laz writer.setCompressed(false);

        //writer.setPointFormat( reader.getPointFormatNumber() );

        writer.initialize();

        writer.write(numPoints);
    }

    else if (hasOption("oracle-writer"))
    {
#ifdef PDAL_HAVE_ORACLE
        try{
        pdal::drivers::las::LasReader reader(m_inputFile);

        const boost::uint64_t numPoints = reader.getNumPoints();

        boost::property_tree::ptree load_tree;

        boost::property_tree::read_xml(m_xml, load_tree);

        boost::property_tree::ptree oracle_options = load_tree.get_child("pdal.drivers.oci.writer");
        boost::property_tree::ptree las_options = load_tree.get_child("pdal.drivers.las");

        pdal::OptionsOld options(oracle_options);

        boost::property_tree::ptree in_srs_options = las_options.get_child("spatialreference");
        std::string in_wkt = in_srs_options.get<std::string>("userinput");
        boost::property_tree::ptree out_srs_options = oracle_options.get_child("spatialreference");
        std::string out_wkt = out_srs_options.get<std::string>("userinput");

        pdal::SpatialReference in_ref(in_wkt);
        pdal::SpatialReference out_ref(out_wkt);

        boost::property_tree::ptree& tree = options.GetPTree();

        boost::uint32_t capacity = tree.get<boost::uint32_t>("capacity");
        double scalex = oracle_options.get<double>("scale.x");
        double scaley = oracle_options.get<double>("scale.y");
        double scalez = oracle_options.get<double>("scale.z");

        double offsetx = oracle_options.get<double>("offset.x");
        double offsety = oracle_options.get<double>("offset.y");
        double offsetz = oracle_options.get<double>("offset.z");

        pdal::filters::CacheFilter cache(reader, 1, capacity);
        pdal::filters::Chipper chipper(cache, capacity);
        pdal::filters::ScalingFilter scalingFilter(chipper);
        pdal::filters::ReprojectionFilter reprojectionFilter(scalingFilter, in_ref, out_ref);
        pdal::filters::DescalingFilter descalingFilter(reprojectionFilter,
                                                       scalex, offsetx,
                                                       scaley, offsety,
                                                       scalez, offsetz);

        // pdal::filters::ByteSwapFilter swapper(descalingFilter);
        pdal::drivers::oci::Writer writer(descalingFilter, options);

        writer.initialize();

        writer.write(numPoints);

        boost::property_tree::ptree output_tree;
        // output_tree.put_child(writer.getName(), options.GetPTree());
        // boost::property_tree::write_xml(m_xml, output_tree);

        } catch (pdal::pdal_error& e)
        {
            std::cerr << "Error writing oracle: " << e.what() << std::endl;

        }
#else
        throw configuration_error("PDAL not compiled with Oracle support");
#endif
    }
        else if (hasOption("oracle-reader"))
        {
    #ifdef PDAL_HAVE_ORACLE
        try{
        boost::property_tree::ptree load_tree;

        boost::property_tree::read_xml(m_xml, load_tree);

        boost::property_tree::ptree oracle_options = load_tree.get_child("pdal.drivers.oci.reader");

        boost::property_tree::ptree las_options = load_tree.get_child("pdal.drivers.las");
        boost::property_tree::ptree srs_options = las_options.get_child("spatialreference");

        double scalex = las_options.get<double>("scale.x");
        double scaley = las_options.get<double>("scale.y");
        double scalez = las_options.get<double>("scale.z");

        double offsetx = las_options.get<double>("offset.x");
        double offsety = las_options.get<double>("offset.y");
        double offsetz = las_options.get<double>("offset.z");

        bool compress = las_options.get<bool>("compress");

        std::string out_wkt = srs_options.get<std::string>("userinput");
        pdal::OptionsOld options(oracle_options);

        pdal::drivers::oci::Reader reader(options);

        pdal::drivers::las::LasWriter* writer;

        pdal::SpatialReference out_ref(out_wkt);
        pdal::SpatialReference in_ref(reader.getSpatialReference());
        if (!(in_ref == out_ref))
        {
            // pdal::filters::ByteSwapFilter swapper(reader);
            pdal::filters::ScalingFilter scalingFilter(reader);
            pdal::filters::ReprojectionFilter reprojectionFilter(scalingFilter, in_ref, out_ref);
            pdal::filters::DescalingFilter descalingFilter(reprojectionFilter,
                                                           scalex, offsetx,
                                                           scaley, offsety,
                                                           scalez, offsetz);

            writer = new pdal::drivers::las::LasWriter(descalingFilter, ofs);
            if (compress)
                writer->setCompressed(true);
            writer->setChunkSize(oracle_options.get<boost::uint32_t>("capacity"));
            writer->setPointFormat(pdal::drivers::las::PointFormat3);

            writer->initialize();

            writer->write(0);
            delete writer;
        }
        else
        {
            writer = new pdal::drivers::las::LasWriter(reader, ofs);
            if (compress)
                writer->setCompressed(true);
            writer->setChunkSize(oracle_options.get<boost::uint32_t>("capacity"));
            writer->setPointFormat(pdal::drivers::las::PointFormat3);

            writer->initialize();

            writer->write(0);
            delete writer;
        }

        } catch (pdal::pdal_error& e)
        {
            std::cerr << "Error reading oracle: " << e.what() << std::endl;
            return 1;

        }

    #else
            throw configuration_error("PDAL not compiled with Oracle support");
    #endif
        }

    else
    {
        pdal::drivers::liblas::LiblasReader reader(m_inputFile);

        const boost::uint64_t numPoints = reader.getNumPoints();

        pdal::drivers::liblas::LiblasWriter writer(reader, ofs);

        //BUG: handle laz writer.setCompressed(false);

        writer.setPointFormat( reader.getPointFormat() );

        writer.initialize();

        writer.write(numPoints);
    }

    Utils::closeFile(ofs);

    return 0;
}

int main(int argc, char* argv[])
{
    Application_pc2pc app(argc, argv);
    return app.run();
}

<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2015, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 */

#include <fatal/lesson/driver.h>

namespace lesson {

/**
 * @author: Marcelo Juchem <marcelo@fb.com>
 */
LESSON(
  "representing values, part 1/4",
  "This lesson gives an overview on how values are represented. Subsequent "
  "tutorials will elaborate on proper ways of achieving such representation."
  "\n\n"
  "The goal, for now, is to come up with the intuition behind it without "
  "drowing in syntax and correctness.",

  template <int Value>
  struct int_constant {
    static int value;
  };

  template <int Value>
  int int_constant<Value>::value = Value;
) {
  COMMENT(
    "A previous lesson mentioned that values can be emulated using types to "
    "represent them. Here's an overview on the intuition of how this can be "
    "achieved."
  );

  CODE(
    using x = int_constant<15>;
  );

  PRINT("x = ", type_str<x>());
  PRINT("x::value = ", x::value);

  COMMENT(
    "Note, however, that `int_constant::value` is a regular runtime variable "
    "as opposed to a compile time constant. It is possible, for instance, to "
    "change the value associated with it:"
  );

  CODE(
    x::value = 30;
  );

  PRINT("x::value = ", x::value);

  COMMENT(
    "This makes it illegal to use such variable as an argument to a template. "
    "Template parameters must be immutable and available at compile time. This "
    "includes, for instance, type and integer constants."
  );

  ILLEGAL(
    "`int_constant::value` is not a constant",
    using y = int_constant<x::value>;
  );
}

/**
 * @author: Marcelo Juchem <marcelo@fb.com>
 */
LESSON(
  "representing values, part 2/4",
  "This lesson demonstrates proper ways to represent values that can be used "
  "at compile time."
  "\n\n"
  "Let's modify the `int_constant` template to properly represent compile time "
  "constants.",

  template <int Value>
  struct int_constant_proper {
    static constexpr int const value = Value;
  };

  template <int Value>
  constexpr int const int_constant_proper<Value>::value;
) {
  COMMENT(
    "C++11 introduced the `constexpr` keyword which roughly allows us to tell "
    "the compiler that a given variable holds the result of a constant "
    "expression."
    "\n\n"
    "Once we have such guarantee, the compiler can evaluate the contents of "
    "such variable at compile time, effectivelly making it a compile time "
    "constant."
  );

  CODE(
    using x = int_constant_proper<15>;
  );

  PRINT("x = ", type_str<x>());
  PRINT("x::value = ", x::value);

  COMMENT(
    "As noted before, constants can be used as template parameters."
  );

  CODE(
    using y = int_constant_proper<x::value>;
  );

  PRINT("y = ", type_str<y>());
  PRINT("y::value = ", y::value);

  COMMENT(
    "In fact, any expression that can be evaluated at compile time can be used "
    "as a compile time constant:"
  );

  CODE(
    using z = int_constant_proper<x::value * 2>;
  );

  PRINT("z = ", type_str<z>());
  PRINT("z::value = ", z::value);

  CODE(
    using w = int_constant_proper<x::value + z::value - 3>;
  );

  PRINT("w = ", type_str<w>());
  PRINT("w::value = ", w::value);
}

/**
 * @author: Marcelo Juchem <marcelo@fb.com>
 */
LESSON(
  "representing values, part 3/4",
  "This lesson gives an overview on the implementation of "
  "`std::integral_constant`."
  "\n\n"
  "So far we've been limited to `int` constants. One could be interested in "
  "employing other types for a constant, like `char` or `unsigned long`."
  "\n\n"
  "Let's modify the `int_constant_proper` template to represent arbitrary "
  "integral types.",

  template <typename T, T Value>
  struct constant {
    static constexpr T const value = Value;
  };

  template <typename T, T Value>
  constexpr T const constant<T, Value>::value;
) {
  COMMENT(
    "Now we can specify the type of the constant, as well as its value."
  );
  using x = constant<int, -15>;

  PRINT("x = ", type_str<x>());
  PRINT("x::value = ", x::value);

  using y = constant<bool, true>;

  PRINT("y = ", type_str<y>());
  PRINT("y::value = ", std::boolalpha, y::value);

  COMMENT(
    "Again, any expression that can be evaluated at compile time will do:"
  );

  using z = constant<unsigned, (x::value > 0) ? x::value : -x::value>;

  PRINT("z = ", type_str<z>());
  PRINT("z::value = ", z::value);
}

/**
 * @author: Marcelo Juchem <marcelo@fb.com>
 */
LESSON(
  "representing values, part 4/4",
  "This lesson gives an overview of some basic features that "
  "`std::integral_constant` offers."
  "\n\n"
  "The implementation and library features built around "
  "`std::integral_constant` are a bit more involved than what we've seen so "
  "far, but for the purposes of a lesson, we don't need to dig too deep."
  "\n\n"
  "For now, let's look at a few more things that `std::integral_constant` "
  "offers."
) {
  COMMENT(
    "We already covered how to represent a compile time constant with a type, "
    "and how to access the constant's value."
  );
  using x = std::integral_constant<int, -15>;

  PRINT("x = ", type_str<x>());
  PRINT("x::value = ", x::value);

  COMMENT(
    "For convenience purposes, `std::integral_constant` also provides an "
    "identity alias in the form of a member called `type`:"
  );
  PRINT("x::type = ", type_str<x::type>());

  COMMENT(
    "It also exposes the type of the constant it represents:"
  );
  PRINT("x::value_type = ", type_str<x::value_type>());

  COMMENT(
    "Shortcuts to boolean constants are also provided:"
  );

  using t = std::true_type;
  PRINT("t = ", type_str<t>());
  PRINT("t::value = ", std::boolalpha, t::value);
  PRINT("t::value_type = ", type_str<t::value_type>());

  using f = std::false_type;
  PRINT("f = ", type_str<f>());
  PRINT("f::value = ", std::boolalpha, f::value);
  PRINT("f::value_type = ", type_str<f::value_type>());
}

/**
 * @author: Marcelo Juchem <marcelo@fb.com>
 */
LESSON(
  "convenience aliases",
  "This lesson gives an overview on how to reduce verbosity through the use of "
  "convenience aliases."
  "\n\n"
  "Some types will be extensively used throughout the examples in this lesson. "
  "For instance, `std::integral_constant` for `int` values."
  "\n\n"
  "For this reason, let's see how we can shorten the code we write when "
  "declaring an integral constant through the use of aliases.",

  template <int Value>
  using int_value = std::integral_constant<int, Value>;
) {
  COMMENT(
    "Let's start by going the verbose route and fully specifying `x` as an "
    "`std::integral_constant`."
  );

  using x = std::integral_constant<int, 10>;

  PRINT("x = ", type_str<x>());
  PRINT("x::value = ", x::value);

  COMMENT(
    "Now let's use the convenient alias `int_value` to declare the same thing."
  );

  using y = int_value<10>;

  PRINT("y = ", type_str<y>());
  PRINT("y::value = ", y::value);

  COMMENT(
    "The beauty of aliases is that they don't create new types. Instead, "
    "they're just shortcuts to existing types. For instance, by checking the "
    "output of this lesson, it's easy to see that both `x` and `y` reference "
    "exactly the same type: `std::integral_constant<int, 10>`."
    "\n\n"
    "The code below will be further explained in a later lesson. For now, it "
    "suffices to know that it will prevent the program from compiling "
    "correctly if both `x` and `y` do not represent the same type."
    "\n\n"
    "This means that, if the line below doesn't result in a compilation error, "
    "then both `x` and `y` are guaranteed to reference the same type."
  );

  static_assert(std::is_same<x, y>::value, "type mismatch");
}

} // namespace lesson {
<commit_msg>- wrapping code blocks in CODE() for lesson 1.1<commit_after>/*
 *  Copyright (c) 2015, Facebook, Inc.
 *  All rights reserved.
 *
 *  This source code is licensed under the BSD-style license found in the
 *  LICENSE file in the root directory of this source tree. An additional grant
 *  of patent rights can be found in the PATENTS file in the same directory.
 */

#include <fatal/lesson/driver.h>

namespace lesson {

/**
 * @author: Marcelo Juchem <marcelo@fb.com>
 */
LESSON(
  "representing values, part 1/4",
  "This lesson gives an overview on how values are represented. Subsequent "
  "tutorials will elaborate on proper ways of achieving such representation."
  "\n\n"
  "The goal, for now, is to come up with the intuition behind it without "
  "drowing in syntax and correctness.",

  template <int Value>
  struct int_constant {
    static int value;
  };

  template <int Value>
  int int_constant<Value>::value = Value;
) {
  COMMENT(
    "A previous lesson mentioned that values can be emulated using types to "
    "represent them. Here's an overview on the intuition of how this can be "
    "achieved."
  );

  CODE(
    using x = int_constant<15>;
  );

  PRINT("x = ", type_str<x>());
  PRINT("x::value = ", x::value);

  COMMENT(
    "Note, however, that `int_constant::value` is a regular runtime variable "
    "as opposed to a compile time constant. It is possible, for instance, to "
    "change the value associated with it:"
  );

  CODE(
    x::value = 30;
  );

  PRINT("x::value = ", x::value);

  COMMENT(
    "This makes it illegal to use such variable as an argument to a template. "
    "Template parameters must be immutable and available at compile time. This "
    "includes, for instance, type and integer constants."
  );

  ILLEGAL(
    "`int_constant::value` is not a constant",
    using y = int_constant<x::value>;
  );
}

/**
 * @author: Marcelo Juchem <marcelo@fb.com>
 */
LESSON(
  "representing values, part 2/4",
  "This lesson demonstrates proper ways to represent values that can be used "
  "at compile time."
  "\n\n"
  "Let's modify the `int_constant` template to properly represent compile time "
  "constants.",

  template <int Value>
  struct int_constant_proper {
    static constexpr int const value = Value;
  };

  template <int Value>
  constexpr int const int_constant_proper<Value>::value;
) {
  COMMENT(
    "C++11 introduced the `constexpr` keyword which roughly allows us to tell "
    "the compiler that a given variable holds the result of a constant "
    "expression."
    "\n\n"
    "Once we have such guarantee, the compiler can evaluate the contents of "
    "such variable at compile time, effectivelly making it a compile time "
    "constant."
  );

  CODE(
    using x = int_constant_proper<15>;
  );

  PRINT("x = ", type_str<x>());
  PRINT("x::value = ", x::value);

  COMMENT(
    "As noted before, constants can be used as template parameters."
  );

  CODE(
    using y = int_constant_proper<x::value>;
  );

  PRINT("y = ", type_str<y>());
  PRINT("y::value = ", y::value);

  COMMENT(
    "In fact, any expression that can be evaluated at compile time can be used "
    "as a compile time constant:"
  );

  CODE(
    using z = int_constant_proper<x::value * 2>;
  );

  PRINT("z = ", type_str<z>());
  PRINT("z::value = ", z::value);

  CODE(
    using w = int_constant_proper<x::value + z::value - 3>;
  );

  PRINT("w = ", type_str<w>());
  PRINT("w::value = ", w::value);
}

/**
 * @author: Marcelo Juchem <marcelo@fb.com>
 */
LESSON(
  "representing values, part 3/4",
  "This lesson gives an overview on the implementation of "
  "`std::integral_constant`."
  "\n\n"
  "So far we've been limited to `int` constants. One could be interested in "
  "employing other types for a constant, like `char` or `unsigned long`."
  "\n\n"
  "Let's modify the `int_constant_proper` template to represent arbitrary "
  "integral types.",

  template <typename T, T Value>
  struct constant {
    static constexpr T const value = Value;
  };

  template <typename T, T Value>
  constexpr T const constant<T, Value>::value;
) {
  COMMENT(
    "Now we can specify the type of the constant, as well as its value."
  );
  CODE(
    using x = constant<int, -15>;
  );

  PRINT("x = ", type_str<x>());
  PRINT("x::value = ", x::value);

  CODE(
    using y = constant<bool, true>;
  );

  PRINT("y = ", type_str<y>());
  PRINT("y::value = ", std::boolalpha, y::value);

  COMMENT(
    "Again, any expression that can be evaluated at compile time will do:"
  );

  CODE(
    using z = constant<unsigned, (x::value > 0) ? x::value : -x::value>;
  );

  PRINT("z = ", type_str<z>());
  PRINT("z::value = ", z::value);
}

/**
 * @author: Marcelo Juchem <marcelo@fb.com>
 */
LESSON(
  "representing values, part 4/4",
  "This lesson gives an overview of some basic features that "
  "`std::integral_constant` offers."
  "\n\n"
  "The implementation and library features built around "
  "`std::integral_constant` are a bit more involved than what we've seen so "
  "far, but for the purposes of a lesson, we don't need to dig too deep."
  "\n\n"
  "For now, let's look at a few more things that `std::integral_constant` "
  "offers."
) {
  COMMENT(
    "We already covered how to represent a compile time constant with a type, "
    "and how to access the constant's value."
  );
  CODE(
    using x = std::integral_constant<int, -15>;
  );

  PRINT("x = ", type_str<x>());
  PRINT("x::value = ", x::value);

  COMMENT(
    "For convenience purposes, `std::integral_constant` also provides an "
    "identity alias in the form of a member called `type`:"
  );
  PRINT("x::type = ", type_str<x::type>());

  COMMENT(
    "It also exposes the type of the constant it represents:"
  );
  PRINT("x::value_type = ", type_str<x::value_type>());

  COMMENT(
    "Shortcuts to boolean constants are also provided:"
  );

  CODE(
    using t = std::true_type;
  );
  PRINT("t = ", type_str<t>());
  PRINT("t::value = ", std::boolalpha, t::value);
  PRINT("t::value_type = ", type_str<t::value_type>());

  CODE(
    using f = std::false_type;
  );
  PRINT("f = ", type_str<f>());
  PRINT("f::value = ", std::boolalpha, f::value);
  PRINT("f::value_type = ", type_str<f::value_type>());
}

/**
 * @author: Marcelo Juchem <marcelo@fb.com>
 */
LESSON(
  "convenience aliases",
  "This lesson gives an overview on how to reduce verbosity through the use of "
  "convenience aliases."
  "\n\n"
  "Some types will be extensively used throughout the examples in this lesson. "
  "For instance, `std::integral_constant` for `int` values."
  "\n\n"
  "For this reason, let's see how we can shorten the code we write when "
  "declaring an integral constant through the use of aliases.",

  template <int Value>
  using int_value = std::integral_constant<int, Value>;
) {
  COMMENT(
    "Let's start by going the verbose route and fully specifying `x` as an "
    "`std::integral_constant`."
  );

  CODE(
    using x = std::integral_constant<int, 10>;
  );

  PRINT("x = ", type_str<x>());
  PRINT("x::value = ", x::value);

  COMMENT(
    "Now let's use the convenient alias `int_value` to declare the same thing."
  );

  CODE(
    using y = int_value<10>;
  );

  PRINT("y = ", type_str<y>());
  PRINT("y::value = ", y::value);

  COMMENT(
    "The beauty of aliases is that they don't create new types. Instead, "
    "they're just shortcuts to existing types. For instance, by checking the "
    "output of this lesson, it's easy to see that both `x` and `y` reference "
    "exactly the same type: `std::integral_constant<int, 10>`."
    "\n\n"
    "The code below will be further explained in a later lesson. For now, it "
    "suffices to know that it will prevent the program from compiling "
    "correctly if both `x` and `y` do not represent the same type."
    "\n\n"
    "This means that, if the line below doesn't result in a compilation error, "
    "then both `x` and `y` are guaranteed to reference the same type."
  );

  CODE(
    static_assert(std::is_same<x, y>::value, "type mismatch");
  );
}

} // namespace lesson {
<|endoftext|>


<commit_before>#include "bamliquidator.h"

#include <cmath>
#include <fstream>
#include <future>
#include <iostream>
#include <map>
#include <stdexcept>
#include <sstream>

#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>

#include <hdf5.h>
#include <hdf5_hl.h>

struct CountH5Record
{
  uint32_t bin_number;
  char cell_type[16];
  char chromosome[16];
  uint64_t count;
  char file_name[64];
};

std::vector<CountH5Record> count(const std::string chr,
                                 const std::string cell_type,
                                 const unsigned int bin_size,
                                 const size_t length,
                                 const std::string bam_file)
{
  const std::string bam_file_name = file_name_from_path(bam_file);

  int bins = std::ceil(length / (double) bin_size);
  int max_base_pair = bins * bin_size;

  const std::vector<double> bin_counts = liquidate(bam_file, chr, 0, max_base_pair, '.', bins, 0);

  CountH5Record record;
  record.bin_number = 0;
  strncpy(record.cell_type,  cell_type.c_str(),     sizeof(CountH5Record::cell_type));
  strncpy(record.chromosome, chr.c_str(),           sizeof(CountH5Record::chromosome));
  strncpy(record.file_name,  bam_file_name.c_str(), sizeof(CountH5Record::file_name));

  std::vector<CountH5Record> records(bin_counts.size(), record);
  for (size_t bin=0; bin < bin_counts.size(); ++bin)
  {
    records[bin].bin_number = bin;
    records[bin].count = bin_counts[bin];
  }

  return records;
}

void batch(hid_t& file,
           const std::string& cell_type,
           const unsigned int bin_size,
           std::map<std::string, size_t> chromosomeLengths,
           const std::string& bam_file)
{
  std::deque<std::future<std::vector<CountH5Record>>> future_counts;

  for (const auto& chromosomeLength : chromosomeLengths)
  {
    future_counts.push_back(std::async(count,
                                       chromosomeLength.first,
                                       cell_type,
                                       bin_size,
                                       chromosomeLength.second,
                                       bam_file));
  }

  const size_t record_size = sizeof(CountH5Record);

  size_t record_offset[] = { HOFFSET(CountH5Record, bin_number),
                             HOFFSET(CountH5Record, cell_type),
                             HOFFSET(CountH5Record, chromosome),
                             HOFFSET(CountH5Record, count),
                             HOFFSET(CountH5Record, file_name) };

  size_t field_sizes[] = { sizeof(CountH5Record::bin_number),
                           sizeof(CountH5Record::cell_type),
                           sizeof(CountH5Record::chromosome),
                           sizeof(CountH5Record::count),
                           sizeof(CountH5Record::file_name) };

  for (auto& future_count : future_counts)
  {
    std::vector<CountH5Record> records = future_count.get();

    herr_t status = H5TBappend_records(file, "bin_counts", records.size(), record_size,
                                       record_offset, field_sizes, records.data());
    if (status != 0)
    {
      std::cerr << "Error appending record, status = " << status << std::endl;
    }
  }
}

int main(int argc, char* argv[])
{
  try
  {
    if (argc <= 5 || argc % 2 != 1)
    {
      std::cerr << "usage: " << argv[0] << " cell_type bin_size bam_file hdf5_file chr1 lenght1 ... \n"
        << "\ne.g. " << argv[0] << " mm1s 100000 /ifs/hg18/mm1s/04032013_D1L57ACXX_4.TTAGGC.hg18.bwt.sorted.bam "
        << "chr1 247249719 chr2 242951149 chr3 199501827"
        << "\nnote that this application is intended to be run from bamliquidator_batch.py -- see"
        << "\nhttps://github.com/BradnerLab/pipeline/wiki for more information"
        << std::endl;
      return 1;
    }
    std::map<std::string, size_t> chromosomeLengths;
    for (int arg = 5; arg < argc && arg + 1 < argc; arg += 2)
    {
      chromosomeLengths[argv[arg]] = boost::lexical_cast<size_t>(argv[arg+1]);
    }

    const std::string cell_type = argv[1];
    const unsigned int bin_size = boost::lexical_cast<unsigned int>(argv[2]);
    const std::string bam_file_path = argv[3];
    const std::string hdf5_file_path = argv[4];

    if (bin_size == 0)
    {
      std::cerr << "bin size cannot be zero" << std::endl;
      return 2;
    }

    hid_t h5file = H5Fopen(hdf5_file_path.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
    if (h5file < 0)
    {
      std::cerr << "Failed to open H5 file " << hdf5_file_path << std::endl;
      return 3;
    }

    batch(h5file, cell_type, bin_size, chromosomeLengths, bam_file_path);

    H5Fclose(h5file);

    return 0;
  }
  catch(const std::exception& e)
  {
    std::cerr << "Unhandled exception: " << e.what() << std::endl;

    return 4;
  }
}

/* The MIT License (MIT)

   Copyright (c) 2013 John DiMatteo (jdimatteo@gmail.com)

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

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

   THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
   IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
   FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
   AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
   LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
   OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
   THE SOFTWARE.
 */
<commit_msg>Fixed chromosome order (e.g. so chr2 is before chr10)<commit_after>#include "bamliquidator.h"

#include <cmath>
#include <fstream>
#include <future>
#include <iostream>
#include <stdexcept>
#include <sstream>
#include <vector>

#include <boost/algorithm/string.hpp>
#include <boost/lexical_cast.hpp>

#include <hdf5.h>
#include <hdf5_hl.h>

struct CountH5Record
{
  uint32_t bin_number;
  char cell_type[16];
  char chromosome[16];
  uint64_t count;
  char file_name[64];
};

std::vector<CountH5Record> count(const std::string chr,
                                 const std::string cell_type,
                                 const unsigned int bin_size,
                                 const size_t length,
                                 const std::string bam_file)
{
  const std::string bam_file_name = file_name_from_path(bam_file);

  int bins = std::ceil(length / (double) bin_size);
  int max_base_pair = bins * bin_size;

  const std::vector<double> bin_counts = liquidate(bam_file, chr, 0, max_base_pair, '.', bins, 0);

  CountH5Record record;
  record.bin_number = 0;
  strncpy(record.cell_type,  cell_type.c_str(),     sizeof(CountH5Record::cell_type));
  strncpy(record.chromosome, chr.c_str(),           sizeof(CountH5Record::chromosome));
  strncpy(record.file_name,  bam_file_name.c_str(), sizeof(CountH5Record::file_name));

  std::vector<CountH5Record> records(bin_counts.size(), record);
  for (size_t bin=0; bin < bin_counts.size(); ++bin)
  {
    records[bin].bin_number = bin;
    records[bin].count = bin_counts[bin];
  }

  return records;
}

void batch(hid_t& file,
           const std::string& cell_type,
           const unsigned int bin_size,
           const std::vector<std::pair<std::string, size_t>>& chromosomeLengths,
           const std::string& bam_file)
{
  std::deque<std::future<std::vector<CountH5Record>>> future_counts;

  for (const auto& chromosomeLength : chromosomeLengths)
  {
    future_counts.push_back(std::async(count,
                                       chromosomeLength.first,
                                       cell_type,
                                       bin_size,
                                       chromosomeLength.second,
                                       bam_file));
  }

  const size_t record_size = sizeof(CountH5Record);

  size_t record_offset[] = { HOFFSET(CountH5Record, bin_number),
                             HOFFSET(CountH5Record, cell_type),
                             HOFFSET(CountH5Record, chromosome),
                             HOFFSET(CountH5Record, count),
                             HOFFSET(CountH5Record, file_name) };

  size_t field_sizes[] = { sizeof(CountH5Record::bin_number),
                           sizeof(CountH5Record::cell_type),
                           sizeof(CountH5Record::chromosome),
                           sizeof(CountH5Record::count),
                           sizeof(CountH5Record::file_name) };

  for (auto& future_count : future_counts)
  {
    std::vector<CountH5Record> records = future_count.get();

    herr_t status = H5TBappend_records(file, "bin_counts", records.size(), record_size,
                                       record_offset, field_sizes, records.data());
    if (status != 0)
    {
      std::cerr << "Error appending record, status = " << status << std::endl;
    }
  }
}

int main(int argc, char* argv[])
{
  try
  {
    if (argc <= 5 || argc % 2 != 1)
    {
      std::cerr << "usage: " << argv[0] << " cell_type bin_size bam_file hdf5_file chr1 lenght1 ... \n"
        << "\ne.g. " << argv[0] << " mm1s 100000 /ifs/hg18/mm1s/04032013_D1L57ACXX_4.TTAGGC.hg18.bwt.sorted.bam "
        << "chr1 247249719 chr2 242951149 chr3 199501827"
        << "\nnote that this application is intended to be run from bamliquidator_batch.py -- see"
        << "\nhttps://github.com/BradnerLab/pipeline/wiki for more information"
        << std::endl;
      return 1;
    }
    std::vector<std::pair<std::string, size_t>> chromosomeLengths;
    for (int arg = 5; arg < argc && arg + 1 < argc; arg += 2)
    {
      chromosomeLengths.push_back(
        std::make_pair(argv[arg], boost::lexical_cast<size_t>(argv[arg+1])));
    }

    const std::string cell_type = argv[1];
    const unsigned int bin_size = boost::lexical_cast<unsigned int>(argv[2]);
    const std::string bam_file_path = argv[3];
    const std::string hdf5_file_path = argv[4];

    if (bin_size == 0)
    {
      std::cerr << "bin size cannot be zero" << std::endl;
      return 2;
    }

    hid_t h5file = H5Fopen(hdf5_file_path.c_str(), H5F_ACC_RDWR, H5P_DEFAULT);
    if (h5file < 0)
    {
      std::cerr << "Failed to open H5 file " << hdf5_file_path << std::endl;
      return 3;
    }

    batch(h5file, cell_type, bin_size, chromosomeLengths, bam_file_path);

    H5Fclose(h5file);

    return 0;
  }
  catch(const std::exception& e)
  {
    std::cerr << "Unhandled exception: " << e.what() << std::endl;

    return 4;
  }
}

/* The MIT License (MIT)

   Copyright (c) 2013 John DiMatteo (jdimatteo@gmail.com)

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

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

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


<commit_before>// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "paddle/phi/kernels/split_kernel.h"

#include "paddle/phi/backends/onednn/onednn_reuse.h"
#include "paddle/phi/core/kernel_registry.h"

namespace phi {

template <typename T, typename Context>
void SplitKernel(const Context& dev_ctx,
                 const DenseTensor& x,
                 const IntArray& sections,
                 const Scalar& split_axis,
                 std::vector<DenseTensor*> out) {
  const auto& onednn_engine = dev_ctx.GetEngine();

  int axis = split_axis.to<int>();

  auto outs_number = out.size();
  const auto x_dims = x.dims();
  auto x_vec_dims = vectorize(x_dims);

  dnnl::memory::data_type x_type = funcs::ToOneDNNDataType(x.dtype());

  auto& astream = OneDNNContext::tls().get_stream();

  std::vector<int64_t> offset(x_vec_dims.size(), 0);
  funcs::ReorderOneDNNHandler reorder_handler(
      x_vec_dims, x.dtype(), x_type, onednn_engine);
  auto reorder_src_memory_p = reorder_handler.AcquireSrcMemory(
      x.mem_desc(), funcs::to_void_cast(x.data<T>()));

  for (size_t i = 0; i < outs_number; ++i) {
    auto out_vec_dims = vectorize(out[i]->dims());
    auto slice_mem_p = reorder_handler.AcquireSubmemory(
        out_vec_dims, offset, reorder_src_memory_p);

    auto reorder_dst_memory_p = reorder_handler.AcquireDstMemory(
        out[i], out_vec_dims, x.format(), dev_ctx.GetPlace());
    auto reorder_p =
        reorder_handler.AcquireReorder(reorder_dst_memory_p, slice_mem_p);

    reorder_p->execute(astream, *slice_mem_p, *reorder_dst_memory_p);

    offset[axis] += sections.GetData()[i];
    out[i]->set_mem_desc(reorder_dst_memory_p->get_desc());
  }
  astream.wait();
}

template <typename T, typename Context>
void SplitWithNumKernel(const Context& dev_ctx,
                        const DenseTensor& x,
                        int num,
                        const Scalar& axis_scalar,
                        std::vector<DenseTensor*> outs) {
  int axis_value = axis_scalar.to<int>();
  auto input_axis_dim = x.dims().at(axis_value);
  std::vector<int64_t> sections_vec;
  for (int i = 0; i < num; ++i) {
    sections_vec.push_back(input_axis_dim / num);
  }
  IntArray sections(sections_vec);
  SplitKernel<T, Context>(dev_ctx, x, sections, axis_scalar, outs);
}

}  // namespace phi

PD_REGISTER_KERNEL(
    split, OneDNN, ONEDNN, phi::SplitKernel, float, phi::dtype::bfloat16) {}

PD_REGISTER_KERNEL(split_with_num,
                   OneDNN,
                   ONEDNN,
                   phi::SplitWithNumKernel,
                   float,
                   phi::dtype::bfloat16) {}
<commit_msg>minor split optimization (#47314)<commit_after>// Copyright (c) 2022 PaddlePaddle Authors. All Rights Reserved.
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

#include "paddle/phi/kernels/split_kernel.h"

#include "paddle/phi/backends/onednn/onednn_reuse.h"
#include "paddle/phi/core/kernel_registry.h"

namespace phi {

template <typename T, typename Context>
void SplitKernel(const Context& dev_ctx,
                 const DenseTensor& x,
                 const IntArray& sections,
                 const Scalar& split_axis,
                 std::vector<DenseTensor*> out) {
  const auto& onednn_engine = dev_ctx.GetEngine();

  int axis = split_axis.to<int>();

  auto outs_number = out.size();
  const auto x_dims = x.dims();
  auto x_vec_dims = vectorize(x_dims);

  dnnl::memory::data_type x_type = funcs::ToOneDNNDataType(x.dtype());

  auto& astream = OneDNNContext::tls().get_stream();

  std::vector<int64_t> offset(x_vec_dims.size(), 0);
  funcs::ReorderOneDNNHandler reorder_handler(
      x_vec_dims, x.dtype(), x_type, onednn_engine);
  auto reorder_src_memory_p = reorder_handler.AcquireSrcMemory(
      x.mem_desc(), funcs::to_void_cast(x.data<T>()));

  for (size_t i = 0; i < outs_number; ++i) {
    auto out_vec_dims = vectorize(out[i]->dims());
    auto slice_mem_p = reorder_handler.AcquireSubmemory(
        out_vec_dims, offset, reorder_src_memory_p);

    auto reorder_dst_memory_p = reorder_handler.AcquireDstMemory(
        out[i], out_vec_dims, x.format(), dev_ctx.GetPlace());
    auto reorder_p =
        reorder_handler.AcquireReorder(reorder_dst_memory_p, slice_mem_p);

    reorder_p->execute(astream, *slice_mem_p, *reorder_dst_memory_p);

    offset[axis] += sections.GetData()[i];
    out[i]->set_mem_desc(reorder_dst_memory_p->get_desc());
  }
  astream.wait();
}

template <typename T, typename Context>
void SplitWithNumKernel(const Context& dev_ctx,
                        const DenseTensor& x,
                        int num,
                        const Scalar& axis_scalar,
                        std::vector<DenseTensor*> outs) {
  int axis_value = axis_scalar.to<int>();
  auto input_axis_dim = x.dims().at(axis_value);
  const std::vector<int64_t> sections_vec(num, input_axis_dim / num);

  IntArray sections(sections_vec);
  SplitKernel<T, Context>(dev_ctx, x, sections, axis_scalar, outs);
}

}  // namespace phi

PD_REGISTER_KERNEL(
    split, OneDNN, ONEDNN, phi::SplitKernel, float, phi::dtype::bfloat16) {}

PD_REGISTER_KERNEL(split_with_num,
                   OneDNN,
                   ONEDNN,
                   phi::SplitWithNumKernel,
                   float,
                   phi::dtype::bfloat16) {}
<|endoftext|>


<commit_before>/*
  ************************************************************************
  *	HardwareSerial.cpp
  *
  *	Arduino core files for MSP430
  *		Copyright (c) 2012 Robert Wessels. All right reserved.
  *
  *
  ***********************************************************************
  Derived from:
  HardwareSerial.cpp - Hardware serial library for Wiring
  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.

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

  This library 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
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

  Modified 23 November 2006 by David A. Mellis
  Modified 28 September 2010 by Mark Sproul
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "Energia.h"
#include "wiring_private.h"
#include "usci_isr_handler.h"

#if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_A0__) || defined(__MSP430_HAS_USCI_A1__) || defined(__MSP430_HAS_EUSCI_A0__)

#include "HardwareSerial.h"

#define UCAxCTLW0     UCA0CTLW0
#define UCAxCTL0      UCA0CTL0
#define UCAxCTL1      UCA0CTL1
#define UCAxBRW       UCA0BRW
#define UCAxBR0       UCA0BR0
#define UCAxBR1       UCA0BR1
#define UCAxMCTL      UCA0MCTL
#define UCAxMCTLW     UCA0MCTLW
#define UCAxSTAT      UCA0STAT
#define UCAxRXBUF     UCA0RXBUF
#define UCAxTXBUF     UCA0TXBUF
#define UCAxABCTL     UCA0ABCTL
#define UCAxIRCTL     UCA0IRCTL
#define UCAxIRTCTL    UCA0IRTCTL
#define UCAxIRRCTL    UCA0IRRCTL
#define UCAxICTL      UCA0ICTL
#define UCAxIE        UCA0IE
#define UCAxIFG       UCA0IFG
#define UCAxIV        UCA0IV

#define SERIAL_BUFFER_SIZE 16

struct ring_buffer
{
	unsigned char buffer[SERIAL_BUFFER_SIZE];
	volatile unsigned int head;
	volatile unsigned int tail;
};

ring_buffer rx_buffer  =  { { 0 }, 0, 0 };
ring_buffer tx_buffer  =  { { 0 }, 0, 0 };
#ifdef SERIAL1_AVAILABLE
ring_buffer rx_buffer1  =  { { 0 }, 0, 0 };
ring_buffer tx_buffer1  =  { { 0 }, 0, 0 };
#endif

inline void store_char(unsigned char c, ring_buffer *buffer)
{
	unsigned int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE;

	// if we should be storing the received character into the location
	// just before the tail (meaning that the head would advance to the
	// current location of the tail), we're about to overflow the buffer
	// and so we don't write the character or advance the head.
	if (i != buffer->tail) {
		buffer->buffer[buffer->head] = c;
		buffer->head = i;
	}
}

void serialEvent() __attribute__((weak));
void serialEvent() {}
#ifdef SERIAL1_AVAILABLE
void serialEvent1() __attribute__((weak));
void serialEvent1() {}
#endif

void serialEventRun(void)
{
	if (Serial.available()) serialEvent();
#ifdef SERIAL1_AVAILABLE
	if (Serial1.available()) serialEvent1();
#endif
}

// Public Methods //////////////////////////////////////////////////////////////
#define SMCLK F_CPU //SMCLK = F_CPU for now

void HardwareSerial::begin(unsigned long baud)
{
	unsigned int mod, divider;
	unsigned char oversampling;

	/* Calling this dummy function prevents the linker
	 * from stripping the USCI interupt vectors.*/
	usci_isr_install();
	if (SMCLK/baud>=48) {                                                // requires SMCLK for oversampling
		oversampling = 1;
	}
	else {
		oversampling= 0;
	}

	divider=(SMCLK<<4)/baud;

	pinMode_int(rxPin, rxPinMode);
	pinMode_int(txPin, txPinMode);

	*(&(UCAxCTL1) + uartOffset) = UCSWRST;
	*(&(UCAxCTL1) + uartOffset) = UCSSEL_2;                                // SMCLK
	*(&(UCAxCTL0) + uartOffset) = 0;
	*(&(UCAxABCTL) + uartOffset) = 0;
#if defined(__MSP430_HAS_EUSCI_A0__)
	if(!oversampling) {
		mod = ((divider&0xF)+1)&0xE;                    // UCBRSx (bit 1-3)
		divider >>=4;
	} else {
		mod = divider&0xFFF0;                           // UCBRFx = INT([(N/16)  INT(N/16)]  16)
		divider>>=8;
	}
	*(&(UCAxBR0) + uartOffset) = divider;
	*(&(UCAxBR1) + uartOffset) = divider>>8;
	*(&(UCAxMCTLW) + uartOffset)= (oversampling ? UCOS16:0) | mod;
#else
	if(!oversampling) {
		mod = ((divider&0xF)+1)&0xE;                    // UCBRSx (bit 1-3)
		divider >>=4;
	} else {
		mod = ((divider&0xf8)+0x8)&0xf0;                // UCBRFx (bit 4-7)
		divider>>=8;
	}
	*(&(UCAxBR0) + uartOffset)= divider;
	*(&(UCAxBR1) + uartOffset) = divider>>8;
	*(&(UCAxMCTL) + uartOffset) = (unsigned char)(oversampling ? UCOS16:0) | mod;
#endif
	*(&(UCAxCTL1) + uartOffset) &= ~UCSWRST;
#if defined(__MSP430_HAS_USCI_A0__) || defined(__MSP430_HAS_USCI_A1__) || defined(__MSP430_HAS_EUSCI_A0__)
	*(&(UCAxIE) + uartOffset) |= UCRXIE;
#else
	*(&(UC0IE) + uartOffset) |= UCA0RXIE;
#endif
}

void HardwareSerial::end()
{
	// wait for transmission of outgoing data
	while (_tx_buffer->head != _tx_buffer->tail);

	_rx_buffer->head = _rx_buffer->tail;
}

int HardwareSerial::available(void)
{
	return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % SERIAL_BUFFER_SIZE;
}

int HardwareSerial::peek(void)
{
	if (_rx_buffer->head == _rx_buffer->tail) {
		return -1;
	} else {
		return _rx_buffer->buffer[_rx_buffer->tail];
	}
}

int HardwareSerial::read(void)
{
	// if the head isn't ahead of the tail, we don't have any characters
	if (_rx_buffer->head == _rx_buffer->tail) {
		return -1;
	} else {
		unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
		_rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) % SERIAL_BUFFER_SIZE;
		return c;
	}
}

void HardwareSerial::flush()
{
	while (_tx_buffer->head != _tx_buffer->tail);
}

size_t HardwareSerial::write(uint8_t c)
{
	unsigned int i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE;

	// If the output buffer is full, there's nothing for it other than to
	// wait for the interrupt handler to empty it a bit
	// ???: return 0 here instead?
	while (i == _tx_buffer->tail);

	_tx_buffer->buffer[_tx_buffer->head] = c;
	_tx_buffer->head = i;

#if defined(__MSP430_HAS_USCI_A0__) || defined(__MSP430_HAS_USCI_A1__) || defined(__MSP430_HAS_EUSCI_A0__)
	*(&(UCAxIE) + uartOffset) |= UCTXIE;
#else
	*(&(UC0IE) + uartOffset) |= UCA0TXIE;
#endif

	return 1;
}

void uart_rx_isr(uint8_t offset)
{
#ifdef SERIAL1_AVAILABLE
	/* Debug uart aka Serial always gets rx_buffer and aux aka Serial1 gets rx_buffer1 */
	ring_buffer *rx_buffer_ptr = (offset == DEBUG_UART_MODULE_OFFSET) ? &rx_buffer:&rx_buffer1;
#else
	ring_buffer *rx_buffer_ptr = &rx_buffer;
#endif
	unsigned char c = *(&(UCAxRXBUF) + offset);
	store_char(c, rx_buffer_ptr);
}

void uart_tx_isr(uint8_t offset)
{
#ifdef SERIAL1_AVAILABLE
	/* Debug uart aka Serial always gets rx_buffer and aux aka Serial1 gets rx_buffer1 */
	ring_buffer *tx_buffer_ptr = (offset == DEBUG_UART_MODULE_OFFSET) ? &tx_buffer : &tx_buffer;
#else
	ring_buffer *tx_buffer_ptr = &tx_buffer;
#endif
	if (tx_buffer_ptr->head == tx_buffer_ptr->tail) {
		// Buffer empty, so disable interrupts
#if defined(__MSP430_HAS_USCI_A0__) || defined(__MSP430_HAS_USCI_A1__) || defined(__MSP430_HAS_EUSCI_A0__)
		*(&(UCAxIE) + offset) &= ~UCTXIE;
		*(&(UCAxIFG) + offset) |= UCTXIFG;    // Set Flag again
#else
		*(&(UC0IE) + offset) &= ~UCA0TXIE;
#endif
		return;
	}

	unsigned char c = tx_buffer_ptr->buffer[tx_buffer_ptr->tail];
	tx_buffer_ptr->tail = (tx_buffer_ptr->tail + 1) % SERIAL_BUFFER_SIZE;
	*(&(UCAxTXBUF) + offset) = c;
}
// Preinstantiate Objects //////////////////////////////////////////////////////

HardwareSerial Serial(&rx_buffer, &tx_buffer, DEBUG_UART_MODULE_OFFSET, DEBUG_UARTRXD_SET_MODE, DEBUG_UARTTXD_SET_MODE, DEBUG_UARTRXD, DEBUG_UARTTXD);
#ifdef SERIAL1_AVAILABLE
HardwareSerial Serial1(&rx_buffer1, &tx_buffer1, AUX_UART_MODULE_OFFSET, AUX_UARTRXD_SET_MODE, DEBUG_UARTTXD_SET_MODE, AUX_UARTRXD, AUX_UARTTXD);
#endif

#endif
<commit_msg>Fix auxiliary UART tx buffer assignment<commit_after>/*
  ************************************************************************
  *	HardwareSerial.cpp
  *
  *	Arduino core files for MSP430
  *		Copyright (c) 2012 Robert Wessels. All right reserved.
  *
  *
  ***********************************************************************
  Derived from:
  HardwareSerial.cpp - Hardware serial library for Wiring
  Copyright (c) 2006 Nicholas Zambetti.  All right reserved.

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

  This library 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
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA

  Modified 23 November 2006 by David A. Mellis
  Modified 28 September 2010 by Mark Sproul
*/

#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <inttypes.h>
#include "Energia.h"
#include "wiring_private.h"
#include "usci_isr_handler.h"

#if defined(__MSP430_HAS_USCI__) || defined(__MSP430_HAS_USCI_A0__) || defined(__MSP430_HAS_USCI_A1__) || defined(__MSP430_HAS_EUSCI_A0__)

#include "HardwareSerial.h"

#define UCAxCTLW0     UCA0CTLW0
#define UCAxCTL0      UCA0CTL0
#define UCAxCTL1      UCA0CTL1
#define UCAxBRW       UCA0BRW
#define UCAxBR0       UCA0BR0
#define UCAxBR1       UCA0BR1
#define UCAxMCTL      UCA0MCTL
#define UCAxMCTLW     UCA0MCTLW
#define UCAxSTAT      UCA0STAT
#define UCAxRXBUF     UCA0RXBUF
#define UCAxTXBUF     UCA0TXBUF
#define UCAxABCTL     UCA0ABCTL
#define UCAxIRCTL     UCA0IRCTL
#define UCAxIRTCTL    UCA0IRTCTL
#define UCAxIRRCTL    UCA0IRRCTL
#define UCAxICTL      UCA0ICTL
#define UCAxIE        UCA0IE
#define UCAxIFG       UCA0IFG
#define UCAxIV        UCA0IV

#define SERIAL_BUFFER_SIZE 16

struct ring_buffer
{
	unsigned char buffer[SERIAL_BUFFER_SIZE];
	volatile unsigned int head;
	volatile unsigned int tail;
};

ring_buffer rx_buffer  =  { { 0 }, 0, 0 };
ring_buffer tx_buffer  =  { { 0 }, 0, 0 };
#ifdef SERIAL1_AVAILABLE
ring_buffer rx_buffer1  =  { { 0 }, 0, 0 };
ring_buffer tx_buffer1  =  { { 0 }, 0, 0 };
#endif

inline void store_char(unsigned char c, ring_buffer *buffer)
{
	unsigned int i = (unsigned int)(buffer->head + 1) % SERIAL_BUFFER_SIZE;

	// if we should be storing the received character into the location
	// just before the tail (meaning that the head would advance to the
	// current location of the tail), we're about to overflow the buffer
	// and so we don't write the character or advance the head.
	if (i != buffer->tail) {
		buffer->buffer[buffer->head] = c;
		buffer->head = i;
	}
}

void serialEvent() __attribute__((weak));
void serialEvent() {}
#ifdef SERIAL1_AVAILABLE
void serialEvent1() __attribute__((weak));
void serialEvent1() {}
#endif

void serialEventRun(void)
{
	if (Serial.available()) serialEvent();
#ifdef SERIAL1_AVAILABLE
	if (Serial1.available()) serialEvent1();
#endif
}

// Public Methods //////////////////////////////////////////////////////////////
#define SMCLK F_CPU //SMCLK = F_CPU for now

void HardwareSerial::begin(unsigned long baud)
{
	unsigned int mod, divider;
	unsigned char oversampling;

	/* Calling this dummy function prevents the linker
	 * from stripping the USCI interupt vectors.*/
	usci_isr_install();
	if (SMCLK/baud>=48) {                                                // requires SMCLK for oversampling
		oversampling = 1;
	}
	else {
		oversampling= 0;
	}

	divider=(SMCLK<<4)/baud;

	pinMode_int(rxPin, rxPinMode);
	pinMode_int(txPin, txPinMode);

	*(&(UCAxCTL1) + uartOffset) = UCSWRST;
	*(&(UCAxCTL1) + uartOffset) = UCSSEL_2;                                // SMCLK
	*(&(UCAxCTL0) + uartOffset) = 0;
	*(&(UCAxABCTL) + uartOffset) = 0;
#if defined(__MSP430_HAS_EUSCI_A0__)
	if(!oversampling) {
		mod = ((divider&0xF)+1)&0xE;                    // UCBRSx (bit 1-3)
		divider >>=4;
	} else {
		mod = divider&0xFFF0;                           // UCBRFx = INT([(N/16)  INT(N/16)]  16)
		divider>>=8;
	}
	*(&(UCAxBR0) + uartOffset) = divider;
	*(&(UCAxBR1) + uartOffset) = divider>>8;
	*(&(UCAxMCTLW) + uartOffset)= (oversampling ? UCOS16:0) | mod;
#else
	if(!oversampling) {
		mod = ((divider&0xF)+1)&0xE;                    // UCBRSx (bit 1-3)
		divider >>=4;
	} else {
		mod = ((divider&0xf8)+0x8)&0xf0;                // UCBRFx (bit 4-7)
		divider>>=8;
	}
	*(&(UCAxBR0) + uartOffset)= divider;
	*(&(UCAxBR1) + uartOffset) = divider>>8;
	*(&(UCAxMCTL) + uartOffset) = (unsigned char)(oversampling ? UCOS16:0) | mod;
#endif
	*(&(UCAxCTL1) + uartOffset) &= ~UCSWRST;
#if defined(__MSP430_HAS_USCI_A0__) || defined(__MSP430_HAS_USCI_A1__) || defined(__MSP430_HAS_EUSCI_A0__)
	*(&(UCAxIE) + uartOffset) |= UCRXIE;
#else
	*(&(UC0IE) + uartOffset) |= UCA0RXIE;
#endif
}

void HardwareSerial::end()
{
	// wait for transmission of outgoing data
	while (_tx_buffer->head != _tx_buffer->tail);

	_rx_buffer->head = _rx_buffer->tail;
}

int HardwareSerial::available(void)
{
	return (unsigned int)(SERIAL_BUFFER_SIZE + _rx_buffer->head - _rx_buffer->tail) % SERIAL_BUFFER_SIZE;
}

int HardwareSerial::peek(void)
{
	if (_rx_buffer->head == _rx_buffer->tail) {
		return -1;
	} else {
		return _rx_buffer->buffer[_rx_buffer->tail];
	}
}

int HardwareSerial::read(void)
{
	// if the head isn't ahead of the tail, we don't have any characters
	if (_rx_buffer->head == _rx_buffer->tail) {
		return -1;
	} else {
		unsigned char c = _rx_buffer->buffer[_rx_buffer->tail];
		_rx_buffer->tail = (unsigned int)(_rx_buffer->tail + 1) % SERIAL_BUFFER_SIZE;
		return c;
	}
}

void HardwareSerial::flush()
{
	while (_tx_buffer->head != _tx_buffer->tail);
}

size_t HardwareSerial::write(uint8_t c)
{
	unsigned int i = (_tx_buffer->head + 1) % SERIAL_BUFFER_SIZE;

	// If the output buffer is full, there's nothing for it other than to
	// wait for the interrupt handler to empty it a bit
	// ???: return 0 here instead?
	while (i == _tx_buffer->tail);

	_tx_buffer->buffer[_tx_buffer->head] = c;
	_tx_buffer->head = i;

#if defined(__MSP430_HAS_USCI_A0__) || defined(__MSP430_HAS_USCI_A1__) || defined(__MSP430_HAS_EUSCI_A0__)
	*(&(UCAxIE) + uartOffset) |= UCTXIE;
#else
	*(&(UC0IE) + uartOffset) |= UCA0TXIE;
#endif

	return 1;
}

void uart_rx_isr(uint8_t offset)
{
#ifdef SERIAL1_AVAILABLE
	/* Debug uart aka Serial always gets rx_buffer and aux aka Serial1 gets rx_buffer1 */
	ring_buffer *rx_buffer_ptr = (offset == DEBUG_UART_MODULE_OFFSET) ? &rx_buffer:&rx_buffer1;
#else
	ring_buffer *rx_buffer_ptr = &rx_buffer;
#endif
	unsigned char c = *(&(UCAxRXBUF) + offset);
	store_char(c, rx_buffer_ptr);
}

void uart_tx_isr(uint8_t offset)
{
#ifdef SERIAL1_AVAILABLE
	/* Debug uart aka Serial always gets rx_buffer and aux aka Serial1 gets rx_buffer1 */
	ring_buffer *tx_buffer_ptr = (offset == DEBUG_UART_MODULE_OFFSET) ? &tx_buffer : &tx_buffer1;
#else
	ring_buffer *tx_buffer_ptr = &tx_buffer;
#endif
	if (tx_buffer_ptr->head == tx_buffer_ptr->tail) {
		// Buffer empty, so disable interrupts
#if defined(__MSP430_HAS_USCI_A0__) || defined(__MSP430_HAS_USCI_A1__) || defined(__MSP430_HAS_EUSCI_A0__)
		*(&(UCAxIE) + offset) &= ~UCTXIE;
		*(&(UCAxIFG) + offset) |= UCTXIFG;    // Set Flag again
#else
		*(&(UC0IE) + offset) &= ~UCA0TXIE;
#endif
		return;
	}

	unsigned char c = tx_buffer_ptr->buffer[tx_buffer_ptr->tail];
	tx_buffer_ptr->tail = (tx_buffer_ptr->tail + 1) % SERIAL_BUFFER_SIZE;
	*(&(UCAxTXBUF) + offset) = c;
}
// Preinstantiate Objects //////////////////////////////////////////////////////

HardwareSerial Serial(&rx_buffer, &tx_buffer, DEBUG_UART_MODULE_OFFSET, DEBUG_UARTRXD_SET_MODE, DEBUG_UARTTXD_SET_MODE, DEBUG_UARTRXD, DEBUG_UARTTXD);
#ifdef SERIAL1_AVAILABLE
HardwareSerial Serial1(&rx_buffer1, &tx_buffer1, AUX_UART_MODULE_OFFSET, AUX_UARTRXD_SET_MODE, DEBUG_UARTTXD_SET_MODE, AUX_UARTRXD, AUX_UARTTXD);
#endif

#endif
<|endoftext|>