<commit_before>#include "linuxPlatform.h"
#include "linuxSystemFontHelper.h"
#include "gl/hardware.h"
#include "log.h"
#include <algorithm>
#include <stdio.h>
#include <stdarg.h>
#include <libgen.h>
#include <unistd.h>
#include <sys/resource.h>
#include <sys/syscall.h>

#if defined(TANGRAM_LINUX)
#include <GLFW/glfw3.h>
#elif defined(TANGRAM_RPI)
#include "context.h"
#endif

namespace Tangram {

void logMsg(const char* fmt, ...) {
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
}

LinuxPlatform::LinuxPlatform() {
    m_urlClient = std::make_unique<UrlClient>(UrlClient::Options{});
    m_fcConfig = FcInitLoadConfigAndFonts();
}

LinuxPlatform::LinuxPlatform(UrlClient::Options urlClientOptions) :
    m_urlClient(std::make_unique<UrlClient>(urlClientOptions)) {
    m_fcConfig = FcInitLoadConfigAndFonts();
}

LinuxPlatform::~LinuxPlatform() {
    FcConfigDestroy(m_fcConfig);
}

void LinuxPlatform::shutdown() {
    // Stop all UrlWorker threads
    m_urlClient.reset();

    Platform::shutdown();
}

void LinuxPlatform::requestRender() const {
    if (m_shutdown) { return; }
    glfwPostEmptyEvent();
}

std::vector<FontSourceHandle> LinuxPlatform::systemFontFallbacksHandle() const {

    // Read system fontconfig to get list of fallback font for each
    // supported language
    auto fallbackFonts = systemFallbackFonts(m_fcConfig);

    // Create FontSourceHandle from the found list of fallback fonts
    std::vector<FontSourceHandle> handles;
    handles.reserve(fallbackFonts.size());

    std::transform(std::begin(fallbackFonts), std::end(fallbackFonts),
                   std::back_inserter(handles),
                   [](auto& path) { return FontSourceHandle(Url(path)); });

    return handles;
}

FontSourceHandle LinuxPlatform::systemFont(const std::string& _name,
                                           const std::string& _weight,
                                           const std::string& _face) const {

    auto fontFile = systemFontPath(m_fcConfig, _name, _weight, _face);

    if (fontFile.empty()) { return {}; }

    return FontSourceHandle(Url(fontFile));
}

Platform::UrlRequestId LinuxPlatform::startUrlRequest(Url _url, UrlRequestHandle _handle) {
    UrlRequestId id = UrlRequestNotCancelable;

    if (_url.hasHttpScheme()) {
        id = m_urlClient->addRequest(_url.string(),
             [this, _handle](UrlResponse&& response) {
                 onUrlResponse(_handle, std::move(response));
             });
    } else {
        //UrlRequestId id = static_cast<UrlRequestHandle>(--m_urlRequestCount);

        m_fileWorker.enqueue([this, path = _url.path(), _handle](){
             UrlResponse response;
             auto allocator = [&](size_t size) {
                 response.content.resize(size);
                 return response.content.data();
             };

             Platform::bytesFromFileSystem(path.c_str(), allocator);
             onUrlResponse(_handle, std::move(response));
        });
    }
    return id;
}

void LinuxPlatform::urlRequestCanceled(Platform::UrlRequestId _id) {
    m_urlClient->cancelRequest(_id);
}

void setCurrentThreadPriority(int priority) {
    setpriority(PRIO_PROCESS, 0, priority);
}

void initGLExtensions() {
    Tangram::Hardware::supportsMapBuffer = true;
}

} // namespace Tangram
<commit_msg>squash: linux fixup+cleanup<commit_after>#include "linuxPlatform.h"
#include "linuxSystemFontHelper.h"
#include "gl/hardware.h"
#include "log.h"
#include <algorithm>
#include <stdio.h>
#include <stdarg.h>
#include <libgen.h>
#include <unistd.h>
#include <sys/resource.h>
#include <sys/syscall.h>

#if defined(TANGRAM_LINUX)
#include <GLFW/glfw3.h>
#elif defined(TANGRAM_RPI)
#include "context.h"
#endif

namespace Tangram {

void logMsg(const char* fmt, ...) {
    va_list args;
    va_start(args, fmt);
    vfprintf(stderr, fmt, args);
    va_end(args);
}

LinuxPlatform::LinuxPlatform() {
    m_urlClient = std::make_unique<UrlClient>(UrlClient::Options{});
    m_fcConfig = FcInitLoadConfigAndFonts();
}

LinuxPlatform::LinuxPlatform(UrlClient::Options urlClientOptions) :
    m_urlClient(std::make_unique<UrlClient>(urlClientOptions)) {
    m_fcConfig = FcInitLoadConfigAndFonts();
}

LinuxPlatform::~LinuxPlatform() {
    FcConfigDestroy(m_fcConfig);
}

void LinuxPlatform::shutdown() {
    // Stop all UrlWorker threads
    m_urlClient.reset();

    Platform::shutdown();
}

void LinuxPlatform::requestRender() const {
    if (m_shutdown) { return; }
    glfwPostEmptyEvent();
}

std::vector<FontSourceHandle> LinuxPlatform::systemFontFallbacksHandle() const {

    // Read system fontconfig to get list of fallback font for each
    // supported language
    auto fallbackFonts = systemFallbackFonts(m_fcConfig);

    // Create FontSourceHandle from the found list of fallback fonts
    std::vector<FontSourceHandle> handles;
    handles.reserve(fallbackFonts.size());

    std::transform(std::begin(fallbackFonts), std::end(fallbackFonts),
                   std::back_inserter(handles),
                   [](auto& path) { return FontSourceHandle(Url(path)); });

    return handles;
}

FontSourceHandle LinuxPlatform::systemFont(const std::string& _name,
                                           const std::string& _weight,
                                           const std::string& _face) const {

    auto fontFile = systemFontPath(m_fcConfig, _name, _weight, _face);

    if (fontFile.empty()) { return {}; }

    return FontSourceHandle(Url(fontFile));
}

Platform::UrlRequestId LinuxPlatform::startUrlRequest(Url _url, UrlRequestHandle _handle) {
    UrlRequestId id = UrlRequestNotCancelable;

    if (_url.hasHttpScheme()) {
        id = m_urlClient->addRequest(_url.string(),
             [this, _handle](UrlResponse&& response) {
                 onUrlResponse(_handle, std::move(response));
             });
    } else {
        m_fileWorker.enqueue([this, path = _url.path(), _handle](){
             UrlResponse response;
             auto allocator = [&](size_t size) {
                 response.content.resize(size);
                 return response.content.data();
             };

             Platform::bytesFromFileSystem(path.c_str(), allocator);
             onUrlResponse(_handle, std::move(response));
        });
    }
    return id;
}

void LinuxPlatform::urlRequestCanceled(Platform::UrlRequestId _id) {
    if (m_urlClient) {
        m_urlClient->cancelRequest(_id);
    }
}

void setCurrentThreadPriority(int priority) {
    setpriority(PRIO_PROCESS, 0, priority);
}

void initGLExtensions() {
    Tangram::Hardware::supportsMapBuffer = true;
}

} // namespace Tangram
<|endoftext|>


<commit_before>#include <iostream>
#include <string>
#include <unordered_map>
#include <utility>
#include <algorithm>
#include <sstream>
#include <vector>

struct SvoRow {
   std::string s;
   std::string v;
   std::string o;
   int n;
};

struct hashPair {
   template <class T1, class T2>
   std::size_t operator () (const std::pair<T1, T2> &p) const {
      auto value = 0x345678;
      auto h1 = std::hash<T1>{}(p.first);
      auto h2 = std::hash<T2>{}(p.second);
      value = (100003 * value) ^ h1;
      value = (100003 * value) ^ h2;
      return value;
   }
};

bool compareTuples(std::tuple<std::string, std::string, int> a,
                     std::tuple<std::string, std::string, int> b) {
   return std::get<2>(a) > std::get<2>(b);
}

std::vector<std::string> &split(const std::string &s, char delim,
                                 std::vector<std::string> &elems) {
   std::stringstream ss(s);
   std::string item;
   while (std::getline(ss, item, delim)) {
      elems.push_back(item);
   }
   return elems;
}

SvoRow rowFromSplit(std::vector<std::string> vec) {
   SvoRow row;
   row.s = vec[0];
   row.v = vec[1];
   row.o = vec[2];
   row.n = std::stoi(vec[3]);
   return row;
}

std::vector<std::string> split(const std::string &s, char delim) {
   std::vector<std::string> elems;
   split(s, delim, elems);
   return elems;
}

int main(int argc, char** argv) {
   if (argc < 2) {
      std::cout << "Unspecified N value" << std::endl;
      return -1;
   }

   int n = std::stoi(argv[1]);
   SvoRow row;
   std::unordered_map<std::pair<std::string, std::string>, int, hashPair> pairs;
   std::vector<std::tuple<std::string, std::string, int> > ordered;
   std::string line;

   while (std::getline(std::cin, line)) {
      std::vector<std::string> elems = split(line, '\t');
      row = rowFromSplit(elems);
      pairs[std::make_pair(row.s, row.o)] += row.n;
   }

   for (const auto &data : pairs) {
      ordered.push_back(std::make_tuple(data.first.first,
                                          data.first.second, data.second));
   }

   n = std::min(n, (int)ordered.size());

   std::partial_sort(ordered.begin(), ordered.begin() + n,
                     ordered.end(), compareTuples);

   for (auto it = ordered.begin(); it != ordered.begin() + n; ++it) {
      std::cout << "(" << std::get<0>(*it) << ", " << std::get<1>(*it)
                  << ") = " << std::get<2>(*it) << "\n";
   }
}
<commit_msg>Now read rows linearly, without splitting<commit_after>#include <iostream>
#include <string>
#include <unordered_map>
#include <utility>
#include <algorithm>
#include <sstream>
#include <vector>

struct SvoRow {
   std::string s;
   std::string v;
   std::string o;
   int n;
};

struct hashPair {
   template <class T1, class T2>
   std::size_t operator () (const std::pair<T1, T2> &p) const {
      auto value = 0x345678;
      auto h1 = std::hash<T1>{}(p.first);
      auto h2 = std::hash<T2>{}(p.second);
      value = (100003 * value) ^ h1;
      value = (100003 * value) ^ h2;
      return value;
   }
};

bool compareTuples(std::tuple<std::string, std::string, int> a,
                     std::tuple<std::string, std::string, int> b) {
   return std::get<2>(a) > std::get<2>(b);
}

std::vector<std::string> &split(const std::string &s, char delim,
                                 std::vector<std::string> &elems) {
   std::stringstream ss(s);
   std::string item;
   while (std::getline(ss, item, delim)) {
      elems.push_back(item);
   }
   return elems;
}

SvoRow rowFromSplit(std::vector<std::string> vec) {
   SvoRow row;
   row.s = vec[0];
   row.v = vec[1];
   row.o = vec[2];
   row.n = std::stoi(vec[3]);
   return row;
}

std::vector<std::string> split(const std::string &s, char delim) {
   std::vector<std::string> elems;
   split(s, delim, elems);
   return elems;
}

int main(int argc, char** argv) {
   if (argc < 2) {
      std::cout << "Unspecified N value" << std::endl;
      return -1;
   }

   int n = std::stoi(argv[1]);
   SvoRow row;
   std::unordered_map<std::pair<std::string, std::string>, int, hashPair> pairs;
   std::vector<std::tuple<std::string, std::string, int> > ordered;
   std::string tempString;

   while (std::cin.good()) {
      std::getline(std::cin, row.s, '\t');
      std::getline(std::cin, row.v, '\t');
      std::getline(std::cin, row.o, '\t');
      std::getline(std::cin, tempString);
      row.n = std::stoi(tempString);
      pairs[std::make_pair(row.s, row.o)] += row.n;
      std::cin.peek();
   }

   for (const auto &data : pairs) {
      ordered.push_back(std::make_tuple(data.first.first,
                                          data.first.second, data.second));
   }

   n = std::min(n, (int)ordered.size());

   std::partial_sort(ordered.begin(), ordered.begin() + n,
                     ordered.end(), compareTuples);

   for (auto it = ordered.begin(); it != ordered.begin() + n; ++it) {
      std::cout << "(" << std::get<0>(*it) << ", " << std::get<1>(*it)
                  << ") = " << std::get<2>(*it) << "\n";
   }
}
<|endoftext|>


<commit_before>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXDE-Qt - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2012 Razor team
 * Authors:
 *   Christian Surlykke <christian@surlykke.dk>
 *
 * This program or 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 Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include <LXQt/SingleApplication>

#include <QCommandLineParser>

#include "mainwindow.h"

int main(int argc, char *argv[])
{
    LXQt::SingleApplication a(argc, argv);

    QCommandLineParser parser;
    parser.setApplicationDescription(QStringLiteral("LXQt Config Powermanagement"));
    const QString VERINFO = QStringLiteral(LXQT_POWERMANAGEMENT_VERSION
                                           "\nliblxqt   " LXQT_VERSION
                                           "\nQt        " QT_VERSION_STR);
    a.setApplicationVersion(VERINFO);
    parser.addVersionOption();
    parser.addHelpOption();
    parser.process(a);

    MainWindow mainWindow;
    mainWindow.setWindowIcon(QIcon::fromTheme("preferences-system-power-management"));
    mainWindow.show();
    a.setActivationWindow(&mainWindow);

    return a.exec();
}
<commit_msg>lxqt-config-powermanagement: set Qt::AA_UseHighDpiPixmaps to true<commit_after>/* BEGIN_COMMON_COPYRIGHT_HEADER
 * (c)LGPL2+
 *
 * LXDE-Qt - a lightweight, Qt based, desktop toolset
 * http://razor-qt.org
 *
 * Copyright: 2012 Razor team
 * Authors:
 *   Christian Surlykke <christian@surlykke.dk>
 *
 * This program or 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 Street, Fifth Floor,
 * Boston, MA 02110-1301 USA
 *
 * END_COMMON_COPYRIGHT_HEADER */

#include <LXQt/SingleApplication>

#include <QCommandLineParser>

#include "mainwindow.h"

int main(int argc, char *argv[])
{
    LXQt::SingleApplication a(argc, argv);
    a.setAttribute(Qt::AA_UseHighDpiPixmaps, true);

    QCommandLineParser parser;
    parser.setApplicationDescription(QStringLiteral("LXQt Config Powermanagement"));
    const QString VERINFO = QStringLiteral(LXQT_POWERMANAGEMENT_VERSION
                                           "\nliblxqt   " LXQT_VERSION
                                           "\nQt        " QT_VERSION_STR);
    a.setApplicationVersion(VERINFO);
    parser.addVersionOption();
    parser.addHelpOption();
    parser.process(a);

    MainWindow mainWindow;
    mainWindow.setWindowIcon(QIcon::fromTheme("preferences-system-power-management"));
    mainWindow.show();
    a.setActivationWindow(&mainWindow);

    return a.exec();
}
<|endoftext|>


<commit_before><commit_msg>Fix two bugs.<commit_after><|endoftext|>


<commit_before><commit_msg>Fix Mach-O bound errors<commit_after><|endoftext|>


<commit_before><commit_msg>do not display jitter information for observers, it is never calculated anyway<commit_after><|endoftext|>


<commit_before><commit_msg>moved lamp down to partially be embedded within terrain<commit_after><|endoftext|>


<commit_before>// Copyright 2021 The Pigweed Authors
//
// 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
//
//     https://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.

#define PW_LOG_LEVEL PW_CPU_EXCEPTION_CORTEX_M_LOG_LEVEL

#include "pw_cpu_exception_cortex_m/snapshot.h"

#include "pw_cpu_exception_cortex_m/proto_dump.h"
#include "pw_cpu_exception_cortex_m_private/config.h"
#include "pw_cpu_exception_cortex_m_private/cortex_m_constants.h"
#include "pw_cpu_exception_cortex_m_protos/cpu_state.pwpb.h"
#include "pw_log/log.h"
#include "pw_protobuf/encoder.h"
#include "pw_status/status.h"
#include "pw_thread/snapshot.h"
#include "pw_thread_protos/thread.pwpb.h"

namespace pw::cpu_exception_cortex_m {
namespace {

constexpr char kMainStackHandlerModeName[] = "Main Stack (Handler Mode)";
constexpr char kMainStackThreadModeName[] = "Main Stack (Thread Mode)";

enum class ProcessorMode {
  kHandlerMode,
  kThreadMode,
};

Status CaptureMainStack(
    ProcessorMode mode,
    uintptr_t stack_low_addr,
    uintptr_t stack_high_addr,
    uintptr_t stack_pointer,
    thread::SnapshotThreadInfo::StreamEncoder& snapshot_encoder,
    thread::ProcessThreadStackCallback& thread_stack_callback) {
  thread::Thread::StreamEncoder encoder = snapshot_encoder.GetThreadsEncoder();

  const char* thread_name;
  thread::ThreadState::Enum thread_state;
  if (mode == ProcessorMode::kHandlerMode) {
    thread_name = kMainStackHandlerModeName;
    PW_LOG_DEBUG("Capturing thread info for Main Stack (Handler Mode)");
    thread_state = thread::ThreadState::Enum::INTERRUPT_HANDLER;
    PW_LOG_DEBUG("Thread state: INTERRUPT_HANDLER");
  } else {  // mode == ProcessorMode::kThreadMode
    thread_name = kMainStackHandlerModeName;
    PW_LOG_DEBUG("Capturing thread info for Main Stack (Thread Mode)");
    thread_state = thread::ThreadState::Enum::RUNNING;
    PW_LOG_DEBUG("Thread state: RUNNING");
  }
  encoder.WriteState(thread_state);
  encoder.WriteName(std::as_bytes(std::span(std::string_view(thread_name))));

  const thread::StackContext thread_ctx = {
      .thread_name = thread_name,
      .stack_low_addr = stack_low_addr,
      .stack_high_addr = stack_high_addr,
      .stack_pointer = stack_pointer,
      .stack_pointer_est_peak = std::nullopt,
  };
  return thread::SnapshotStack(thread_ctx, encoder, thread_stack_callback);
}

}  // namespace

Status SnapshotCpuState(
    const pw_cpu_exception_State& cpu_state,
    cpu_exception::cortex_m::SnapshotCpuState::StreamEncoder&
        snapshot_encoder) {
  cpu_exception::LogCpuState(cpu_state);
  cpu_exception::cortex_m::ArmV7mCpuState::StreamEncoder cpu_state_encoder =
      snapshot_encoder.GetArmv7mCpuStateEncoder();
  pw::cpu_exception::DumpCpuStateProto(cpu_state_encoder, cpu_state);
  return snapshot_encoder.status();
}

Status SnapshotMainStackThread(
    uintptr_t stack_low_addr,
    uintptr_t stack_high_addr,
    thread::SnapshotThreadInfo::StreamEncoder& encoder,
    thread::ProcessThreadStackCallback& thread_stack_callback) {
  uintptr_t stack_pointer;
  asm volatile("mrs %0, msp\n" : "=r"(stack_pointer));

  // First check if we're in Handler mode, AKA handling exceptions/interrupts.
  //
  // Handler mode vs thread mode can be determined via IPSR, bits 8:0 of xPSR.
  // In thread mode the value is 0, in handler mode the value is non-zero.
  uint32_t xpsr;
  asm volatile("mrs %0, xpsr\n" : "=r"(xpsr));
  if ((xpsr & cpu_exception::kXpsrIpsrMask) != 0) {
    return CaptureMainStack(ProcessorMode::kHandlerMode,
                            stack_low_addr,
                            stack_high_addr,
                            stack_pointer,
                            encoder,
                            thread_stack_callback);
  }

  // It looks like we're in Thread mode which means we need to check whether
  // or not we are executing off the main stack currently.
  //
  // See ARMv7-M Architecture Reference Manual Section B1.4.4 for the control
  // register values, in particular the SPSEL bit while in Thread mode which
  // is 0 while running off the main stack and 1 while running off the proces
  // stack.
  uint32_t control;
  asm volatile("mrs %0, control\n" : "=r"(control));
  if ((control & cpu_exception::kControlThreadModeStackMask) != 0) {
    return OkStatus();  // Main stack is not currently active.
  }

  // We're running off the main stack in Thread mode.
  return CaptureMainStack(ProcessorMode::kThreadMode,
                          stack_low_addr,
                          stack_high_addr,
                          stack_pointer,
                          encoder,
                          thread_stack_callback);
}

Status SnapshotMainStackThread(
    const pw_cpu_exception_State& cpu_state,
    uintptr_t stack_low_addr,
    uintptr_t stack_high_addr,
    thread::SnapshotThreadInfo::StreamEncoder& encoder,
    thread::ProcessThreadStackCallback& thread_stack_callback) {
  const uint32_t exc_return = cpu_state.extended.exc_return;

  // See ARMv7-M Architecture Reference Manual Section B1.5.8 for the exception
  // return values, in particular bits 0:3.
  // Bits 0:3 of EXC_RETURN:
  // 0b0001 - 0x1 Handler mode Main
  // 0b1001 - 0x9 Thread mode Main
  // 0b1101 - 0xD Thread mode Process

  // First check whether the CPU state shows the main stack was active.
  if ((exc_return & cpu_exception::kExcReturnStackMask) != 0) {
    return OkStatus();  // Main stack is not currently active.
  }
  const uintptr_t stack_pointer = cpu_state.extended.msp;

  // Second, check if we're in Handler mode, AKA handling exceptions/interrupts.
  const ProcessorMode mode =
      ((exc_return & cpu_exception::kExcReturnModeMask) == 0)
          ? ProcessorMode::kHandlerMode
          : ProcessorMode::kThreadMode;

  return CaptureMainStack(mode,
                          stack_low_addr,
                          stack_high_addr,
                          stack_pointer,
                          encoder,
                          thread_stack_callback);
}

}  // namespace pw::cpu_exception_cortex_m
<commit_msg>pw_cpu_exception_cortex_m: Fix encoder usage<commit_after>// Copyright 2021 The Pigweed Authors
//
// 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
//
//     https://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.

#define PW_LOG_LEVEL PW_CPU_EXCEPTION_CORTEX_M_LOG_LEVEL

#include "pw_cpu_exception_cortex_m/snapshot.h"

#include "pw_cpu_exception_cortex_m/proto_dump.h"
#include "pw_cpu_exception_cortex_m_private/config.h"
#include "pw_cpu_exception_cortex_m_private/cortex_m_constants.h"
#include "pw_cpu_exception_cortex_m_protos/cpu_state.pwpb.h"
#include "pw_log/log.h"
#include "pw_protobuf/encoder.h"
#include "pw_status/status.h"
#include "pw_thread/snapshot.h"
#include "pw_thread_protos/thread.pwpb.h"

namespace pw::cpu_exception_cortex_m {
namespace {

constexpr char kMainStackHandlerModeName[] = "Main Stack (Handler Mode)";
constexpr char kMainStackThreadModeName[] = "Main Stack (Thread Mode)";

enum class ProcessorMode {
  kHandlerMode,
  kThreadMode,
};

Status CaptureMainStack(
    ProcessorMode mode,
    uintptr_t stack_low_addr,
    uintptr_t stack_high_addr,
    uintptr_t stack_pointer,
    thread::SnapshotThreadInfo::StreamEncoder& snapshot_encoder,
    thread::ProcessThreadStackCallback& thread_stack_callback) {
  thread::Thread::StreamEncoder encoder = snapshot_encoder.GetThreadsEncoder();

  const char* thread_name;
  thread::ThreadState::Enum thread_state;
  if (mode == ProcessorMode::kHandlerMode) {
    thread_name = kMainStackHandlerModeName;
    PW_LOG_DEBUG("Capturing thread info for Main Stack (Handler Mode)");
    thread_state = thread::ThreadState::Enum::INTERRUPT_HANDLER;
    PW_LOG_DEBUG("Thread state: INTERRUPT_HANDLER");
  } else {  // mode == ProcessorMode::kThreadMode
    thread_name = kMainStackHandlerModeName;
    PW_LOG_DEBUG("Capturing thread info for Main Stack (Thread Mode)");
    thread_state = thread::ThreadState::Enum::RUNNING;
    PW_LOG_DEBUG("Thread state: RUNNING");
  }
  encoder.WriteState(thread_state);
  encoder.WriteName(std::as_bytes(std::span(std::string_view(thread_name))));

  const thread::StackContext thread_ctx = {
      .thread_name = thread_name,
      .stack_low_addr = stack_low_addr,
      .stack_high_addr = stack_high_addr,
      .stack_pointer = stack_pointer,
      .stack_pointer_est_peak = std::nullopt,
  };
  return thread::SnapshotStack(thread_ctx, encoder, thread_stack_callback);
}

}  // namespace

Status SnapshotCpuState(
    const pw_cpu_exception_State& cpu_state,
    cpu_exception::cortex_m::SnapshotCpuState::StreamEncoder&
        snapshot_encoder) {
  cpu_exception::LogCpuState(cpu_state);
  {
    cpu_exception::cortex_m::ArmV7mCpuState::StreamEncoder cpu_state_encoder =
        snapshot_encoder.GetArmv7mCpuStateEncoder();
    pw::cpu_exception::DumpCpuStateProto(cpu_state_encoder, cpu_state);
  }
  return snapshot_encoder.status();
}

Status SnapshotMainStackThread(
    uintptr_t stack_low_addr,
    uintptr_t stack_high_addr,
    thread::SnapshotThreadInfo::StreamEncoder& encoder,
    thread::ProcessThreadStackCallback& thread_stack_callback) {
  uintptr_t stack_pointer;
  asm volatile("mrs %0, msp\n" : "=r"(stack_pointer));

  // First check if we're in Handler mode, AKA handling exceptions/interrupts.
  //
  // Handler mode vs thread mode can be determined via IPSR, bits 8:0 of xPSR.
  // In thread mode the value is 0, in handler mode the value is non-zero.
  uint32_t xpsr;
  asm volatile("mrs %0, xpsr\n" : "=r"(xpsr));
  if ((xpsr & cpu_exception::kXpsrIpsrMask) != 0) {
    return CaptureMainStack(ProcessorMode::kHandlerMode,
                            stack_low_addr,
                            stack_high_addr,
                            stack_pointer,
                            encoder,
                            thread_stack_callback);
  }

  // It looks like we're in Thread mode which means we need to check whether
  // or not we are executing off the main stack currently.
  //
  // See ARMv7-M Architecture Reference Manual Section B1.4.4 for the control
  // register values, in particular the SPSEL bit while in Thread mode which
  // is 0 while running off the main stack and 1 while running off the proces
  // stack.
  uint32_t control;
  asm volatile("mrs %0, control\n" : "=r"(control));
  if ((control & cpu_exception::kControlThreadModeStackMask) != 0) {
    return OkStatus();  // Main stack is not currently active.
  }

  // We're running off the main stack in Thread mode.
  return CaptureMainStack(ProcessorMode::kThreadMode,
                          stack_low_addr,
                          stack_high_addr,
                          stack_pointer,
                          encoder,
                          thread_stack_callback);
}

Status SnapshotMainStackThread(
    const pw_cpu_exception_State& cpu_state,
    uintptr_t stack_low_addr,
    uintptr_t stack_high_addr,
    thread::SnapshotThreadInfo::StreamEncoder& encoder,
    thread::ProcessThreadStackCallback& thread_stack_callback) {
  const uint32_t exc_return = cpu_state.extended.exc_return;

  // See ARMv7-M Architecture Reference Manual Section B1.5.8 for the exception
  // return values, in particular bits 0:3.
  // Bits 0:3 of EXC_RETURN:
  // 0b0001 - 0x1 Handler mode Main
  // 0b1001 - 0x9 Thread mode Main
  // 0b1101 - 0xD Thread mode Process

  // First check whether the CPU state shows the main stack was active.
  if ((exc_return & cpu_exception::kExcReturnStackMask) != 0) {
    return OkStatus();  // Main stack is not currently active.
  }
  const uintptr_t stack_pointer = cpu_state.extended.msp;

  // Second, check if we're in Handler mode, AKA handling exceptions/interrupts.
  const ProcessorMode mode =
      ((exc_return & cpu_exception::kExcReturnModeMask) == 0)
          ? ProcessorMode::kHandlerMode
          : ProcessorMode::kThreadMode;

  return CaptureMainStack(mode,
                          stack_low_addr,
                          stack_high_addr,
                          stack_pointer,
                          encoder,
                          thread_stack_callback);
}

}  // namespace pw::cpu_exception_cortex_m
<|endoftext|>


<commit_before>/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include "schema.hh"
#include "bytes.hh"
#include "types.hh"

//
// This header defines type system for primary key holders.
//
// We distinguish partition keys and clustering keys. API-wise they are almost
// the same, but they're separate type hierarchies.
//
// Clustering keys are further divided into prefixed and non-prefixed (full).
// Non-prefixed keys always have full component set, as defined by schema.
// Prefixed ones can have any number of trailing components missing. They may
// differ in underlying representation.
//
// The main classes are:
//
//   partition_key           - full partition key
//   clustering_key          - full clustering key
//   clustering_key_prefix   - clustering key prefix
//
// These classes wrap only the minimum information required to store the key
// (the key value itself). Any information which can be inferred from schema
// is not stored. Therefore accessors need to be provided with a pointer to
// schema, from which information about structure is extracted.

class partition_key;
class clustering_key;
class clustering_key_prefix;

// Abstracts serialized tuple, managed by tuple_type.
template <typename TopLevel>
class tuple_wrapper {
protected:
    bytes _bytes;
protected:
    tuple_wrapper(bytes&& b) : _bytes(std::move(b)) {}

    static inline auto get_tuple_type(const schema& s) {
        return TopLevel::get_tuple_type(s);
    }
public:
    static TopLevel make_empty(const schema& s) {
        std::vector<bytes> v;
        v.resize(get_tuple_type(s)->types().size());
        return from_exploded(s, v);
    }

    static TopLevel from_exploded(const schema& s, const std::vector<bytes>& v) {
        return TopLevel::from_bytes(get_tuple_type(s)->serialize_value(v));
    }

    static TopLevel from_exploded(const schema& s, std::vector<bytes>&& v) {
        return TopLevel::from_bytes(get_tuple_type(s)->serialize_value(std::move(v)));
    }

    // We don't allow optional values, but provide this method as an efficient adaptor
    static TopLevel from_optional_exploded(const schema& s, const std::vector<bytes_opt>& v) {
        return TopLevel::from_bytes(get_tuple_type(s)->serialize_optionals(v));
    }

    static TopLevel from_deeply_exploded(const schema& s, const std::vector<boost::any>& v) {
        return TopLevel::from_bytes(get_tuple_type(s)->serialize_value_deep(v));
    }

    static TopLevel from_single_value(const schema& s, bytes v) {
        return TopLevel::from_bytes(get_tuple_type(s)->serialize_single(std::move(v)));
    }

    // FIXME: return views
    std::vector<bytes> explode(const schema& s) const {
        return get_tuple_type(s)->deserialize_value(_bytes);
    }

    struct less_compare {
        typename TopLevel::tuple _t;
        less_compare(const schema& s) : _t(get_tuple_type(s)) {}
        bool operator()(const TopLevel& k1, const TopLevel& k2) const {
            return _t->less(k1, k2);
        }
    };

    struct hashing {
        typename TopLevel::tuple _t;
        hashing(const schema& s) : _t(get_tuple_type(s)) {}
        size_t operator()(const TopLevel& o) const {
            return _t->hash(o);
        }
    };

    struct equality {
        typename TopLevel::tuple _t;
        equality(const schema& s) : _t(get_tuple_type(s)) {}
        bool operator()(const TopLevel& o1, const TopLevel& o2) const {
            return _t->equal(o1, o2);
        }
    };

    bool equal(const schema& s, const TopLevel& other) const {
        return get_tuple_type(s)->equal(*this, other);
    }

    operator bytes_view() const {
        return _bytes;
    }
};

template <typename TopLevel, typename PrefixTopLevel>
class prefix_view_on_full_tuple {
public:
    using iterator = typename tuple_type<allow_prefixes::no>::iterator;
private:
    bytes_view _b;
    unsigned _prefix_len;
    iterator _begin;
    iterator _end;
public:
    prefix_view_on_full_tuple(const schema& s, bytes_view b, unsigned prefix_len)
        : _b(b)
        , _prefix_len(prefix_len)
        , _begin(TopLevel::get_tuple_type(s)->begin(_b))
        , _end(_begin)
    {
        std::advance(_end, prefix_len);
    }

    iterator begin() const { return _begin; }
    iterator end() const { return _end; }

    struct less_compare_with_prefix {
        typename PrefixTopLevel::tuple prefix_type;

        less_compare_with_prefix(const schema& s)
            : prefix_type(PrefixTopLevel::get_tuple_type(s))
        { }

        bool operator()(const prefix_view_on_full_tuple& k1, const PrefixTopLevel& k2) const {
            return lexicographical_tri_compare(
                prefix_type->types().begin(), prefix_type->types().end(),
                k1.begin(), k1.end(),
                prefix_type->begin(k2), prefix_type->end(k2),
                tri_compare) < 0;
        }

        bool operator()(const PrefixTopLevel& k1, const prefix_view_on_full_tuple& k2) const {
            return lexicographical_tri_compare(
                prefix_type->types().begin(), prefix_type->types().end(),
                prefix_type->begin(k1), prefix_type->end(k1),
                k2.begin(), k2.end(),
                tri_compare) < 0;
        }
    };
};

template <typename TopLevel, typename PrefixTopLevel>
class prefixable_full_tuple : public tuple_wrapper<TopLevel> {
    using base = tuple_wrapper<TopLevel>;
protected:
    prefixable_full_tuple(bytes&& b) : base(std::move(b)) {}
public:
    using prefix_view_type = prefix_view_on_full_tuple<TopLevel, PrefixTopLevel>;

    bool is_prefixed_by(const schema& s, const PrefixTopLevel& prefix) const {
        auto t = base::get_tuple_type(s);
        auto prefix_type = PrefixTopLevel::get_tuple_type(s);
        return ::is_prefixed_by(t->types().begin(),
            t->begin(*this), t->end(*this),
            prefix_type->begin(prefix), prefix_type->end(prefix),
            ::equal);
    }

    struct less_compare_with_prefix {
        typename PrefixTopLevel::tuple prefix_type;
        typename TopLevel::tuple full_type;

        less_compare_with_prefix(const schema& s)
            : prefix_type(PrefixTopLevel::get_tuple_type(s))
            , full_type(TopLevel::get_tuple_type(s))
        { }

        bool operator()(const TopLevel& k1, const PrefixTopLevel& k2) const {
            return lexicographical_tri_compare(
                prefix_type->types().begin(), prefix_type->types().end(),
                full_type->begin(k1), full_type->end(k1),
                prefix_type->begin(k2), prefix_type->end(k2),
                tri_compare) < 0;
        }

        bool operator()(const PrefixTopLevel& k1, const TopLevel& k2) const {
            return lexicographical_tri_compare(
                prefix_type->types().begin(), prefix_type->types().end(),
                prefix_type->begin(k1), prefix_type->end(k1),
                full_type->begin(k2), full_type->end(k2),
                tri_compare) < 0;
        }
    };

    // In prefix equality two sequences are equal if any of them is a prefix
    // of the other. Otherwise lexicographical ordering is applied.
    // Note: full tuples sorted according to lexicographical ordering are also
    // sorted according to prefix equality ordering.
    struct prefix_equality_less_compare {
        typename PrefixTopLevel::tuple prefix_type;
        typename TopLevel::tuple full_type;

        prefix_equality_less_compare(const schema& s)
            : prefix_type(PrefixTopLevel::get_tuple_type(s))
            , full_type(TopLevel::get_tuple_type(s))
        { }

        bool operator()(const TopLevel& k1, const PrefixTopLevel& k2) const {
            return prefix_equality_tri_compare(prefix_type->types().begin(),
                full_type->begin(k1), full_type->end(k1),
                prefix_type->begin(k2), prefix_type->end(k2),
                tri_compare) < 0;
        }

        bool operator()(const PrefixTopLevel& k1, const TopLevel& k2) const {
            return prefix_equality_tri_compare(prefix_type->types().begin(),
                prefix_type->begin(k1), prefix_type->end(k1),
                full_type->begin(k2), full_type->end(k2),
                tri_compare) < 0;
        }
    };

    auto prefix_view(const schema& s, unsigned prefix_len) const {
        return prefix_view_type(s, *this, prefix_len);
    }
};

template <typename TopLevel, typename FullTopLevel>
class prefix_tuple_wrapper : public tuple_wrapper<TopLevel> {
    using base = tuple_wrapper<TopLevel>;
protected:
    prefix_tuple_wrapper(bytes&& b) : base(std::move(b)) {}
public:
    bool is_full(const schema& s) const {
        return TopLevel::get_tuple_type(s)->is_full(base::_bytes);
    }

    // Can be called only if is_full()
    FullTopLevel to_full(const schema& s) const {
        return FullTopLevel::from_exploded(s, base::explode(s));
    }

    bool is_prefixed_by(const schema& s, const TopLevel& prefix) const {
        auto t = base::get_tuple_type(s);
        return ::is_prefixed_by(t->types().begin(),
            t->begin(*this), t->end(*this),
            t->begin(prefix), t->end(prefix),
            equal);
    }
};

class partition_key : public tuple_wrapper<partition_key> {
public:
    partition_key(bytes&& b) : tuple_wrapper<partition_key>(std::move(b)) {}
public:
    using tuple = lw_shared_ptr<tuple_type<allow_prefixes::no>>;

    static partition_key from_bytes(bytes b) { return partition_key(std::move(b)); }
    static auto get_tuple_type(const schema& s) { return s.partition_key_type; }
};

class exploded_clustering_prefix {
    std::vector<bytes> _v;
public:
    exploded_clustering_prefix(std::vector<bytes>&& v) : _v(std::move(v)) {}
    exploded_clustering_prefix() {}
    size_t size() const {
        return _v.size();
    }
    auto const& components() const {
        return _v;
    }
    explicit operator bool() const {
        return !_v.empty();
    }
    bool is_full(const schema& s) const {
        return _v.size() == s.clustering_key_size();
    }
    friend std::ostream& operator<<(std::ostream& os, const exploded_clustering_prefix& ecp);
};

class clustering_key : public prefixable_full_tuple<clustering_key, clustering_key_prefix> {
public:
    clustering_key(bytes&& b) : prefixable_full_tuple<clustering_key, clustering_key_prefix>(std::move(b)) {}
public:
    using tuple = lw_shared_ptr<tuple_type<allow_prefixes::no>>;

    static clustering_key from_bytes(bytes b) { return clustering_key(std::move(b)); }
    static auto get_tuple_type(const schema& s) { return s.clustering_key_type; }

    static clustering_key from_clustering_prefix(const schema& s, const exploded_clustering_prefix& prefix) {
        assert(prefix.is_full(s));
        return from_exploded(s, prefix.components());
    }
};

class clustering_key_prefix : public prefix_tuple_wrapper<clustering_key_prefix, clustering_key> {
    clustering_key_prefix(bytes&& b) : prefix_tuple_wrapper<clustering_key_prefix, clustering_key>(std::move(b)) {}
public:
    using tuple = lw_shared_ptr<tuple_type<allow_prefixes::yes>>;

    static clustering_key_prefix from_bytes(bytes b) { return clustering_key_prefix(std::move(b)); }
    static auto get_tuple_type(const schema& s) { return s.clustering_key_prefix_type; }

    static clustering_key_prefix from_clustering_prefix(const schema& s, const exploded_clustering_prefix& prefix) {
        return from_exploded(s, prefix.components());
    }
};

static inline
std::ostream& operator<<(std::ostream& out, const partition_key& pk) {
    return out << "pk{" << to_hex(pk) << "}";
}

static inline
std::ostream& operator<<(std::ostream& out, const clustering_key& ck) {
    return out << "ck{" << to_hex(ck) << "}";
}

static inline
std::ostream& operator<<(std::ostream& out, const clustering_key_prefix& ckp) {
    return out << "ckp{" << to_hex(ckp) << "}";
}
<commit_msg>types: Improve code readability<commit_after>/*
 * Copyright (C) 2015 Cloudius Systems, Ltd.
 */

#pragma once

#include "schema.hh"
#include "bytes.hh"
#include "types.hh"

//
// This header defines type system for primary key holders.
//
// We distinguish partition keys and clustering keys. API-wise they are almost
// the same, but they're separate type hierarchies.
//
// Clustering keys are further divided into prefixed and non-prefixed (full).
// Non-prefixed keys always have full component set, as defined by schema.
// Prefixed ones can have any number of trailing components missing. They may
// differ in underlying representation.
//
// The main classes are:
//
//   partition_key           - full partition key
//   clustering_key          - full clustering key
//   clustering_key_prefix   - clustering key prefix
//
// These classes wrap only the minimum information required to store the key
// (the key value itself). Any information which can be inferred from schema
// is not stored. Therefore accessors need to be provided with a pointer to
// schema, from which information about structure is extracted.

class partition_key;
class clustering_key;
class clustering_key_prefix;

// Abstracts serialized tuple, managed by tuple_type.
template <typename TopLevel>
class tuple_wrapper {
protected:
    bytes _bytes;
protected:
    tuple_wrapper(bytes&& b) : _bytes(std::move(b)) {}

    static inline auto get_tuple_type(const schema& s) {
        return TopLevel::get_tuple_type(s);
    }
public:
    static TopLevel make_empty(const schema& s) {
        std::vector<bytes> v;
        v.resize(get_tuple_type(s)->types().size());
        return from_exploded(s, v);
    }

    static TopLevel from_exploded(const schema& s, const std::vector<bytes>& v) {
        return TopLevel::from_bytes(get_tuple_type(s)->serialize_value(v));
    }

    static TopLevel from_exploded(const schema& s, std::vector<bytes>&& v) {
        return TopLevel::from_bytes(get_tuple_type(s)->serialize_value(std::move(v)));
    }

    // We don't allow optional values, but provide this method as an efficient adaptor
    static TopLevel from_optional_exploded(const schema& s, const std::vector<bytes_opt>& v) {
        return TopLevel::from_bytes(get_tuple_type(s)->serialize_optionals(v));
    }

    static TopLevel from_deeply_exploded(const schema& s, const std::vector<boost::any>& v) {
        return TopLevel::from_bytes(get_tuple_type(s)->serialize_value_deep(v));
    }

    static TopLevel from_single_value(const schema& s, bytes v) {
        return TopLevel::from_bytes(get_tuple_type(s)->serialize_single(std::move(v)));
    }

    // FIXME: return views
    std::vector<bytes> explode(const schema& s) const {
        return get_tuple_type(s)->deserialize_value(_bytes);
    }

    struct less_compare {
        typename TopLevel::tuple _t;
        less_compare(const schema& s) : _t(get_tuple_type(s)) {}
        bool operator()(const TopLevel& k1, const TopLevel& k2) const {
            return _t->less(k1, k2);
        }
    };

    struct hashing {
        typename TopLevel::tuple _t;
        hashing(const schema& s) : _t(get_tuple_type(s)) {}
        size_t operator()(const TopLevel& o) const {
            return _t->hash(o);
        }
    };

    struct equality {
        typename TopLevel::tuple _t;
        equality(const schema& s) : _t(get_tuple_type(s)) {}
        bool operator()(const TopLevel& o1, const TopLevel& o2) const {
            return _t->equal(o1, o2);
        }
    };

    bool equal(const schema& s, const TopLevel& other) const {
        return get_tuple_type(s)->equal(*this, other);
    }

    operator bytes_view() const {
        return _bytes;
    }
};

template <typename TopLevel, typename PrefixTopLevel>
class prefix_view_on_full_tuple {
public:
    using iterator = typename tuple_type<allow_prefixes::no>::iterator;
private:
    bytes_view _b;
    unsigned _prefix_len;
    iterator _begin;
    iterator _end;
public:
    prefix_view_on_full_tuple(const schema& s, bytes_view b, unsigned prefix_len)
        : _b(b)
        , _prefix_len(prefix_len)
        , _begin(TopLevel::get_tuple_type(s)->begin(_b))
        , _end(_begin)
    {
        std::advance(_end, prefix_len);
    }

    iterator begin() const { return _begin; }
    iterator end() const { return _end; }

    struct less_compare_with_prefix {
        typename PrefixTopLevel::tuple prefix_type;

        less_compare_with_prefix(const schema& s)
            : prefix_type(PrefixTopLevel::get_tuple_type(s))
        { }

        bool operator()(const prefix_view_on_full_tuple& k1, const PrefixTopLevel& k2) const {
            return lexicographical_tri_compare(
                prefix_type->types().begin(), prefix_type->types().end(),
                k1.begin(), k1.end(),
                prefix_type->begin(k2), prefix_type->end(k2),
                tri_compare) < 0;
        }

        bool operator()(const PrefixTopLevel& k1, const prefix_view_on_full_tuple& k2) const {
            return lexicographical_tri_compare(
                prefix_type->types().begin(), prefix_type->types().end(),
                prefix_type->begin(k1), prefix_type->end(k1),
                k2.begin(), k2.end(),
                tri_compare) < 0;
        }
    };
};

template <typename TopLevel, typename PrefixTopLevel>
class prefixable_full_tuple : public tuple_wrapper<TopLevel> {
    using base = tuple_wrapper<TopLevel>;
protected:
    prefixable_full_tuple(bytes&& b) : base(std::move(b)) {}
public:
    using prefix_view_type = prefix_view_on_full_tuple<TopLevel, PrefixTopLevel>;

    bool is_prefixed_by(const schema& s, const PrefixTopLevel& prefix) const {
        auto t = base::get_tuple_type(s);
        auto prefix_type = PrefixTopLevel::get_tuple_type(s);
        return ::is_prefixed_by(t->types().begin(),
            t->begin(*this), t->end(*this),
            prefix_type->begin(prefix), prefix_type->end(prefix),
            ::equal);
    }

    struct less_compare_with_prefix {
        typename PrefixTopLevel::tuple prefix_type;
        typename TopLevel::tuple full_type;

        less_compare_with_prefix(const schema& s)
            : prefix_type(PrefixTopLevel::get_tuple_type(s))
            , full_type(TopLevel::get_tuple_type(s))
        { }

        bool operator()(const TopLevel& k1, const PrefixTopLevel& k2) const {
            return lexicographical_tri_compare(
                prefix_type->types().begin(), prefix_type->types().end(),
                full_type->begin(k1), full_type->end(k1),
                prefix_type->begin(k2), prefix_type->end(k2),
                tri_compare) < 0;
        }

        bool operator()(const PrefixTopLevel& k1, const TopLevel& k2) const {
            return lexicographical_tri_compare(
                prefix_type->types().begin(), prefix_type->types().end(),
                prefix_type->begin(k1), prefix_type->end(k1),
                full_type->begin(k2), full_type->end(k2),
                tri_compare) < 0;
        }
    };

    // In prefix equality two sequences are equal if any of them is a prefix
    // of the other. Otherwise lexicographical ordering is applied.
    // Note: full tuples sorted according to lexicographical ordering are also
    // sorted according to prefix equality ordering.
    struct prefix_equality_less_compare {
        typename PrefixTopLevel::tuple prefix_type;
        typename TopLevel::tuple full_type;

        prefix_equality_less_compare(const schema& s)
            : prefix_type(PrefixTopLevel::get_tuple_type(s))
            , full_type(TopLevel::get_tuple_type(s))
        { }

        bool operator()(const TopLevel& k1, const PrefixTopLevel& k2) const {
            return prefix_equality_tri_compare(prefix_type->types().begin(),
                full_type->begin(k1), full_type->end(k1),
                prefix_type->begin(k2), prefix_type->end(k2),
                tri_compare) < 0;
        }

        bool operator()(const PrefixTopLevel& k1, const TopLevel& k2) const {
            return prefix_equality_tri_compare(prefix_type->types().begin(),
                prefix_type->begin(k1), prefix_type->end(k1),
                full_type->begin(k2), full_type->end(k2),
                tri_compare) < 0;
        }
    };

    auto prefix_view(const schema& s, unsigned prefix_len) const {
        return prefix_view_type(s, *this, prefix_len);
    }
};

template <typename TopLevel, typename FullTopLevel>
class prefix_tuple_wrapper : public tuple_wrapper<TopLevel> {
    using base = tuple_wrapper<TopLevel>;
protected:
    prefix_tuple_wrapper(bytes&& b) : base(std::move(b)) {}
public:
    bool is_full(const schema& s) const {
        return TopLevel::get_tuple_type(s)->is_full(base::_bytes);
    }

    // Can be called only if is_full()
    FullTopLevel to_full(const schema& s) const {
        return FullTopLevel::from_exploded(s, base::explode(s));
    }

    bool is_prefixed_by(const schema& s, const TopLevel& prefix) const {
        auto t = base::get_tuple_type(s);
        return ::is_prefixed_by(t->types().begin(),
            t->begin(*this), t->end(*this),
            t->begin(prefix), t->end(prefix),
            equal);
    }
};

class partition_key : public tuple_wrapper<partition_key> {
public:
    partition_key(bytes&& b) : tuple_wrapper<partition_key>(std::move(b)) {}
public:
    using tuple = lw_shared_ptr<tuple_type<allow_prefixes::no>>;

    static partition_key from_bytes(bytes b) {
        return partition_key(std::move(b));
    }

    static const tuple& get_tuple_type(const schema& s) {
        return s.partition_key_type;
    }
};

class exploded_clustering_prefix {
    std::vector<bytes> _v;
public:
    exploded_clustering_prefix(std::vector<bytes>&& v) : _v(std::move(v)) {}
    exploded_clustering_prefix() {}
    size_t size() const {
        return _v.size();
    }
    auto const& components() const {
        return _v;
    }
    explicit operator bool() const {
        return !_v.empty();
    }
    bool is_full(const schema& s) const {
        return _v.size() == s.clustering_key_size();
    }
    friend std::ostream& operator<<(std::ostream& os, const exploded_clustering_prefix& ecp);
};

class clustering_key : public prefixable_full_tuple<clustering_key, clustering_key_prefix> {
public:
    clustering_key(bytes&& b) : prefixable_full_tuple<clustering_key, clustering_key_prefix>(std::move(b)) {}
public:
    using tuple = lw_shared_ptr<tuple_type<allow_prefixes::no>>;

    static clustering_key from_bytes(bytes b) {
        return clustering_key(std::move(b));
    }

    static const tuple& get_tuple_type(const schema& s) {
        return s.clustering_key_type;
    }

    static clustering_key from_clustering_prefix(const schema& s, const exploded_clustering_prefix& prefix) {
        assert(prefix.is_full(s));
        return from_exploded(s, prefix.components());
    }
};

class clustering_key_prefix : public prefix_tuple_wrapper<clustering_key_prefix, clustering_key> {
    clustering_key_prefix(bytes&& b) : prefix_tuple_wrapper<clustering_key_prefix, clustering_key>(std::move(b)) {}
public:
    using tuple = lw_shared_ptr<tuple_type<allow_prefixes::yes>>;

    static clustering_key_prefix from_bytes(bytes b) {
        return clustering_key_prefix(std::move(b));
    }

    static const tuple& get_tuple_type(const schema& s) {
        return s.clustering_key_prefix_type;
    }

    static clustering_key_prefix from_clustering_prefix(const schema& s, const exploded_clustering_prefix& prefix) {
        return from_exploded(s, prefix.components());
    }
};

static inline
std::ostream& operator<<(std::ostream& out, const partition_key& pk) {
    return out << "pk{" << to_hex(pk) << "}";
}

static inline
std::ostream& operator<<(std::ostream& out, const clustering_key& ck) {
    return out << "ck{" << to_hex(ck) << "}";
}

static inline
std::ostream& operator<<(std::ostream& out, const clustering_key_prefix& ckp) {
    return out << "ckp{" << to_hex(ckp) << "}";
}
<|endoftext|>


<commit_before>//Fork standard library

#include "lib.h"

//extern "C" disables C++ name mangling

//Never garble writing to the output stream
std::mutex print_mutex;
std::mutex malloc_mutex;

//Parallism data structures
int64_t thread_count = 0;
int64_t max_threads = 0;
std::map<int,std::future<int64_t>> int_future_id_map;
std::map<int,std::future<double>> float_future_id_map;
std::map<int,std::future<int64_t*>> intptr_future_id_map;
std::map<int,std::future<double*>> floatptr_future_id_map;
std::map<int,std::future<void>> void_future_id_map;
std::mutex thread_count_mutex;
std::mutex map_mutex;

//Public-facing standard library functions
//Note that cmath functions (Ex: sin, cos) are available as well

extern "C" void print_int(int64_t i) {
  print_mutex.lock();
  printf("Outputing Integer: %d\n",(int)i);
  print_mutex.unlock();
}

extern "C" void print_float(double d) {
  print_mutex.lock();
  printf("Outputing Float: %f\n",d);
  print_mutex.unlock();
}

extern "C" float* malloc_float(int64_t s) {
  malloc_mutex.lock();
  float* allocd = (float*)malloc(s*8);
  malloc_mutex.unlock();
  return allocd;
}

extern "C" int64_t* malloc_int(int64_t s) {
  malloc_mutex.lock();
  int64_t* allocd = (int64_t*)malloc(s*8);
  malloc_mutex.unlock();
  return allocd;
}

extern "C" float* calloc_float(int64_t s) {
  malloc_mutex.lock();
  float* allocd = (float*)calloc(s,8);
  malloc_mutex.unlock();
  return allocd;
}

extern "C" int64_t* calloc_int(int64_t s) {
  malloc_mutex.lock();
  int64_t* allocd = (int64_t*)calloc(s,8);
  malloc_mutex.unlock();
  return allocd;
}

extern "C" void free_float(float* f) {
  malloc_mutex.lock();
  free(f);
  malloc_mutex.unlock();
}

extern "C" void free_int(int64_t* i) {
  malloc_mutex.lock();
  free(i);
  malloc_mutex.unlock();
}

//Hidden funcitons implement parallism
//They are not intended to be called by user code

void set_max_threads() {
  if (max_threads) return;
  unsigned long dth = std::thread::hardware_concurrency();
  printf("Detected %d compute elements.\n",(int)dth);
  if (dth < 1) max_threads = 1;
  else if (dth > 4) max_threads = 4;
  else max_threads = dth;
  printf("Setting max_threads = %d\n",(int)max_threads);
}

extern "C"  void __fork_sched_int(int64_t (*statement)(void),int64_t id) {
  set_max_threads();
  std::future<int64_t> promise;
  thread_count_mutex.lock();
  if (thread_count >= max_threads) {
    thread_count_mutex.unlock();
    promise = std::async(std::launch::deferred,statement);
  } else {
    promise = std::async(std::launch::async,statement);
    thread_count++;
    thread_count_mutex.unlock();
  }
  map_mutex.lock();
  int_future_id_map.insert(std::pair<int64_t,std::future<int64_t>>(id,std::move(promise)));
  map_mutex.unlock();
}

extern "C"  void __fork_sched_float(double (*statement)(void),int64_t id) {
  set_max_threads();
  std::future<double> promise;
  thread_count_mutex.lock();
  if (thread_count >= max_threads) {
    thread_count_mutex.unlock();
    promise = std::async(std::launch::deferred,statement);
  } else {
    promise = std::async(std::launch::async,statement);
    thread_count++;
    thread_count_mutex.unlock();
  }
  map_mutex.lock();
  float_future_id_map.insert(std::pair<int64_t,std::future<double>>(id,std::move(promise)));
  map_mutex.unlock();
}

extern "C"  void __fork_sched_intptr(int64_t* (*statement)(void),int64_t id) {
  set_max_threads();
  std::future<int64_t*> promise;
  thread_count_mutex.lock();
  if (thread_count >= max_threads) {
    thread_count_mutex.unlock();
    promise = std::async(std::launch::deferred,statement);
  } else {
    promise = std::async(std::launch::async,statement);
    thread_count++;
    thread_count_mutex.unlock();
  }
  map_mutex.lock();
  intptr_future_id_map.insert(std::pair<int64_t,std::future<int64_t*>>(id,std::move(promise)));
  map_mutex.unlock();
}

extern "C"  void __fork_sched_floatptr(double* (*statement)(void),int64_t id) {
  set_max_threads();
  std::future<double*> promise;
  thread_count_mutex.lock();
  if (thread_count >= max_threads) {
    thread_count_mutex.unlock();
    promise = std::async(std::launch::deferred,statement);
  } else {
    promise = std::async(std::launch::async,statement);
    thread_count++;
    thread_count_mutex.unlock();
  }
  map_mutex.lock();
  floatptr_future_id_map.insert(std::pair<int64_t,std::future<double*>>(id,std::move(promise)));
  map_mutex.unlock();
}

extern "C"  void __fork_sched_void(void (*statement)(void),int64_t id) {
  set_max_threads();
  std::future<void> promise;
  thread_count_mutex.lock();
  if (thread_count >= max_threads) {
    thread_count_mutex.unlock();
    promise = std::async(std::launch::deferred,statement);
  } else {
    promise = std::async(std::launch::async,statement);
    thread_count++;
    thread_count_mutex.unlock();
  }
  map_mutex.lock();
  void_future_id_map.insert(std::pair<int64_t,std::future<void>>(id,std::move(promise)));
  map_mutex.unlock();
}

extern "C" int64_t __recon_int(int64_t original,int64_t known,int64_t update,int64_t id,int64_t max) {
  std::chrono::milliseconds span(0);
  map_mutex.lock();
  auto fv = std::move(int_future_id_map.at(id));
  int_future_id_map.erase(id);
  map_mutex.unlock();
  if (fv.wait_for(span)==std::future_status::deferred) {
    return fv.get();
  } else {
    auto v = fv.get();
    thread_count_mutex.lock();
    thread_count--;
    thread_count_mutex.unlock();
    return v;
  }
}

extern "C" double __recon_float(double original,int64_t known,double update,int64_t id,int64_t max) {
  std::chrono::milliseconds span(0);
  map_mutex.lock();
  auto fv = std::move(float_future_id_map.at(id));
  float_future_id_map.erase(id);
  map_mutex.unlock();
  if (fv.wait_for(span)==std::future_status::deferred) {
    return fv.get();
  } else {
    auto v = fv.get();
    thread_count_mutex.lock();
    thread_count--;
    thread_count_mutex.unlock();
    return v;
  }
}

extern "C" int64_t* __recon_intptr(int64_t* original,int64_t known,int64_t* update,int64_t id,int64_t max) {
  std::chrono::milliseconds span(0);
  map_mutex.lock();
  auto fv = std::move(intptr_future_id_map.at(id));
  intptr_future_id_map.erase(id);
  map_mutex.unlock();
  if (fv.wait_for(span)==std::future_status::deferred) {
    return fv.get();
  } else {
    auto v = fv.get();
    thread_count_mutex.lock();
    thread_count--;
    thread_count_mutex.unlock();
    return v;
  }
}

extern "C" double* __recon_floatptr(double* original,int64_t known,double* update,int64_t id,int64_t max) {
  std::chrono::milliseconds span(0);
  map_mutex.lock();
  auto fv = std::move(floatptr_future_id_map.at(id));
  floatptr_future_id_map.erase(id);
  map_mutex.unlock();
  if (fv.wait_for(span)==std::future_status::deferred) {
    return fv.get();
  } else {
    auto v = fv.get();
    thread_count_mutex.lock();
    thread_count--;
    thread_count_mutex.unlock();
    return v;
  }
}

extern "C" void  __recon_void(int64_t id,int64_t max) {
  std::chrono::milliseconds span(0);
  map_mutex.lock();
  auto fv = std::move(void_future_id_map.at(id));
  void_future_id_map.erase(id);
  map_mutex.unlock();
  if (fv.wait_for(span)==std::future_status::deferred) {
    fv.get();
  } else {
    fv.get();
    thread_count_mutex.lock();
    thread_count--;
    thread_count_mutex.unlock();
  }
}

<commit_msg>Better wording, count main thread as a worker as well because we process deferred execution<commit_after>//Fork standard library

#include "lib.h"

//extern "C" disables C++ name mangling

//Never garble writing to the output stream
std::mutex print_mutex;
std::mutex malloc_mutex;

//Parallism data structures
int64_t thread_count = 0;
int64_t max_threads = -1;
std::map<int,std::future<int64_t>> int_future_id_map;
std::map<int,std::future<double>> float_future_id_map;
std::map<int,std::future<int64_t*>> intptr_future_id_map;
std::map<int,std::future<double*>> floatptr_future_id_map;
std::map<int,std::future<void>> void_future_id_map;
std::mutex thread_count_mutex;
std::mutex map_mutex;

//Public-facing standard library functions
//Note that cmath functions (Ex: sin, cos) are available as well

extern "C" void print_int(int64_t i) {
  print_mutex.lock();
  printf("Outputing Integer: %d\n",(int)i);
  print_mutex.unlock();
}

extern "C" void print_float(double d) {
  print_mutex.lock();
  printf("Outputing Float: %f\n",d);
  print_mutex.unlock();
}

extern "C" float* malloc_float(int64_t s) {
  malloc_mutex.lock();
  float* allocd = (float*)malloc(s*8);
  malloc_mutex.unlock();
  return allocd;
}

extern "C" int64_t* malloc_int(int64_t s) {
  malloc_mutex.lock();
  int64_t* allocd = (int64_t*)malloc(s*8);
  malloc_mutex.unlock();
  return allocd;
}

extern "C" float* calloc_float(int64_t s) {
  malloc_mutex.lock();
  float* allocd = (float*)calloc(s,8);
  malloc_mutex.unlock();
  return allocd;
}

extern "C" int64_t* calloc_int(int64_t s) {
  malloc_mutex.lock();
  int64_t* allocd = (int64_t*)calloc(s,8);
  malloc_mutex.unlock();
  return allocd;
}

extern "C" void free_float(float* f) {
  malloc_mutex.lock();
  free(f);
  malloc_mutex.unlock();
}

extern "C" void free_int(int64_t* i) {
  malloc_mutex.lock();
  free(i);
  malloc_mutex.unlock();
}

//Hidden funcitons implement parallism
//They are not intended to be called by user code

void set_max_threads() {
  if (max_threads != -1) return;
  unsigned long dth = std::thread::hardware_concurrency()-1;
  printf("Detected %d additional compute elements.\n",(int)dth);
  if (dth < 0) max_threads = 0;
  else if (dth > 3) max_threads = 3;
  else max_threads = dth;
  printf("Setting max execution threads = %d\n",(int)max_threads+1);
}

extern "C"  void __fork_sched_int(int64_t (*statement)(void),int64_t id) {
  set_max_threads();
  std::future<int64_t> promise;
  thread_count_mutex.lock();
  if (thread_count >= max_threads) {
    thread_count_mutex.unlock();
    promise = std::async(std::launch::deferred,statement);
  } else {
    promise = std::async(std::launch::async,statement);
    thread_count++;
    thread_count_mutex.unlock();
  }
  map_mutex.lock();
  int_future_id_map.insert(std::pair<int64_t,std::future<int64_t>>(id,std::move(promise)));
  map_mutex.unlock();
}

extern "C"  void __fork_sched_float(double (*statement)(void),int64_t id) {
  set_max_threads();
  std::future<double> promise;
  thread_count_mutex.lock();
  if (thread_count >= max_threads) {
    thread_count_mutex.unlock();
    promise = std::async(std::launch::deferred,statement);
  } else {
    promise = std::async(std::launch::async,statement);
    thread_count++;
    thread_count_mutex.unlock();
  }
  map_mutex.lock();
  float_future_id_map.insert(std::pair<int64_t,std::future<double>>(id,std::move(promise)));
  map_mutex.unlock();
}

extern "C"  void __fork_sched_intptr(int64_t* (*statement)(void),int64_t id) {
  set_max_threads();
  std::future<int64_t*> promise;
  thread_count_mutex.lock();
  if (thread_count >= max_threads) {
    thread_count_mutex.unlock();
    promise = std::async(std::launch::deferred,statement);
  } else {
    promise = std::async(std::launch::async,statement);
    thread_count++;
    thread_count_mutex.unlock();
  }
  map_mutex.lock();
  intptr_future_id_map.insert(std::pair<int64_t,std::future<int64_t*>>(id,std::move(promise)));
  map_mutex.unlock();
}

extern "C"  void __fork_sched_floatptr(double* (*statement)(void),int64_t id) {
  set_max_threads();
  std::future<double*> promise;
  thread_count_mutex.lock();
  if (thread_count >= max_threads) {
    thread_count_mutex.unlock();
    promise = std::async(std::launch::deferred,statement);
  } else {
    promise = std::async(std::launch::async,statement);
    thread_count++;
    thread_count_mutex.unlock();
  }
  map_mutex.lock();
  floatptr_future_id_map.insert(std::pair<int64_t,std::future<double*>>(id,std::move(promise)));
  map_mutex.unlock();
}

extern "C"  void __fork_sched_void(void (*statement)(void),int64_t id) {
  set_max_threads();
  std::future<void> promise;
  thread_count_mutex.lock();
  if (thread_count >= max_threads) {
    thread_count_mutex.unlock();
    promise = std::async(std::launch::deferred,statement);
  } else {
    promise = std::async(std::launch::async,statement);
    thread_count++;
    thread_count_mutex.unlock();
  }
  map_mutex.lock();
  void_future_id_map.insert(std::pair<int64_t,std::future<void>>(id,std::move(promise)));
  map_mutex.unlock();
}

extern "C" int64_t __recon_int(int64_t original,int64_t known,int64_t update,int64_t id,int64_t max) {
  std::chrono::milliseconds span(0);
  map_mutex.lock();
  auto fv = std::move(int_future_id_map.at(id));
  int_future_id_map.erase(id);
  map_mutex.unlock();
  if (fv.wait_for(span)==std::future_status::deferred) {
    return fv.get();
  } else {
    auto v = fv.get();
    thread_count_mutex.lock();
    thread_count--;
    thread_count_mutex.unlock();
    return v;
  }
}

extern "C" double __recon_float(double original,int64_t known,double update,int64_t id,int64_t max) {
  std::chrono::milliseconds span(0);
  map_mutex.lock();
  auto fv = std::move(float_future_id_map.at(id));
  float_future_id_map.erase(id);
  map_mutex.unlock();
  if (fv.wait_for(span)==std::future_status::deferred) {
    return fv.get();
  } else {
    auto v = fv.get();
    thread_count_mutex.lock();
    thread_count--;
    thread_count_mutex.unlock();
    return v;
  }
}

extern "C" int64_t* __recon_intptr(int64_t* original,int64_t known,int64_t* update,int64_t id,int64_t max) {
  std::chrono::milliseconds span(0);
  map_mutex.lock();
  auto fv = std::move(intptr_future_id_map.at(id));
  intptr_future_id_map.erase(id);
  map_mutex.unlock();
  if (fv.wait_for(span)==std::future_status::deferred) {
    return fv.get();
  } else {
    auto v = fv.get();
    thread_count_mutex.lock();
    thread_count--;
    thread_count_mutex.unlock();
    return v;
  }
}

extern "C" double* __recon_floatptr(double* original,int64_t known,double* update,int64_t id,int64_t max) {
  std::chrono::milliseconds span(0);
  map_mutex.lock();
  auto fv = std::move(floatptr_future_id_map.at(id));
  floatptr_future_id_map.erase(id);
  map_mutex.unlock();
  if (fv.wait_for(span)==std::future_status::deferred) {
    return fv.get();
  } else {
    auto v = fv.get();
    thread_count_mutex.lock();
    thread_count--;
    thread_count_mutex.unlock();
    return v;
  }
}

extern "C" void  __recon_void(int64_t id,int64_t max) {
  std::chrono::milliseconds span(0);
  map_mutex.lock();
  auto fv = std::move(void_future_id_map.at(id));
  void_future_id_map.erase(id);
  map_mutex.unlock();
  if (fv.wait_for(span)==std::future_status::deferred) {
    fv.get();
  } else {
    fv.get();
    thread_count_mutex.lock();
    thread_count--;
    thread_count_mutex.unlock();
  }
}

<|endoftext|>


<commit_before>// Very messy hack to get the defines for different bio operations. Should be
// changed to something more palatable if possible.
#include <linux/blk_types.h>

#include <cassert>
#include <cstring>

#include <fstream>
#include <ios>
#include <iostream>
#include <memory>
#include <random>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

#include "utils.h"

namespace fs_testing {
namespace utils {
using std::endl;
using std::ifstream;
using std::ios;
using std::memcpy;
using std::mt19937;
using std::ofstream;
using std::ostream;
using std::pair;
using std::shared_ptr;
using std::tie;
using std::uniform_int_distribution;
using std::vector;

bool disk_write::is_async_write() {
  return (
      !((metadata.bi_rw & REQ_SYNC) ||
        (metadata.bi_rw & REQ_FUA) ||
        (metadata.bi_rw & REQ_FLUSH) ||
        (metadata.bi_rw & REQ_FLUSH_SEQ) ||
        (metadata.bi_rw & REQ_SOFTBARRIER)) &&
        metadata.bi_rw & REQ_WRITE);
}

bool disk_write::is_barrier_write() {
  return (
      ((metadata.bi_rw & REQ_FUA) ||
        (metadata.bi_rw & REQ_FLUSH) ||
        (metadata.bi_rw & REQ_FLUSH_SEQ) ||
        (metadata.bi_rw & REQ_SOFTBARRIER)) &&
        metadata.bi_rw & REQ_WRITE);
}

bool disk_write::is_meta() {
  return (metadata.bi_rw & REQ_META);
}

disk_write::disk_write(const struct disk_write_op_meta& m,
    const char *d) {
  metadata = m;
  if (metadata.size > 0 && d != NULL) {
    data = shared_ptr<char>(new char[metadata.size]);
    memcpy(data.get(), d, metadata.size);
  }
}

disk_write::disk_write(const disk_write& other) {
  metadata = other.metadata;
  data = other.data;
}

void disk_write::operator=(const disk_write& other) {
  metadata = other.metadata;
  data = other.data;
}

bool operator==(const disk_write& a, const disk_write& b) {
  if (tie(a.metadata.bi_flags, a.metadata.bi_rw, a.metadata.write_sector,
        a.metadata.size) ==
      tie(b.metadata.bi_flags, b.metadata.bi_rw, b.metadata.write_sector,
        b.metadata.size)) {
    if ((a.data.get() == NULL && b.data.get() != NULL) ||
        (a.data.get() != NULL && b.data.get() == NULL)) {
      return false;
    }
    if (memcmp(a.data.get(), b.data.get(), a.metadata.size) == 0) {
      return true;
    }
  }
  return false;
}

bool operator!=(const disk_write& a, const disk_write& b) {
  return !(a == b);
}

void disk_write::serialize(std::ofstream& fs, const disk_write& dw) {
  ios prev_format(NULL);
  prev_format.copyfmt(fs);
  fs << std::hex;
  fs << dw.metadata.bi_flags << " "
    << dw.metadata.bi_rw << " "
    << dw.metadata.write_sector << " "
    << dw.metadata.size << " ";
  char *data = (char *) dw.data.get();
  for (unsigned int i = 0; i < dw.metadata.size; ++i) {
    // TODO(ashmrtn): Change to put?
    fs << *(data + i);
  }
  fs << endl;
  fs.copyfmt(prev_format);
}

// TODO(ashmrtn): Greatly refactor this so that it is much more flexible and
// complete. Think about removing whitespace between fields and just checking
// for newlines? But then what happens if your data is all newlines?
disk_write disk_write::deserialize(ifstream& is) {
  disk_write_op_meta meta;
  ios prev_format(NULL);
  prev_format.copyfmt(is);
  is >> std::skipws;
  is >> std::hex;
  is >> meta.bi_flags
    >> meta.bi_rw
    >> meta.write_sector
    >> meta.size;

  char nl;
  // Eat single space between size of data and data.
  is.get(nl);
  assert(nl == ' ');
  char *data = new char[meta.size];
  is.read(data, meta.size);
  // Make sure that the meta.size field matches the actual data size in the log.
  is.get(nl);
  assert(nl == '\n');
  is.copyfmt(prev_format);
  disk_write res(meta, data);
  delete[] data;
  return res;
}

/*
 * Output all data for a single object on a single line.
 */
ofstream& operator<<(ofstream& fs, const disk_write& dw) {
  fs << dw.metadata.bi_flags << " "
    << dw.metadata.bi_rw << " "
    << dw.metadata.write_sector << " "
    << dw.metadata.size << " "
    << dw.data;
  return fs;
}

ostream& operator<<(ostream& os, const disk_write& dw) {
  os << std::hex << std::showbase << dw.metadata.bi_rw << std::noshowbase
    << std::dec;
  return os;
}

bool disk_write::has_write_flag() {
  return metadata.bi_rw & REQ_WRITE;
}

shared_ptr<char> disk_write::set_data(const char *d) {
  if (metadata.size > 0 && d != NULL) {
    data = shared_ptr<char>(new char[metadata.size]);
    memcpy(data.get(), d, metadata.size);
  }
  return data;
}

shared_ptr<char> disk_write::get_data() {
  return data;
}

}  // namespace utils
}  // namespace fs_testing
<commit_msg>Fix shared_ptr delete memory leak.<commit_after>// Very messy hack to get the defines for different bio operations. Should be
// changed to something more palatable if possible.
#include <linux/blk_types.h>

#include <cassert>
#include <cstring>

#include <fstream>
#include <ios>
#include <iostream>
#include <memory>
#include <random>
#include <string>
#include <tuple>
#include <utility>
#include <vector>

#include "utils.h"

namespace fs_testing {
namespace utils {
using std::endl;
using std::ifstream;
using std::ios;
using std::memcpy;
using std::mt19937;
using std::ofstream;
using std::ostream;
using std::pair;
using std::shared_ptr;
using std::tie;
using std::uniform_int_distribution;
using std::vector;

bool disk_write::is_async_write() {
  return (
      !((metadata.bi_rw & REQ_SYNC) ||
        (metadata.bi_rw & REQ_FUA) ||
        (metadata.bi_rw & REQ_FLUSH) ||
        (metadata.bi_rw & REQ_FLUSH_SEQ) ||
        (metadata.bi_rw & REQ_SOFTBARRIER)) &&
        metadata.bi_rw & REQ_WRITE);
}

bool disk_write::is_barrier_write() {
  return (
      ((metadata.bi_rw & REQ_FUA) ||
        (metadata.bi_rw & REQ_FLUSH) ||
        (metadata.bi_rw & REQ_FLUSH_SEQ) ||
        (metadata.bi_rw & REQ_SOFTBARRIER)) &&
        metadata.bi_rw & REQ_WRITE);
}

bool disk_write::is_meta() {
  return (metadata.bi_rw & REQ_META);
}

disk_write::disk_write(const struct disk_write_op_meta& m,
    const char *d) {
  metadata = m;
  if (metadata.size > 0 && d != NULL) {
    data = shared_ptr<char>(new char[metadata.size],
        [](char* c) {delete[] c;});
    memcpy(data.get(), d, metadata.size);
  }
}

disk_write::disk_write(const disk_write& other) {
  metadata = other.metadata;
  data = other.data;
}

void disk_write::operator=(const disk_write& other) {
  metadata = other.metadata;
  data = other.data;
}

bool operator==(const disk_write& a, const disk_write& b) {
  if (tie(a.metadata.bi_flags, a.metadata.bi_rw, a.metadata.write_sector,
        a.metadata.size) ==
      tie(b.metadata.bi_flags, b.metadata.bi_rw, b.metadata.write_sector,
        b.metadata.size)) {
    if ((a.data.get() == NULL && b.data.get() != NULL) ||
        (a.data.get() != NULL && b.data.get() == NULL)) {
      return false;
    }
    if (memcmp(a.data.get(), b.data.get(), a.metadata.size) == 0) {
      return true;
    }
  }
  return false;
}

bool operator!=(const disk_write& a, const disk_write& b) {
  return !(a == b);
}

void disk_write::serialize(std::ofstream& fs, const disk_write& dw) {
  ios prev_format(NULL);
  prev_format.copyfmt(fs);
  fs << std::hex;
  fs << dw.metadata.bi_flags << " "
    << dw.metadata.bi_rw << " "
    << dw.metadata.write_sector << " "
    << dw.metadata.size << " ";
  char *data = (char *) dw.data.get();
  for (unsigned int i = 0; i < dw.metadata.size; ++i) {
    // TODO(ashmrtn): Change to put?
    fs << *(data + i);
  }
  fs << endl;
  fs.copyfmt(prev_format);
}

// TODO(ashmrtn): Greatly refactor this so that it is much more flexible and
// complete. Think about removing whitespace between fields and just checking
// for newlines? But then what happens if your data is all newlines?
disk_write disk_write::deserialize(ifstream& is) {
  disk_write_op_meta meta;
  ios prev_format(NULL);
  prev_format.copyfmt(is);
  is >> std::skipws;
  is >> std::hex;
  is >> meta.bi_flags
    >> meta.bi_rw
    >> meta.write_sector
    >> meta.size;

  char nl;
  // Eat single space between size of data and data.
  is.get(nl);
  assert(nl == ' ');
  char *data = new char[meta.size];
  is.read(data, meta.size);
  // Make sure that the meta.size field matches the actual data size in the log.
  is.get(nl);
  assert(nl == '\n');
  is.copyfmt(prev_format);
  disk_write res(meta, data);
  delete[] data;
  return res;
}

/*
 * Output all data for a single object on a single line.
 */
ofstream& operator<<(ofstream& fs, const disk_write& dw) {
  fs << dw.metadata.bi_flags << " "
    << dw.metadata.bi_rw << " "
    << dw.metadata.write_sector << " "
    << dw.metadata.size << " "
    << dw.data;
  return fs;
}

ostream& operator<<(ostream& os, const disk_write& dw) {
  os << std::hex << std::showbase << dw.metadata.bi_rw << std::noshowbase
    << std::dec;
  return os;
}

bool disk_write::has_write_flag() {
  return metadata.bi_rw & REQ_WRITE;
}

shared_ptr<char> disk_write::set_data(const char *d) {
  if (metadata.size > 0 && d != NULL) {
    data = shared_ptr<char>(new char[metadata.size]);
    memcpy(data.get(), d, metadata.size);
  }
  return data;
}

shared_ptr<char> disk_write::get_data() {
  return data;
}

}  // namespace utils
}  // namespace fs_testing
<|endoftext|>


<commit_before>#include "constants.h"
// bullet
#include "btBulletDynamicsCommon.h"
#include <osg/Array>

// http://stackoverflow.com/questions/3681140/how-do-i-avoid-both-global-variables-and-magic-numbers

namespace troen
{
	// GENERAL

	// GAME
	const int DEFAULT_WINDOW_WIDTH(1024);
	const int DEFAULT_WINDOW_HEIGHT(768);
	const float DEFAULT_SOUND_VOLUME(1.f);

	const float FOVY_INITIAL(29.1484f);
	const float FOVY_ADDITION_MAX(30.f);
	const float FOVY_DELTA_MAX(.7f);

	const int NUM_MULTISAMPLES(8);

	// LOGIC
	const double RESPAWN_DURATION(3000);
	const double GAME_START_COUNTDOWN_DURATION(3000);

	//PHYSIS
	const btVector3 DEFAULT_GRAVITY(0,0,-98);

	// BIKE
	const btVector3 BIKE_DIMENSIONS(2, 4, 2);
	const float BIKE_VIEW_SCALE_FACTOR(1.f / 5.f * BIKE_DIMENSIONS.y());
	const osg::Vec3f BIKE_VIEW_SCALE_FACTORS(BIKE_VIEW_SCALE_FACTOR, BIKE_VIEW_SCALE_FACTOR, BIKE_VIEW_SCALE_FACTOR);
	const osg::Vec3f BIKE_VIEW_TRANSLATE_VALUES(0,0,-BIKE_DIMENSIONS.z() * 4.9f / 12.5);

	const float BIKE_MASS(300);
	const int BIKE_VELOCITY_MAX(BIKE_DIMENSIONS.y() * 90);
	const int BIKE_VELOCITY_MIN(BIKE_DIMENSIONS.y() * 30);
	const float BIKE_VELOCITY_DAMPENING_TERM(.3f);
	const float BIKE_ACCELERATION_FACTOR_MAX(1.5f);
	const float BIKE_DECELERATION_FACTOR(4.f);
	const float BIKE_TURN_FACTOR_MAX(15);
	const float BIKE_ANGULAR_DAMPENING_TERM(0.001f);

	const float TURBO_PHASE_LENGTH(1000);

	// BIKE_TILT_DAMPENING = 1 would lead to immediate/unsmooth tilt
	// 1 / BIKE_TILT_MAX specifies angle in radiant
	const float BIKE_TILT_DAMPENING(20.f);
	const float BIKE_TILT_MAX(16.f);
	const float BIKE_WHEELY_TILT_MAX(2.f);
	const float THRESHOLD_FOR_ABRUPT_VELOCITY_CHANGE(20.f);

	//INPUT
	const float BIKE_ROTATION_VALUE(10.0f);
	const float BIKE_HANDBRAKE_FACTOR(0.8f);
	// this should always be less than 1000/60FPS - the smaller, the more responsive is the input
	const int POLLING_DELAY_MS(8);
	const int VIBRATION_TIME_MS(500);

	// FENCE
	// determines how accurate the fence will be
	const float FENCE_HEIGHT_MODEL(BIKE_DIMENSIONS.x() * 1.5f);
	const float FENCE_HEIGHT_VIEW(FENCE_HEIGHT_MODEL * .7f);
	const float FENCE_PART_LENGTH(BIKE_DIMENSIONS.y() / 2);
	const float FENCE_PART_WIDTH(BIKE_DIMENSIONS.x() * .3f);
	const int DEFAULT_MAX_FENCE_PARTS(400);

	// CAMERA
	const osg::Vec3 CAMERA_POSITION_OFFSET(0, 0, BIKE_DIMENSIONS.y());
	const float CAMERA_ROTATION_OFFSET(.05f);
	const osg::Vec3 CAMERA_EYE_POSITION(0.f,-BIKE_DIMENSIONS.y()*5.5f,BIKE_DIMENSIONS.z()*.8f);
	const float CAMERA_TILT_FACTOR(16.f);
	const int HUD_PROJECTION_SIZE(1000);

	const unsigned int CAMERA_MASK_MAIN(0x1);
	const unsigned int CAMERA_MASK_RADAR(0x2);

	// PHYSICS
	const float BIKE_FENCE_IMPACT_THRESHOLD_LOW(BIKE_MASS*BIKE_VELOCITY_MIN);
	const float BIKE_FENCE_IMPACT_THRESHOLD_HIGH(BIKE_MASS*BIKE_VELOCITY_MAX / 3);

	const float BIKE_DEFAULT_HEALTH(5 * BIKE_FENCE_IMPACT_THRESHOLD_HIGH);

	// AUDIO
	const int ENGINE_FREQUENCY_LOW(50000);
	const int ENGINE_FREQUENCY_HIGH(120000);

}<commit_msg>fixes #43 increased camera tilting<commit_after>#include "constants.h"
// bullet
#include "btBulletDynamicsCommon.h"
#include <osg/Array>

// http://stackoverflow.com/questions/3681140/how-do-i-avoid-both-global-variables-and-magic-numbers

namespace troen
{
	// GENERAL

	// GAME
	const int DEFAULT_WINDOW_WIDTH(1024);
	const int DEFAULT_WINDOW_HEIGHT(768);
	const float DEFAULT_SOUND_VOLUME(1.f);

	const float FOVY_INITIAL(29.1484f);
	const float FOVY_ADDITION_MAX(30.f);
	const float FOVY_DELTA_MAX(.7f);

	const int NUM_MULTISAMPLES(8);

	// LOGIC
	const double RESPAWN_DURATION(3000);
	const double GAME_START_COUNTDOWN_DURATION(3000);

	//PHYSIS
	const btVector3 DEFAULT_GRAVITY(0,0,-98);

	// BIKE
	const btVector3 BIKE_DIMENSIONS(2, 4, 2);
	const float BIKE_VIEW_SCALE_FACTOR(1.f / 5.f * BIKE_DIMENSIONS.y());
	const osg::Vec3f BIKE_VIEW_SCALE_FACTORS(BIKE_VIEW_SCALE_FACTOR, BIKE_VIEW_SCALE_FACTOR, BIKE_VIEW_SCALE_FACTOR);
	const osg::Vec3f BIKE_VIEW_TRANSLATE_VALUES(0,0,-BIKE_DIMENSIONS.z() * 4.9f / 12.5);

	const float BIKE_MASS(300);
	const int BIKE_VELOCITY_MAX(BIKE_DIMENSIONS.y() * 90);
	const int BIKE_VELOCITY_MIN(BIKE_DIMENSIONS.y() * 30);
	const float BIKE_VELOCITY_DAMPENING_TERM(.3f);
	const float BIKE_ACCELERATION_FACTOR_MAX(1.5f);
	const float BIKE_DECELERATION_FACTOR(4.f);
	const float BIKE_TURN_FACTOR_MAX(15);
	const float BIKE_ANGULAR_DAMPENING_TERM(0.001f);

	const float TURBO_PHASE_LENGTH(1000);

	// BIKE_TILT_DAMPENING = 1 would lead to immediate/unsmooth tilt
	// 1 / BIKE_TILT_MAX specifies angle in radiant
	const float BIKE_TILT_DAMPENING(20.f);
	const float BIKE_TILT_MAX(16.f);
	const float BIKE_WHEELY_TILT_MAX(2.f);
	const float THRESHOLD_FOR_ABRUPT_VELOCITY_CHANGE(20.f);

	//INPUT
	const float BIKE_ROTATION_VALUE(10.0f);
	const float BIKE_HANDBRAKE_FACTOR(0.8f);
	// this should always be less than 1000/60FPS - the smaller, the more responsive is the input
	const int POLLING_DELAY_MS(8);
	const int VIBRATION_TIME_MS(500);

	// FENCE
	// determines how accurate the fence will be
	const float FENCE_HEIGHT_MODEL(BIKE_DIMENSIONS.x() * 1.5f);
	const float FENCE_HEIGHT_VIEW(FENCE_HEIGHT_MODEL * .7f);
	const float FENCE_PART_LENGTH(BIKE_DIMENSIONS.y() / 2);
	const float FENCE_PART_WIDTH(BIKE_DIMENSIONS.x() * .3f);
	const int DEFAULT_MAX_FENCE_PARTS(400);

	// CAMERA
	const osg::Vec3 CAMERA_POSITION_OFFSET(0, 0, BIKE_DIMENSIONS.y());
	const float CAMERA_ROTATION_OFFSET(.05f);
	const osg::Vec3 CAMERA_EYE_POSITION(0.f,-BIKE_DIMENSIONS.y()*5.5f,BIKE_DIMENSIONS.z()*.8f);
	const float CAMERA_TILT_FACTOR(4.f);
	const int HUD_PROJECTION_SIZE(1000);

	const unsigned int CAMERA_MASK_MAIN(0x1);
	const unsigned int CAMERA_MASK_RADAR(0x2);

	// PHYSICS
	const float BIKE_FENCE_IMPACT_THRESHOLD_LOW(BIKE_MASS*BIKE_VELOCITY_MIN);
	const float BIKE_FENCE_IMPACT_THRESHOLD_HIGH(BIKE_MASS*BIKE_VELOCITY_MAX / 3);

	const float BIKE_DEFAULT_HEALTH(5 * BIKE_FENCE_IMPACT_THRESHOLD_HIGH);

	// AUDIO
	const int ENGINE_FREQUENCY_LOW(50000);
	const int ENGINE_FREQUENCY_HIGH(120000);

}<|endoftext|>


<commit_before><commit_msg>Revert "Measure: Don't use kdebug_signpost on Travis CI"<commit_after><|endoftext|>


<commit_before>#include <iostream>
#include <fstream>
#include <string>
#include "include/dir.h"
#include "include/generator.h"

using namespace std;

//main program
int main()
{
  fstream cfgfile;
  cfgfile.open("./testgen.cfg");
  if(!cfgfile.is_open())
  {
    cfgfile.open("./testgen.cfg", ios::out);
    cout << "config not found, generating config file testgen.cfg."<<endl<<"Set your templates folder and adjust the other settings" << endl;
    cfgfile << "./templates" << endl << "/tmp" << endl << "/tmp/savedtests" << endl<< "latexmk -f -pdf" << endl << "evince" << endl;
    cfgfile.close();
    return 0;
  }
  string sTemplatesPath, sTempPath, sMake, sShow, sSaveBasePath;
  getline(cfgfile,sTemplatesPath);
  getline(cfgfile,sTempPath);
  getline(cfgfile,sSaveBasePath);
  MyDir::createDir(sSaveBasePath);
  getline(cfgfile,sMake);
  getline(cfgfile,sShow);
  MyDir::dirlist _dirlist;
  _dirlist=MyDir::getAllSubdirs(sTemplatesPath);

  cout << "available subjects:" << endl;
  for(int i=0;i<_dirlist.size();i++)
  {
    cout << i+1 << ": " <<_dirlist[i] << endl;
  }
  int iSelect;
  string sSubject;
  cout << "select test subject number" << endl;
  cin >> iSelect;
  sSubject=_dirlist[iSelect-1];

  _dirlist=MyDir::getAllSubdirs(sTemplatesPath+"/"+sSubject);

  cout << "available classes:" << endl;
  for(int i=0;i<_dirlist.size();i++)
  {
    cout << i+1 << ": " << _dirlist[i] << endl;
  }
  string sClass;
  cout << "select class" << endl;
  cin >> iSelect;
  sClass=_dirlist[iSelect-1];

  _dirlist=MyDir::getAllSubdirs(sTemplatesPath+"/"+sSubject+"/"+sClass);

  string sCName, sTitle, sDate;
  cin.ignore (numeric_limits<std::streamsize>::max(), '\n');//flush for getline
  cout << "Enter class name, e.g. Klasse 5a" << endl;
  getline(cin,sCName);

  cout << "Enter test title, e.g. 1. Schulaufgabe" << endl;
  getline(cin,sTitle);

  cout << "Enter test date" << endl;
  getline(cin,sDate);

  generator *gen=new generator(sTemplatesPath,sTempPath, sMake, sShow,sCName,sTitle, sDate);
  string sBasePath=sTemplatesPath+"/"+sSubject+"/"+sClass;
  gen->showAvailableTests(sBasePath);
  string sSelectedTestNumbers;
  cout << "Enter test numbers to generate new test, seperated my colon"<<endl;
  cin >> sSelectedTestNumbers;
  string sPath;
  cout << "enter save path: " + sSaveBasePath+"/" << endl;
  cin >> sPath;
  while(MyDir::bTestExists(sSaveBasePath + "/" + sPath))
  {
    cout << sSaveBasePath << "/main.tex exists!" << endl;
    cin >> sPath;
  }
  sPath=sSaveBasePath+"/"+sPath;
  gen->generateTestFromSelectionString(sBasePath, sSelectedTestNumbers, sPath);
  return 0;
}

<commit_msg>added preview mode<commit_after>#include <iostream>
#include <fstream>
#include <string>
#include "include/dir.h"
#include "include/generator.h"

using namespace std;

//main program
int main()
{
  fstream cfgfile;
  cfgfile.open("./testgen.cfg");
  if(!cfgfile.is_open())
  {
    cfgfile.open("./testgen.cfg", ios::out);
    cout << "config not found, generating config file testgen.cfg."<<endl<<"Set your templates folder and adjust the other settings" << endl;
    cfgfile << "./templates" << endl << "/tmp" << endl << "/tmp/savedtests" << endl<< "latexmk -f -pdf" << endl << "evince" << endl;
    cfgfile.close();
    return 0;
  }
  string sTemplatesPath, sTempPath, sMake, sShow, sSaveBasePath;
  getline(cfgfile,sTemplatesPath);
  getline(cfgfile,sTempPath);
  getline(cfgfile,sSaveBasePath);
  MyDir::createDir(sSaveBasePath);
  getline(cfgfile,sMake);
  getline(cfgfile,sShow);
  MyDir::dirlist _dirlist;
  _dirlist=MyDir::getAllSubdirs(sTemplatesPath);

  cout << "available subjects:" << endl;
  for(int i=0;i<_dirlist.size();i++)
  {
    cout << i+1 << ": " <<_dirlist[i] << endl;
  }
  int iSelect;
  string sSubject;
  cout << "select test subject number" << endl;
  cin >> iSelect;
  sSubject=_dirlist[iSelect-1];

  _dirlist=MyDir::getAllSubdirs(sTemplatesPath+"/"+sSubject);

  cout << "available classes:" << endl;
  for(int i=0;i<_dirlist.size();i++)
  {
    cout << i+1 << ": " << _dirlist[i] << endl;
  }
  string sClass;
  cout << "select class" << endl;
  cin >> iSelect;
  sClass=_dirlist[iSelect-1];

  _dirlist=MyDir::getAllSubdirs(sTemplatesPath+"/"+sSubject+"/"+sClass);

  string sCName, sTitle, sDate;
  cin.ignore (numeric_limits<std::streamsize>::max(), '\n');//flush for getline
  cout << "Enter class name, e.g. Klasse 5a. Enter '-' for preview mode" << endl;
  getline(cin,sCName);
  bool bPreviewMode=(sCName=="-");
  if(!bPreviewMode)
  {
    cout << "Enter test title, e.g. 1. Schulaufgabe" << endl;
    getline(cin,sTitle);

    cout << "Enter test date" << endl;
    getline(cin,sDate);
  }
  generator *gen=new generator(sTemplatesPath,sTempPath, sMake, sShow,sCName,sTitle, sDate);
  string sBasePath=sTemplatesPath+"/"+sSubject+"/"+sClass;
  gen->showAvailableTests(sBasePath);
  if(bPreviewMode)
    return 0;
  string sSelectedTestNumbers;
  cout << "Enter test numbers to generate new test, seperated my colon"<<endl;
  cin >> sSelectedTestNumbers;
  string sPath;
  cout << "enter save path: " + sSaveBasePath+"/" << endl;
  cin >> sPath;
  while(MyDir::bTestExists(sSaveBasePath + "/" + sPath))
  {
    cout << sSaveBasePath << "/main.tex exists!" << endl;
    cin >> sPath;
  }
  sPath=sSaveBasePath+"/"+sPath;
  gen->generateTestFromSelectionString(sBasePath, sSelectedTestNumbers, sPath);
  return 0;
}

<|endoftext|>


<commit_before>#include "mpdas.h"

CMPD* MPD = 0;

void
CMPD::SetSong(const Song *song)
{
    _cached = false;
	if(song && !song->getArtist().empty() && !song->getTitle().empty()) {
        _song = *song;
		_gotsong = true;
		iprintf("New song: %s - %s", _song.getArtist().c_str(), _song.getTitle().c_str());
        AudioScrobbler->SendNowPlaying(*song);
	}
	else {
		_gotsong = false;
	}
	_starttime = time(NULL);
}

void
CMPD::CheckSubmit(int curplaytime)
{
	if(!_gotsong || _cached || (_song.getArtist().empty() || _song.getTitle().empty())) return;
	if(curplaytime - _start >= 240 || curplaytime - _start >= _song.getDuration()/2) {
		Cache->AddToCache(_song, _starttime);
		_cached = true;
	}
}

CMPD::CMPD()
{
    _conn = NULL;
	_gotsong = false;
	_connected = false;
	_cached = false;
    _songid = -1;
    _songpos = -1;

	if(Connect())
		iprintf("%s", "Connected to MPD.");
	else
		eprintf("%s", "Could not connect to MPD.");
}

CMPD::~CMPD()
{
	if(_conn)
		mpd_connection_free(_conn);
}

bool
CMPD::Connect()
{
    std::cout << _conn;
    if(_conn)
        mpd_connection_free(_conn);

	_conn = mpd_connection_new(Config->getMHost().c_str(), Config->getMPort(), 0);
    _connected = _conn && mpd_connection_get_error(_conn) == MPD_ERROR_SUCCESS;

    if(_connected && Config->getMPassword().size() > 0) {
        _connected &= mpd_run_password(_conn, Config->getMPassword().c_str());
    }

    if(_connected)
        mpd_run_subscribe(_conn, "mpdas");

	return _connected;
}

void
CMPD::GotNewSong(struct mpd_song *song)
{
    Song *s = new Song(song);
    SetSong(s);
    delete s;
}

void
CMPD::Update()
{
	if(!_connected) {
        iprintf("Reconnecting in 10 seconds.");
        sleep(10);
		if(Connect())
            iprintf("%s", "Reconnected!");
        else {
            eprintf("%s", "Could not reconnect.");
            return;
        }
	}

    mpd_status *status = mpd_run_status(_conn);
    mpd_stats *stats = mpd_run_stats(_conn);

    if(status && stats) {
        int newsongid = mpd_status_get_song_id(status);
        int newsongpos = mpd_status_get_elapsed_time(status);
        int curplaytime = mpd_stats_get_play_time(stats);
        mpd_song *song = mpd_run_current_song(_conn);

        // new song
        if(newsongid != _songid) {
            _songid = newsongid;
            _songpos = newsongpos;
            _start = curplaytime;

            if(song) {
                GotNewSong(song);
                mpd_song_free(song);
            }
        }

        // song playing
        if(newsongpos != _songpos) {
            _songpos = newsongpos;
            CheckSubmit(curplaytime);
        }

        // check for client-to-client messages
        if(mpd_send_read_messages(_conn)) {
            mpd_message *msg;
            while((msg = mpd_recv_message(_conn)) != NULL) {
                const char *text = mpd_message_get_text(msg);
                if(_gotsong && text && !strncmp(text, "love", 4))
                    AudioScrobbler->LoveTrack(_song);
                mpd_message_free(msg);
            }
            mpd_response_finish(_conn);
        }

        mpd_status_free(status);
        mpd_stats_free(stats);
    }
    else { // we have most likely lost our connection
        eprintf("Could not query MPD server: %s", mpd_connection_get_error_message(_conn));
        _connected = false;
    }
}

Song::Song(struct mpd_song *song)
{
    const char* temp;

    temp = mpd_song_get_tag(song, MPD_TAG_ARTIST, 0);
    artist = temp ? temp : "";

    temp = mpd_song_get_tag(song, MPD_TAG_TITLE, 0);
    title = temp ? temp : "";

    temp = mpd_song_get_tag(song, MPD_TAG_ALBUM, 0);
    album = temp ? temp : "";

    duration = mpd_song_get_duration(song);
}
<commit_msg>remove debug print leftover<commit_after>#include "mpdas.h"

CMPD* MPD = 0;

void
CMPD::SetSong(const Song *song)
{
    _cached = false;
	if(song && !song->getArtist().empty() && !song->getTitle().empty()) {
        _song = *song;
		_gotsong = true;
		iprintf("New song: %s - %s", _song.getArtist().c_str(), _song.getTitle().c_str());
        AudioScrobbler->SendNowPlaying(*song);
	}
	else {
		_gotsong = false;
	}
	_starttime = time(NULL);
}

void
CMPD::CheckSubmit(int curplaytime)
{
	if(!_gotsong || _cached || (_song.getArtist().empty() || _song.getTitle().empty())) return;
	if(curplaytime - _start >= 240 || curplaytime - _start >= _song.getDuration()/2) {
		Cache->AddToCache(_song, _starttime);
		_cached = true;
	}
}

CMPD::CMPD()
{
    _conn = NULL;
	_gotsong = false;
	_connected = false;
	_cached = false;
    _songid = -1;
    _songpos = -1;

	if(Connect())
		iprintf("%s", "Connected to MPD.");
	else
		eprintf("%s", "Could not connect to MPD.");
}

CMPD::~CMPD()
{
	if(_conn)
		mpd_connection_free(_conn);
}

bool
CMPD::Connect()
{
    if(_conn)
        mpd_connection_free(_conn);

	_conn = mpd_connection_new(Config->getMHost().c_str(), Config->getMPort(), 0);
    _connected = _conn && mpd_connection_get_error(_conn) == MPD_ERROR_SUCCESS;

    if(_connected && Config->getMPassword().size() > 0) {
        _connected &= mpd_run_password(_conn, Config->getMPassword().c_str());
    }

    if(_connected)
        mpd_run_subscribe(_conn, "mpdas");

	return _connected;
}

void
CMPD::GotNewSong(struct mpd_song *song)
{
    Song *s = new Song(song);
    SetSong(s);
    delete s;
}

void
CMPD::Update()
{
	if(!_connected) {
        iprintf("Reconnecting in 10 seconds.");
        sleep(10);
		if(Connect())
            iprintf("%s", "Reconnected!");
        else {
            eprintf("%s", "Could not reconnect.");
            return;
        }
	}

    mpd_status *status = mpd_run_status(_conn);
    mpd_stats *stats = mpd_run_stats(_conn);

    if(status && stats) {
        int newsongid = mpd_status_get_song_id(status);
        int newsongpos = mpd_status_get_elapsed_time(status);
        int curplaytime = mpd_stats_get_play_time(stats);
        mpd_song *song = mpd_run_current_song(_conn);

        // new song
        if(newsongid != _songid) {
            _songid = newsongid;
            _songpos = newsongpos;
            _start = curplaytime;

            if(song) {
                GotNewSong(song);
                mpd_song_free(song);
            }
        }

        // song playing
        if(newsongpos != _songpos) {
            _songpos = newsongpos;
            CheckSubmit(curplaytime);
        }

        // check for client-to-client messages
        if(mpd_send_read_messages(_conn)) {
            mpd_message *msg;
            while((msg = mpd_recv_message(_conn)) != NULL) {
                const char *text = mpd_message_get_text(msg);
                if(_gotsong && text && !strncmp(text, "love", 4))
                    AudioScrobbler->LoveTrack(_song);
                mpd_message_free(msg);
            }
            mpd_response_finish(_conn);
        }

        mpd_status_free(status);
        mpd_stats_free(stats);
    }
    else { // we have most likely lost our connection
        eprintf("Could not query MPD server: %s", mpd_connection_get_error_message(_conn));
        _connected = false;
    }
}

Song::Song(struct mpd_song *song)
{
    const char* temp;

    temp = mpd_song_get_tag(song, MPD_TAG_ARTIST, 0);
    artist = temp ? temp : "";

    temp = mpd_song_get_tag(song, MPD_TAG_TITLE, 0);
    title = temp ? temp : "";

    temp = mpd_song_get_tag(song, MPD_TAG_ALBUM, 0);
    album = temp ? temp : "";

    duration = mpd_song_get_duration(song);
}
<|endoftext|>