<commit_before>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#if defined(_WIN32)
#include <windows.h>
#include <DbgHelp.h>
#endif

#include "qv4stacktrace_p.h"
#include "qv4function_p.h"
#include "qv4engine_p.h"
#include "qv4unwindhelper_p.h"

#if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_MAC)
#define HAVE_GNU_BACKTRACE
#include <execinfo.h>
#endif

QT_BEGIN_NAMESPACE

using namespace QV4;

NativeStackTrace::NativeStackTrace(ExecutionContext *context)
{
    engine = context->engine;
    currentNativeFrame = 0;

#if defined(HAVE_GNU_BACKTRACE)
    UnwindHelper::prepareForUnwind(context);

    nativeFrameCount = backtrace(&trace[0], sizeof(trace) / sizeof(trace[0]));
#elif defined(Q_OS_WIN)

    int machineType = 0;

    CONTEXT winContext;
    memset(&winContext, 0, sizeof(winContext));
    winContext.ContextFlags = CONTEXT_FULL;
    RtlCaptureContext(&winContext);

    STACKFRAME64 sf64;
    memset(&sf64, 0, sizeof(sf64));

#if defined(Q_PROCESSOR_X86_32)
    machineType = IMAGE_FILE_MACHINE_I386;

    sf64.AddrFrame.Offset = winContext.Ebp;
    sf64.AddrFrame.Mode = AddrModeFlat;
    sf64.AddrPC.Offset = winContext.Eip;
    sf64.AddrPC.Mode = AddrModeFlat;
    sf64.AddrStack.Offset = winContext.Esp;
    sf64.AddrStack.Mode = AddrModeFlat;

#elif defined(Q_PROCESSOR_X86_64)
    machineType = IMAGE_FILE_MACHINE_AMD64;

    sf64.AddrFrame.Offset = winContext.Rbp;
    sf64.AddrFrame.Mode = AddrModeFlat;
    sf64.AddrPC.Offset = winContext.Rip;
    sf64.AddrPC.Mode = AddrModeFlat;
    sf64.AddrStack.Offset = winContext.Rsp;
    sf64.AddrStack.Mode = AddrModeFlat;

#else
#error "Platform unsupported!"
#endif

    nativeFrameCount = 0;

    while (StackWalk64(machineType, GetCurrentProcess(), GetCurrentThread(), &sf64, &winContext, 0, SymFunctionTableAccess64, SymGetModuleBase64, 0)) {

        if (sf64.AddrReturn.Offset == 0)
            break;

        trace[nativeFrameCount] = reinterpret_cast<void*>(sf64.AddrReturn.Offset);
        nativeFrameCount++;
        if (nativeFrameCount >= sizeof(trace) / sizeof(trace[0]))
            break;
    }

#else
    nativeFrameCount = 0;
#endif
    }

NativeFrame NativeStackTrace::nextFrame() {
    NativeFrame frame;
    frame.function = 0;
    frame.line = -1;

    for (; currentNativeFrame < nativeFrameCount && !frame.function; ++currentNativeFrame) {
        quintptr pc = reinterpret_cast<quintptr>(trace[currentNativeFrame]);
        // The pointers from the back trace point to the return address, but we are interested in
        // the caller site.
        pc = pc - 1;

        Function *f = engine->functionForProgramCounter(pc);
        if (!f)
            continue;

        frame.function = f;
        frame.line = f->lineNumberForProgramCounter(pc - reinterpret_cast<quintptr>(f->code));
    }

    return frame;
}

QT_END_NAMESPACE
<commit_msg>wince: Build fix, creating stack traces is not available on this platform<commit_after>/****************************************************************************
**
** Copyright (C) 2013 Digia Plc and/or its subsidiary(-ies).
** Contact: http://www.qt-project.org/legal
**
** This file is part of the QtQml module of the Qt Toolkit.
**
** $QT_BEGIN_LICENSE:LGPL$
** Commercial License Usage
** Licensees holding valid commercial Qt licenses may use this file in
** accordance with the commercial license agreement provided with the
** Software or, alternatively, in accordance with the terms contained in
** a written agreement between you and Digia.  For licensing terms and
** conditions see http://qt.digia.com/licensing.  For further information
** use the contact form at http://qt.digia.com/contact-us.
**
** GNU Lesser General Public License Usage
** Alternatively, this file may be used under the terms of the GNU Lesser
** General Public License version 2.1 as published by the Free Software
** Foundation and appearing in the file LICENSE.LGPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU Lesser General Public License version 2.1 requirements
** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
**
** In addition, as a special exception, Digia gives you certain additional
** rights.  These rights are described in the Digia Qt LGPL Exception
** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
**
** GNU General Public License Usage
** Alternatively, this file may be used under the terms of the GNU
** General Public License version 3.0 as published by the Free Software
** Foundation and appearing in the file LICENSE.GPL included in the
** packaging of this file.  Please review the following information to
** ensure the GNU General Public License version 3.0 requirements will be
** met: http://www.gnu.org/copyleft/gpl.html.
**
**
** $QT_END_LICENSE$
**
****************************************************************************/

#if defined(_WIN32) && !(defined(WINCE) || defined(_WIN32_WCE))
#include <windows.h>
#include <DbgHelp.h>
#endif

#include "qv4stacktrace_p.h"
#include "qv4function_p.h"
#include "qv4engine_p.h"
#include "qv4unwindhelper_p.h"

#if (defined(Q_OS_LINUX) && !defined(Q_OS_ANDROID)) || defined(Q_OS_MAC)
#define HAVE_GNU_BACKTRACE
#include <execinfo.h>
#endif

QT_BEGIN_NAMESPACE

using namespace QV4;

NativeStackTrace::NativeStackTrace(ExecutionContext *context)
{
    engine = context->engine;
    currentNativeFrame = 0;

#if defined(HAVE_GNU_BACKTRACE)
    UnwindHelper::prepareForUnwind(context);

    nativeFrameCount = backtrace(&trace[0], sizeof(trace) / sizeof(trace[0]));
#elif defined(Q_OS_WIN) && !defined(Q_OS_WINCE)

    int machineType = 0;

    CONTEXT winContext;
    memset(&winContext, 0, sizeof(winContext));
    winContext.ContextFlags = CONTEXT_FULL;
    RtlCaptureContext(&winContext);

    STACKFRAME64 sf64;
    memset(&sf64, 0, sizeof(sf64));

#if defined(Q_PROCESSOR_X86_32)
    machineType = IMAGE_FILE_MACHINE_I386;

    sf64.AddrFrame.Offset = winContext.Ebp;
    sf64.AddrFrame.Mode = AddrModeFlat;
    sf64.AddrPC.Offset = winContext.Eip;
    sf64.AddrPC.Mode = AddrModeFlat;
    sf64.AddrStack.Offset = winContext.Esp;
    sf64.AddrStack.Mode = AddrModeFlat;

#elif defined(Q_PROCESSOR_X86_64)
    machineType = IMAGE_FILE_MACHINE_AMD64;

    sf64.AddrFrame.Offset = winContext.Rbp;
    sf64.AddrFrame.Mode = AddrModeFlat;
    sf64.AddrPC.Offset = winContext.Rip;
    sf64.AddrPC.Mode = AddrModeFlat;
    sf64.AddrStack.Offset = winContext.Rsp;
    sf64.AddrStack.Mode = AddrModeFlat;

#else
#error "Platform unsupported!"
#endif

    nativeFrameCount = 0;

    while (StackWalk64(machineType, GetCurrentProcess(), GetCurrentThread(), &sf64, &winContext, 0, SymFunctionTableAccess64, SymGetModuleBase64, 0)) {

        if (sf64.AddrReturn.Offset == 0)
            break;

        trace[nativeFrameCount] = reinterpret_cast<void*>(sf64.AddrReturn.Offset);
        nativeFrameCount++;
        if (nativeFrameCount >= sizeof(trace) / sizeof(trace[0]))
            break;
    }

#else
    nativeFrameCount = 0;
#endif
    }

NativeFrame NativeStackTrace::nextFrame() {
    NativeFrame frame;
    frame.function = 0;
    frame.line = -1;

    for (; currentNativeFrame < nativeFrameCount && !frame.function; ++currentNativeFrame) {
        quintptr pc = reinterpret_cast<quintptr>(trace[currentNativeFrame]);
        // The pointers from the back trace point to the return address, but we are interested in
        // the caller site.
        pc = pc - 1;

        Function *f = engine->functionForProgramCounter(pc);
        if (!f)
            continue;

        frame.function = f;
        frame.line = f->lineNumberForProgramCounter(pc - reinterpret_cast<quintptr>(f->code));
    }

    return frame;
}

QT_END_NAMESPACE
<|endoftext|>


<commit_before>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
#include "webrtc/base/event_tracer.h"

#include <inttypes.h>

#include <vector>

#include "webrtc/base/checks.h"
#include "webrtc/base/criticalsection.h"
#include "webrtc/base/event.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/platform_thread.h"
#include "webrtc/base/timeutils.h"
#include "webrtc/base/trace_event.h"

namespace webrtc {

namespace {

GetCategoryEnabledPtr g_get_category_enabled_ptr = nullptr;
AddTraceEventPtr g_add_trace_event_ptr = nullptr;

}  // namespace

void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr,
                      AddTraceEventPtr add_trace_event_ptr) {
  g_get_category_enabled_ptr = get_category_enabled_ptr;
  g_add_trace_event_ptr = add_trace_event_ptr;
}

const unsigned char* EventTracer::GetCategoryEnabled(const char* name) {
  if (g_get_category_enabled_ptr)
    return g_get_category_enabled_ptr(name);

  // A string with null terminator means category is disabled.
  return reinterpret_cast<const unsigned char*>("\0");
}

// Arguments to this function (phase, etc.) are as defined in
// webrtc/base/trace_event.h.
void EventTracer::AddTraceEvent(char phase,
                                const unsigned char* category_enabled,
                                const char* name,
                                unsigned long long id,
                                int num_args,
                                const char** arg_names,
                                const unsigned char* arg_types,
                                const unsigned long long* arg_values,
                                unsigned char flags) {
  if (g_add_trace_event_ptr) {
    g_add_trace_event_ptr(phase,
                          category_enabled,
                          name,
                          id,
                          num_args,
                          arg_names,
                          arg_types,
                          arg_values,
                          flags);
  }
}

}  // namespace webrtc

namespace rtc {
namespace tracing {
namespace {

static bool EventTracingThreadFunc(void* params);

// Atomic-int fast path for avoiding logging when disabled.
static volatile int g_event_logging_active = 0;

// TODO(pbos): Log metadata for all threads, etc.
class EventLogger final {
 public:
  EventLogger()
      : logging_thread_(EventTracingThreadFunc, this, "EventTracingThread"),
        shutdown_event_(false, false) {}
  ~EventLogger() { RTC_DCHECK(thread_checker_.CalledOnValidThread()); }

  void AddTraceEvent(const char* name,
                     const unsigned char* category_enabled,
                     char phase,
                     uint64_t timestamp,
                     int pid,
                     rtc::PlatformThreadId thread_id) {
    rtc::CritScope lock(&crit_);
    trace_events_.push_back(
        {name, category_enabled, phase, timestamp, 1, thread_id});
  }

// The TraceEvent format is documented here:
// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
  void Log() {
    RTC_DCHECK(output_file_);
    static const int kLoggingIntervalMs = 100;
    fprintf(output_file_, "{ \"traceEvents\": [\n");
    bool has_logged_event = false;
    while (true) {
      bool shutting_down = shutdown_event_.Wait(kLoggingIntervalMs);
      std::vector<TraceEvent> events;
      {
        rtc::CritScope lock(&crit_);
        trace_events_.swap(events);
      }
      for (const TraceEvent& e : events) {
        fprintf(output_file_,
                "%s{ \"name\": \"%s\""
                ", \"cat\": \"%s\""
                ", \"ph\": \"%c\""
                ", \"ts\": %" PRIu64
                ", \"pid\": %d"
                ", \"tid\": %d}\n",
                has_logged_event ? "," : " ", e.name, e.category_enabled,
                e.phase, e.timestamp, e.pid, static_cast<int>(e.tid));
        has_logged_event = true;
      }
      if (shutting_down)
        break;
    }
    fprintf(output_file_, "]}\n");
    if (output_file_owned_)
      fclose(output_file_);
    output_file_ = nullptr;
  }

  void Start(FILE* file, bool owned) {
    RTC_DCHECK(file);
    RTC_DCHECK(!output_file_);
    output_file_ = file;
    output_file_owned_ = owned;
    {
      rtc::CritScope lock(&crit_);
      // Since the atomic fast-path for adding events to the queue can be
      // bypassed while the logging thread is shutting down there may be some
      // stale events in the queue, hence the vector needs to be cleared to not
      // log events from a previous logging session (which may be days old).
      trace_events_.clear();
    }
    // Enable event logging (fast-path). This should be disabled since starting
    // shouldn't be done twice.
    RTC_CHECK_EQ(0,
                 rtc::AtomicOps::CompareAndSwap(&g_event_logging_active, 0, 1));

    // Finally start, everything should be set up now.
    logging_thread_.Start();
  }

  void Stop() {
    // Try to stop. Abort if we're not currently logging.
    if (rtc::AtomicOps::CompareAndSwap(&g_event_logging_active, 1, 0) == 0)
      return;

    // Wake up logging thread to finish writing.
    shutdown_event_.Set();
    // Join the logging thread.
    logging_thread_.Stop();
  }

 private:
  struct TraceEvent {
    const char* name;
    const unsigned char* category_enabled;
    char phase;
    uint64_t timestamp;
    int pid;
    rtc::PlatformThreadId tid;
  };

  rtc::CriticalSection crit_;
  std::vector<TraceEvent> trace_events_ GUARDED_BY(crit_);
  rtc::PlatformThread logging_thread_;
  rtc::Event shutdown_event_;
  rtc::ThreadChecker thread_checker_;
  FILE* output_file_ = nullptr;
  bool output_file_owned_ = false;
};

static bool EventTracingThreadFunc(void* params) {
  static_cast<EventLogger*>(params)->Log();
  return true;
}

static EventLogger* volatile g_event_logger = nullptr;
static const char* const kDisabledTracePrefix = TRACE_DISABLED_BY_DEFAULT("");
const unsigned char* InternalGetCategoryEnabled(const char* name) {
  const char* prefix_ptr = &kDisabledTracePrefix[0];
  const char* name_ptr = name;
  // Check whether name contains the default-disabled prefix.
  while (*prefix_ptr == *name_ptr && *prefix_ptr != '\0') {
    ++prefix_ptr;
    ++name_ptr;
  }
  return reinterpret_cast<const unsigned char*>(*prefix_ptr == '\0' ? ""
                                                                    : name);
}

void InternalAddTraceEvent(char phase,
                           const unsigned char* category_enabled,
                           const char* name,
                           unsigned long long id,
                           int num_args,
                           const char** arg_names,
                           const unsigned char* arg_types,
                           const unsigned long long* arg_values,
                           unsigned char flags) {
  // Fast path for when event tracing is inactive.
  if (rtc::AtomicOps::AcquireLoad(&g_event_logging_active) == 0)
    return;

  g_event_logger->AddTraceEvent(name, category_enabled, phase,
                                rtc::TimeMicros(), 1, rtc::CurrentThreadId());
}

}  // namespace

void SetupInternalTracer() {
  RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr(
                &g_event_logger, static_cast<EventLogger*>(nullptr),
                new EventLogger()) == nullptr);
  g_event_logger = new EventLogger();
  webrtc::SetupEventTracer(InternalGetCategoryEnabled, InternalAddTraceEvent);
}

void StartInternalCaptureToFile(FILE* file) {
  g_event_logger->Start(file, false);
}

bool StartInternalCapture(const char* filename) {
  FILE* file = fopen(filename, "w");
  if (!file) {
    LOG(LS_ERROR) << "Failed to open trace file '" << filename
                  << "' for writing.";
    return false;
  }
  g_event_logger->Start(file, true);
  return true;
}

void StopInternalCapture() {
  g_event_logger->Stop();
}

void ShutdownInternalTracer() {
  StopInternalCapture();
  EventLogger* old_logger = rtc::AtomicOps::AtomicLoadPtr(&g_event_logger);
  RTC_DCHECK(old_logger);
  RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr(
                &g_event_logger, old_logger,
                static_cast<EventLogger*>(nullptr)) == old_logger);
  delete old_logger;
  webrtc::SetupEventTracer(nullptr, nullptr);
}

}  // namespace tracing
}  // namespace rtc
<commit_msg>Remove thread-id wraparounds in event tracing.<commit_after>/*
 *  Copyright (c) 2012 The WebRTC project authors. All Rights Reserved.
 *
 *  Use of this source code is governed by a BSD-style license
 *  that can be found in the LICENSE file in the root of the source
 *  tree. An additional intellectual property rights grant can be found
 *  in the file PATENTS.  All contributing project authors may
 *  be found in the AUTHORS file in the root of the source tree.
 */
#include "webrtc/base/event_tracer.h"

#include <inttypes.h>

#include <vector>

#include "webrtc/base/checks.h"
#include "webrtc/base/criticalsection.h"
#include "webrtc/base/event.h"
#include "webrtc/base/logging.h"
#include "webrtc/base/platform_thread.h"
#include "webrtc/base/timeutils.h"
#include "webrtc/base/trace_event.h"

namespace webrtc {

namespace {

GetCategoryEnabledPtr g_get_category_enabled_ptr = nullptr;
AddTraceEventPtr g_add_trace_event_ptr = nullptr;

}  // namespace

void SetupEventTracer(GetCategoryEnabledPtr get_category_enabled_ptr,
                      AddTraceEventPtr add_trace_event_ptr) {
  g_get_category_enabled_ptr = get_category_enabled_ptr;
  g_add_trace_event_ptr = add_trace_event_ptr;
}

const unsigned char* EventTracer::GetCategoryEnabled(const char* name) {
  if (g_get_category_enabled_ptr)
    return g_get_category_enabled_ptr(name);

  // A string with null terminator means category is disabled.
  return reinterpret_cast<const unsigned char*>("\0");
}

// Arguments to this function (phase, etc.) are as defined in
// webrtc/base/trace_event.h.
void EventTracer::AddTraceEvent(char phase,
                                const unsigned char* category_enabled,
                                const char* name,
                                unsigned long long id,
                                int num_args,
                                const char** arg_names,
                                const unsigned char* arg_types,
                                const unsigned long long* arg_values,
                                unsigned char flags) {
  if (g_add_trace_event_ptr) {
    g_add_trace_event_ptr(phase,
                          category_enabled,
                          name,
                          id,
                          num_args,
                          arg_names,
                          arg_types,
                          arg_values,
                          flags);
  }
}

}  // namespace webrtc

namespace rtc {
namespace tracing {
namespace {

static bool EventTracingThreadFunc(void* params);

// Atomic-int fast path for avoiding logging when disabled.
static volatile int g_event_logging_active = 0;

// TODO(pbos): Log metadata for all threads, etc.
class EventLogger final {
 public:
  EventLogger()
      : logging_thread_(EventTracingThreadFunc, this, "EventTracingThread"),
        shutdown_event_(false, false) {}
  ~EventLogger() { RTC_DCHECK(thread_checker_.CalledOnValidThread()); }

  void AddTraceEvent(const char* name,
                     const unsigned char* category_enabled,
                     char phase,
                     uint64_t timestamp,
                     int pid,
                     rtc::PlatformThreadId thread_id) {
    rtc::CritScope lock(&crit_);
    trace_events_.push_back(
        {name, category_enabled, phase, timestamp, 1, thread_id});
  }

// The TraceEvent format is documented here:
// https://docs.google.com/document/d/1CvAClvFfyA5R-PhYUmn5OOQtYMH4h6I0nSsKchNAySU/preview
  void Log() {
    RTC_DCHECK(output_file_);
    static const int kLoggingIntervalMs = 100;
    fprintf(output_file_, "{ \"traceEvents\": [\n");
    bool has_logged_event = false;
    while (true) {
      bool shutting_down = shutdown_event_.Wait(kLoggingIntervalMs);
      std::vector<TraceEvent> events;
      {
        rtc::CritScope lock(&crit_);
        trace_events_.swap(events);
      }
      for (const TraceEvent& e : events) {
        fprintf(output_file_,
                "%s{ \"name\": \"%s\""
                ", \"cat\": \"%s\""
                ", \"ph\": \"%c\""
                ", \"ts\": %" PRIu64
                ", \"pid\": %d"
#if defined(WEBRTC_WIN)
                ", \"tid\": %lu"
#else
                ", \"tid\": %d"
#endif  // defined(WEBRTC_WIN)
                "}\n",
                has_logged_event ? "," : " ", e.name, e.category_enabled,
                e.phase, e.timestamp, e.pid, e.tid);
        has_logged_event = true;
      }
      if (shutting_down)
        break;
    }
    fprintf(output_file_, "]}\n");
    if (output_file_owned_)
      fclose(output_file_);
    output_file_ = nullptr;
  }

  void Start(FILE* file, bool owned) {
    RTC_DCHECK(file);
    RTC_DCHECK(!output_file_);
    output_file_ = file;
    output_file_owned_ = owned;
    {
      rtc::CritScope lock(&crit_);
      // Since the atomic fast-path for adding events to the queue can be
      // bypassed while the logging thread is shutting down there may be some
      // stale events in the queue, hence the vector needs to be cleared to not
      // log events from a previous logging session (which may be days old).
      trace_events_.clear();
    }
    // Enable event logging (fast-path). This should be disabled since starting
    // shouldn't be done twice.
    RTC_CHECK_EQ(0,
                 rtc::AtomicOps::CompareAndSwap(&g_event_logging_active, 0, 1));

    // Finally start, everything should be set up now.
    logging_thread_.Start();
  }

  void Stop() {
    // Try to stop. Abort if we're not currently logging.
    if (rtc::AtomicOps::CompareAndSwap(&g_event_logging_active, 1, 0) == 0)
      return;

    // Wake up logging thread to finish writing.
    shutdown_event_.Set();
    // Join the logging thread.
    logging_thread_.Stop();
  }

 private:
  struct TraceEvent {
    const char* name;
    const unsigned char* category_enabled;
    char phase;
    uint64_t timestamp;
    int pid;
    rtc::PlatformThreadId tid;
  };

  rtc::CriticalSection crit_;
  std::vector<TraceEvent> trace_events_ GUARDED_BY(crit_);
  rtc::PlatformThread logging_thread_;
  rtc::Event shutdown_event_;
  rtc::ThreadChecker thread_checker_;
  FILE* output_file_ = nullptr;
  bool output_file_owned_ = false;
};

static bool EventTracingThreadFunc(void* params) {
  static_cast<EventLogger*>(params)->Log();
  return true;
}

static EventLogger* volatile g_event_logger = nullptr;
static const char* const kDisabledTracePrefix = TRACE_DISABLED_BY_DEFAULT("");
const unsigned char* InternalGetCategoryEnabled(const char* name) {
  const char* prefix_ptr = &kDisabledTracePrefix[0];
  const char* name_ptr = name;
  // Check whether name contains the default-disabled prefix.
  while (*prefix_ptr == *name_ptr && *prefix_ptr != '\0') {
    ++prefix_ptr;
    ++name_ptr;
  }
  return reinterpret_cast<const unsigned char*>(*prefix_ptr == '\0' ? ""
                                                                    : name);
}

void InternalAddTraceEvent(char phase,
                           const unsigned char* category_enabled,
                           const char* name,
                           unsigned long long id,
                           int num_args,
                           const char** arg_names,
                           const unsigned char* arg_types,
                           const unsigned long long* arg_values,
                           unsigned char flags) {
  // Fast path for when event tracing is inactive.
  if (rtc::AtomicOps::AcquireLoad(&g_event_logging_active) == 0)
    return;

  g_event_logger->AddTraceEvent(name, category_enabled, phase,
                                rtc::TimeMicros(), 1, rtc::CurrentThreadId());
}

}  // namespace

void SetupInternalTracer() {
  RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr(
                &g_event_logger, static_cast<EventLogger*>(nullptr),
                new EventLogger()) == nullptr);
  g_event_logger = new EventLogger();
  webrtc::SetupEventTracer(InternalGetCategoryEnabled, InternalAddTraceEvent);
}

void StartInternalCaptureToFile(FILE* file) {
  g_event_logger->Start(file, false);
}

bool StartInternalCapture(const char* filename) {
  FILE* file = fopen(filename, "w");
  if (!file) {
    LOG(LS_ERROR) << "Failed to open trace file '" << filename
                  << "' for writing.";
    return false;
  }
  g_event_logger->Start(file, true);
  return true;
}

void StopInternalCapture() {
  g_event_logger->Stop();
}

void ShutdownInternalTracer() {
  StopInternalCapture();
  EventLogger* old_logger = rtc::AtomicOps::AtomicLoadPtr(&g_event_logger);
  RTC_DCHECK(old_logger);
  RTC_CHECK(rtc::AtomicOps::CompareAndSwapPtr(
                &g_event_logger, old_logger,
                static_cast<EventLogger*>(nullptr)) == old_logger);
  delete old_logger;
  webrtc::SetupEventTracer(nullptr, nullptr);
}

}  // namespace tracing
}  // namespace rtc
<|endoftext|>


<commit_before>#ifndef RDB_PROTOCOL_QUERY_LANGUAGE_HPP_
#define RDB_PROTOCOL_QUERY_LANGUAGE_HPP_

#include <list>
#include <deque>

#include "utils.hpp"
#include <boost/variant.hpp>
#include <boost/shared_ptr.hpp>

#include "clustering/administration/metadata.hpp"
#include "clustering/administration/namespace_interface_repository.hpp"
#include "http/json.hpp"
#include "rdb_protocol/protocol.hpp"
#include "rdb_protocol/query_language.pb.h"

namespace query_language {

class type_error_t {
public:
    explicit type_error_t(const std::string &s) : message(s) { }

    std::string what() const throw () {
        return message;
    }
private:
    std::string message;
};

struct type_t {
    enum Type {
        INVALID,
        ERROR,
        JSON,
        STREAM,
        VIEW,
        READ,
        WRITE,
        QUERY
    } value;

    type_t() : value(INVALID) { }

    explicit type_t(Type _value) : value(_value) { }

    bool operator==(const type_t &p) const {
        if (value == VIEW && p.value == STREAM) {
            return true; // we can coerce a view to a stream
        }
        return value == p.value;
    }

    bool operator!=(const type_t &p) const {
        return !(operator==(p));
    }
};

namespace Type {
    const type_t ERROR = type_t(type_t::ERROR);
    const type_t JSON = type_t(type_t::JSON);
    const type_t STREAM = type_t(type_t::STREAM);
    const type_t VIEW = type_t(type_t::VIEW);
    const type_t READ = type_t(type_t::READ);
    const type_t WRITE = type_t(type_t::WRITE);
    const type_t QUERY = type_t(type_t::WRITE);
}

class function_t {
public:
    // _n_args==-1 indicates a variadic function
    function_t(const type_t& _arg_type, int _n_args, const type_t& _return_type);
    function_t(const type_t& _arg1_type, const type_t& _arg2_type, const type_t& _return_type);

    const type_t& get_arg_type(int n) const;
    const type_t& get_return_type() const;
    bool is_variadic() const;
    bool is_error() const;

    int get_n_args() const;
private:
    type_t arg_type[3];
    int n_args;
    type_t return_type;
};

template <class T>
class variable_scope_t {
public:
    void put_in_scope(const std::string &name, const T &t) {
        rassert(!scopes.empty());
        scopes.front()[name] = t;
    }

    T get(const std::string &name) {
        for (typename scopes_t::iterator it  = scopes.begin();
                                         it != scopes.end();
                                         ++it) {
            typename std::map<std::string, T>::iterator jt = it->find(name);
            if (jt != it->end()) {
                return jt->second;
            }
        }

        unreachable("Variable not in scope, probably because the code fails to call is_in_scope().");
    }

    // Calling this only makes sense in the typechecker. All variables
    // are guranteed by the typechecker to be present at runtime.
    bool is_in_scope(const std::string &name) {
        for (typename scopes_t::iterator it  = scopes.begin();
                                         it != scopes.end();
                                         ++it) {
            typename std::map<std::string, T>::iterator jt = it->find(name);
            if (jt != it->end()) {
                return true;
            }
        }
        return false;
    }

    void push() {
        scopes.push_front(std::map<std::string, T>());
    }

    void pop() {
        scopes.pop_front();
    }

    struct new_scope_t {
        explicit new_scope_t(variable_scope_t<T> *_parent)
            : parent(_parent)
        {
            parent->push();
        }
        ~new_scope_t() {
            parent->pop();
        }

        variable_scope_t<T> *parent;
    };
private:
    typedef std::deque<std::map<std::string, T> > scopes_t;
    scopes_t scopes;
};

typedef variable_scope_t<type_t> variable_type_scope_t;

typedef variable_type_scope_t::new_scope_t new_scope_t;

/* get_type functions throw exceptions if their inputs aren't well defined or
   fail type-checking. (A well-defined input has the correct fields filled in)  */
const type_t get_type(const Term &t, variable_type_scope_t *scope);
const type_t get_type(const Reduction &r, variable_type_scope_t *scope);
const type_t get_type(const Mapping &m, variable_type_scope_t *scope);
const type_t get_type(const Predicate &p, variable_type_scope_t *scope);
const type_t get_type(const ReadQuery &r, variable_type_scope_t *scope);
const type_t get_type(const WriteQuery &w, variable_type_scope_t *scope);
const type_t get_type(const Query &q, variable_type_scope_t *scope);

const function_t get_type(const Builtin &b, variable_type_scope_t *scope);

/* functions to evaluate the queries */

class json_stream_t {
public:
    virtual boost::shared_ptr<scoped_cJSON_t> next() = 0;
    virtual ~json_stream_t() { }
};

class in_memory_stream_t : public json_stream_t {
public:
    typedef std::list<boost::shared_ptr<scoped_cJSON_t> > cJSON_list_t;

    template <class iterator>
    in_memory_stream_t(const iterator &begin, const iterator &end)
        : data(begin, end), hd(data.begin())
    { }

    in_memory_stream_t(json_array_iterator_t it) {
        while (cJSON *json = it.next()) {
            data.push_back(boost::shared_ptr<scoped_cJSON_t>(new scoped_cJSON_t(cJSON_DeepCopy(json))));
        }
        hd = data.begin();
    }

    in_memory_stream_t(boost::shared_ptr<json_stream_t> stream) {
        while (boost::shared_ptr<scoped_cJSON_t> json = stream->next()) {
            data.push_back(json);
        }
        hd = data.begin();
    }

    template <class Ordering>
    void sort(const Ordering &o) {
        guarantee(hd == data.begin(), "Can't sort a stream if you've already consumed from it");
        data.sort(o);
        hd = data.begin();
    }

    boost::shared_ptr<scoped_cJSON_t> next() {
        if (hd == data.end()) {
            return boost::shared_ptr<scoped_cJSON_t>();
        } else {
            boost::shared_ptr<scoped_cJSON_t> res = *hd;
            ++hd;
            return res;
        }
    }
private:
    cJSON_list_t data;
    cJSON_list_t::iterator hd;
};

class union_stream_t : public json_stream_t {
public:
    typedef std::list<boost::shared_ptr<json_stream_t> > stream_list_t;

    union_stream_t(const stream_list_t &_streams)
        : streams(_streams), hd(streams.begin())
    { }

    boost::shared_ptr<scoped_cJSON_t> next() {
        while (hd != streams.end()) {
            if (boost::shared_ptr<scoped_cJSON_t> json = (*hd)->next()) {
                return json;
            } else {
                ++hd;
            }
        }
        return boost::shared_ptr<scoped_cJSON_t>();
    }

private:
    stream_list_t streams;
    stream_list_t::iterator hd;
};

template <class P>
class filter_stream_t : public json_stream_t {
public:
    typedef boost::function<bool(boost::shared_ptr<scoped_cJSON_t>)> predicate;
    filter_stream_t(boost::shared_ptr<json_stream_t> _stream, const P &_p)
        : stream(_stream), p(_p)
    { }

    boost::shared_ptr<scoped_cJSON_t> next() {
        while (boost::shared_ptr<scoped_cJSON_t> json = stream->next()) {
            if (p(json)) {
                return json;
            }
        }
        return boost::shared_ptr<scoped_cJSON_t>();
    }

private:
    boost::shared_ptr<json_stream_t> stream;
    P p;
};

template <class F>
class mapping_stream_t : public json_stream_t {
public:
    mapping_stream_t(boost::shared_ptr<json_stream_t> _stream, const F &_f)
        : stream(_stream), f(_f)
    { }

    boost::shared_ptr<scoped_cJSON_t> next() {
        if (boost::shared_ptr<scoped_cJSON_t> json = stream->next()) {
            return f(json);
        } else {
            return json;
        }
    }

private:
    boost::shared_ptr<json_stream_t> stream;
    F f;
};

template <class F>
class concat_mapping_stream_t : public  json_stream_t {
public:
    concat_mapping_stream_t(boost::shared_ptr<json_stream_t> _stream, const F &_f)
        : stream(_stream), f(_f)
    {
        f = _f;
        if (boost::shared_ptr<scoped_cJSON_t> json = stream->next()) {
            substream = f(json);
        }
    }

    boost::shared_ptr<scoped_cJSON_t> next() {
        boost::shared_ptr<scoped_cJSON_t> res;

        while (!res) {
            if (!substream) {
                return res;
            } else if ((res = substream->next())) {
                continue;
            } else if (boost::shared_ptr<scoped_cJSON_t> json = stream->next()) {
                substream = f(json);
            } else {
                substream.reset();
            }
        }

        return res;
    }

private:
    boost::shared_ptr<json_stream_t> stream, substream;
    F f;
};

class limit_stream_t : public json_stream_t {
public:
    limit_stream_t(boost::shared_ptr<json_stream_t> _stream, int _limit)
        : stream(_stream), limit(_limit)
    {
        guarantee(limit >= 0);
    }

    boost::shared_ptr<scoped_cJSON_t> next() {
        if (limit == 0) {
            return boost::shared_ptr<scoped_cJSON_t>();
        } else {
            return stream->next();
        }
    }

private:
    boost::shared_ptr<json_stream_t> stream;
    int limit;
};

//Scopes for single pieces of json
typedef variable_scope_t<boost::shared_ptr<scoped_cJSON_t> > variable_val_scope_t;

typedef variable_val_scope_t::new_scope_t new_val_scope_t;

//scopes for json streams
typedef variable_scope_t<boost::shared_ptr<json_stream_t> > variable_stream_scope_t;

typedef variable_stream_scope_t::new_scope_t new_stream_scope_t;

class runtime_exc_t {
public:
    explicit runtime_exc_t(const std::string &_what)
        : what_happened(_what)
    { }

    std::string what() const throw() {
        return what_happened;
    }
private:
    std::string what_happened;
};

class runtime_environment_t {
public:
    runtime_environment_t(namespace_repo_t<rdb_protocol_t> *_ns_repo,
                          boost::shared_ptr<semilattice_read_view_t<cluster_semilattice_metadata_t> > _semilattice_metadata)
        : ns_repo(_ns_repo), semilattice_metadata(_semilattice_metadata)
    { }

    variable_val_scope_t scope;
    variable_stream_scope_t stream_scope;
    variable_type_scope_t type_scope;

    namespace_repo_t<rdb_protocol_t> *ns_repo;
    //TODO this should really just be the namespace metadata... but
    //constructing views is too hard :-/
    boost::shared_ptr<semilattice_read_view_t<cluster_semilattice_metadata_t> > semilattice_metadata;
    cond_t interruptor;
};

//TODO most of these functions that are supposed to only throw runtime exceptions

Response eval(const Query &q, runtime_environment_t *);

Response eval(const ReadQuery &r, runtime_environment_t *) THROWS_ONLY(runtime_exc_t);

Response eval(const WriteQuery &r, runtime_environment_t *) THROWS_ONLY(runtime_exc_t);

boost::shared_ptr<scoped_cJSON_t> eval(const Term &t, runtime_environment_t *) THROWS_ONLY(runtime_exc_t);

boost::shared_ptr<json_stream_t> eval_stream(const Term &t, runtime_environment_t *) THROWS_ONLY(runtime_exc_t);

boost::shared_ptr<scoped_cJSON_t> eval(const Term::Call &c, runtime_environment_t *) THROWS_ONLY(runtime_exc_t);

boost::shared_ptr<json_stream_t> eval_stream(const Term::Call &c, runtime_environment_t *) THROWS_ONLY(runtime_exc_t);

boost::shared_ptr<scoped_cJSON_t> eval_cmp(const Term::Call &c, runtime_environment_t *) THROWS_ONLY(runtime_exc_t);

namespace_repo_t<rdb_protocol_t>::access_t eval(const TableRef &t, runtime_environment_t *) THROWS_ONLY(runtime_exc_t);

class view_t {
public:
    view_t(const namespace_repo_t<rdb_protocol_t>::access_t &_access,
           boost::shared_ptr<json_stream_t> _stream)
        : access(_access), stream(_stream) { }

    namespace_repo_t<rdb_protocol_t>::access_t access;
    boost::shared_ptr<json_stream_t> stream;
};

view_t eval_view(const Term::Table &t, runtime_environment_t *) THROWS_ONLY(runtime_exc_t);

} //namespace query_language

#endif /* RDB_PROTOCOL_QUERY_LANGUAGE_HPP_ */
<commit_msg>Adds a stream multiplexer.<commit_after>#ifndef RDB_PROTOCOL_QUERY_LANGUAGE_HPP_
#define RDB_PROTOCOL_QUERY_LANGUAGE_HPP_

#include <list>
#include <deque>

#include "utils.hpp"
#include <boost/variant.hpp>
#include <boost/shared_ptr.hpp>

#include "clustering/administration/metadata.hpp"
#include "clustering/administration/namespace_interface_repository.hpp"
#include "http/json.hpp"
#include "rdb_protocol/protocol.hpp"
#include "rdb_protocol/query_language.pb.h"

namespace query_language {

class type_error_t {
public:
    explicit type_error_t(const std::string &s) : message(s) { }

    std::string what() const throw () {
        return message;
    }
private:
    std::string message;
};

struct type_t {
    enum Type {
        INVALID,
        ERROR,
        JSON,
        STREAM,
        VIEW,
        READ,
        WRITE,
        QUERY
    } value;

    type_t() : value(INVALID) { }

    explicit type_t(Type _value) : value(_value) { }

    bool operator==(const type_t &p) const {
        if (value == VIEW && p.value == STREAM) {
            return true; // we can coerce a view to a stream
        }
        return value == p.value;
    }

    bool operator!=(const type_t &p) const {
        return !(operator==(p));
    }
};

namespace Type {
    const type_t ERROR = type_t(type_t::ERROR);
    const type_t JSON = type_t(type_t::JSON);
    const type_t STREAM = type_t(type_t::STREAM);
    const type_t VIEW = type_t(type_t::VIEW);
    const type_t READ = type_t(type_t::READ);
    const type_t WRITE = type_t(type_t::WRITE);
    const type_t QUERY = type_t(type_t::WRITE);
}

class function_t {
public:
    // _n_args==-1 indicates a variadic function
    function_t(const type_t& _arg_type, int _n_args, const type_t& _return_type);
    function_t(const type_t& _arg1_type, const type_t& _arg2_type, const type_t& _return_type);

    const type_t& get_arg_type(int n) const;
    const type_t& get_return_type() const;
    bool is_variadic() const;
    bool is_error() const;

    int get_n_args() const;
private:
    type_t arg_type[3];
    int n_args;
    type_t return_type;
};

template <class T>
class variable_scope_t {
public:
    void put_in_scope(const std::string &name, const T &t) {
        rassert(!scopes.empty());
        scopes.front()[name] = t;
    }

    T get(const std::string &name) {
        for (typename scopes_t::iterator it  = scopes.begin();
                                         it != scopes.end();
                                         ++it) {
            typename std::map<std::string, T>::iterator jt = it->find(name);
            if (jt != it->end()) {
                return jt->second;
            }
        }

        unreachable("Variable not in scope, probably because the code fails to call is_in_scope().");
    }

    // Calling this only makes sense in the typechecker. All variables
    // are guranteed by the typechecker to be present at runtime.
    bool is_in_scope(const std::string &name) {
        for (typename scopes_t::iterator it  = scopes.begin();
                                         it != scopes.end();
                                         ++it) {
            typename std::map<std::string, T>::iterator jt = it->find(name);
            if (jt != it->end()) {
                return true;
            }
        }
        return false;
    }

    void push() {
        scopes.push_front(std::map<std::string, T>());
    }

    void pop() {
        scopes.pop_front();
    }

    struct new_scope_t {
        explicit new_scope_t(variable_scope_t<T> *_parent)
            : parent(_parent)
        {
            parent->push();
        }
        ~new_scope_t() {
            parent->pop();
        }

        variable_scope_t<T> *parent;
    };
private:
    typedef std::deque<std::map<std::string, T> > scopes_t;
    scopes_t scopes;
};

typedef variable_scope_t<type_t> variable_type_scope_t;

typedef variable_type_scope_t::new_scope_t new_scope_t;

/* get_type functions throw exceptions if their inputs aren't well defined or
   fail type-checking. (A well-defined input has the correct fields filled in)  */
const type_t get_type(const Term &t, variable_type_scope_t *scope);
const type_t get_type(const Reduction &r, variable_type_scope_t *scope);
const type_t get_type(const Mapping &m, variable_type_scope_t *scope);
const type_t get_type(const Predicate &p, variable_type_scope_t *scope);
const type_t get_type(const ReadQuery &r, variable_type_scope_t *scope);
const type_t get_type(const WriteQuery &w, variable_type_scope_t *scope);
const type_t get_type(const Query &q, variable_type_scope_t *scope);

const function_t get_type(const Builtin &b, variable_type_scope_t *scope);

/* functions to evaluate the queries */

typedef std::list<boost::shared_ptr<scoped_cJSON_t> > cJSON_list_t;

class json_stream_t {
public:
    virtual boost::shared_ptr<scoped_cJSON_t> next() = 0;
    virtual ~json_stream_t() { }
};

class in_memory_stream_t : public json_stream_t {
public:
    template <class iterator>
    in_memory_stream_t(const iterator &begin, const iterator &end)
        : data(begin, end)
    { }

    in_memory_stream_t(json_array_iterator_t it) {
        while (cJSON *json = it.next()) {
            data.push_back(boost::shared_ptr<scoped_cJSON_t>(new scoped_cJSON_t(cJSON_DeepCopy(json))));
        }
    }

    in_memory_stream_t(boost::shared_ptr<json_stream_t> stream) {
        while (boost::shared_ptr<scoped_cJSON_t> json = stream->next()) {
            data.push_back(json);
        }
    }

    template <class Ordering>
    void sort(const Ordering &o) {
        data.sort(o);
    }

    boost::shared_ptr<scoped_cJSON_t> next() {
        if (data.empty()) {
            return boost::shared_ptr<scoped_cJSON_t>();
        } else {
            boost::shared_ptr<scoped_cJSON_t> res = data.front();
            data.pop_front();
            return res;
        }
    }
private:
    cJSON_list_t data;
};

class stream_multiplexer_t {
    stream_multiplexer_t(boost::shared_ptr<json_stream_t> _stream)
        : stream(_stream)
    { }

    class stream_t : public json_stream_t {
    public:
        stream_t(stream_multiplexer_t *_parent)
            : parent(_parent)
        {
            if (parent->data.empty()) {
                parent->maybe_read_more();
            }
            hd = parent->data.begin();
        }

        boost::shared_ptr<scoped_cJSON_t> next() {
            if (hd == parent->data.end()) {
                return boost::shared_ptr<scoped_cJSON_t>();
            } else {
                boost::shared_ptr<scoped_cJSON_t> res = *hd;
                cJSON_list_t::iterator next = hd;
                ++next;
                if (next != parent->data.end()) {
                    hd = next;
                } else {
                    parent->maybe_read_more();
                    ++hd;
                }

                return res;
            }
        }
    private:
        stream_multiplexer_t *parent;
        cJSON_list_t::iterator hd;
    };

private:
    friend class stream_t;

    void maybe_read_more() {
        if (boost::shared_ptr<scoped_cJSON_t> json = stream->next()) {
            data.push_back(json);
        }
    }
    boost::shared_ptr<json_stream_t> stream;
    cJSON_list_t data;
};

class union_stream_t : public json_stream_t {
public:
    typedef std::list<boost::shared_ptr<json_stream_t> > stream_list_t;

    union_stream_t(const stream_list_t &_streams)
        : streams(_streams), hd(streams.begin())
    { }

    boost::shared_ptr<scoped_cJSON_t> next() {
        while (hd != streams.end()) {
            if (boost::shared_ptr<scoped_cJSON_t> json = (*hd)->next()) {
                return json;
            } else {
                ++hd;
            }
        }
        return boost::shared_ptr<scoped_cJSON_t>();
    }

private:
    stream_list_t streams;
    stream_list_t::iterator hd;
};

template <class P>
class filter_stream_t : public json_stream_t {
public:
    typedef boost::function<bool(boost::shared_ptr<scoped_cJSON_t>)> predicate;
    filter_stream_t(boost::shared_ptr<json_stream_t> _stream, const P &_p)
        : stream(_stream), p(_p)
    { }

    boost::shared_ptr<scoped_cJSON_t> next() {
        while (boost::shared_ptr<scoped_cJSON_t> json = stream->next()) {
            if (p(json)) {
                return json;
            }
        }
        return boost::shared_ptr<scoped_cJSON_t>();
    }

private:
    boost::shared_ptr<json_stream_t> stream;
    P p;
};

template <class F>
class mapping_stream_t : public json_stream_t {
public:
    mapping_stream_t(boost::shared_ptr<json_stream_t> _stream, const F &_f)
        : stream(_stream), f(_f)
    { }

    boost::shared_ptr<scoped_cJSON_t> next() {
        if (boost::shared_ptr<scoped_cJSON_t> json = stream->next()) {
            return f(json);
        } else {
            return json;
        }
    }

private:
    boost::shared_ptr<json_stream_t> stream;
    F f;
};

template <class F>
class concat_mapping_stream_t : public  json_stream_t {
public:
    concat_mapping_stream_t(boost::shared_ptr<json_stream_t> _stream, const F &_f)
        : stream(_stream), f(_f)
    {
        f = _f;
        if (boost::shared_ptr<scoped_cJSON_t> json = stream->next()) {
            substream = f(json);
        }
    }

    boost::shared_ptr<scoped_cJSON_t> next() {
        boost::shared_ptr<scoped_cJSON_t> res;

        while (!res) {
            if (!substream) {
                return res;
            } else if ((res = substream->next())) {
                continue;
            } else if (boost::shared_ptr<scoped_cJSON_t> json = stream->next()) {
                substream = f(json);
            } else {
                substream.reset();
            }
        }

        return res;
    }

private:
    boost::shared_ptr<json_stream_t> stream, substream;
    F f;
};

class limit_stream_t : public json_stream_t {
public:
    limit_stream_t(boost::shared_ptr<json_stream_t> _stream, int _limit)
        : stream(_stream), limit(_limit)
    {
        guarantee(limit >= 0);
    }

    boost::shared_ptr<scoped_cJSON_t> next() {
        if (limit == 0) {
            return boost::shared_ptr<scoped_cJSON_t>();
        } else {
            return stream->next();
        }
    }

private:
    boost::shared_ptr<json_stream_t> stream;
    int limit;
};

//Scopes for single pieces of json
typedef variable_scope_t<boost::shared_ptr<scoped_cJSON_t> > variable_val_scope_t;

typedef variable_val_scope_t::new_scope_t new_val_scope_t;

//scopes for json streams
typedef variable_scope_t<boost::shared_ptr<json_stream_t> > variable_stream_scope_t;

typedef variable_stream_scope_t::new_scope_t new_stream_scope_t;

class runtime_exc_t {
public:
    explicit runtime_exc_t(const std::string &_what)
        : what_happened(_what)
    { }

    std::string what() const throw() {
        return what_happened;
    }
private:
    std::string what_happened;
};

class runtime_environment_t {
public:
    runtime_environment_t(namespace_repo_t<rdb_protocol_t> *_ns_repo,
                          boost::shared_ptr<semilattice_read_view_t<cluster_semilattice_metadata_t> > _semilattice_metadata)
        : ns_repo(_ns_repo), semilattice_metadata(_semilattice_metadata)
    { }

    variable_val_scope_t scope;
    variable_stream_scope_t stream_scope;
    variable_type_scope_t type_scope;

    namespace_repo_t<rdb_protocol_t> *ns_repo;
    //TODO this should really just be the namespace metadata... but
    //constructing views is too hard :-/
    boost::shared_ptr<semilattice_read_view_t<cluster_semilattice_metadata_t> > semilattice_metadata;
    cond_t interruptor;
};

//TODO most of these functions that are supposed to only throw runtime exceptions

Response eval(const Query &q, runtime_environment_t *);

Response eval(const ReadQuery &r, runtime_environment_t *) THROWS_ONLY(runtime_exc_t);

Response eval(const WriteQuery &r, runtime_environment_t *) THROWS_ONLY(runtime_exc_t);

boost::shared_ptr<scoped_cJSON_t> eval(const Term &t, runtime_environment_t *) THROWS_ONLY(runtime_exc_t);

boost::shared_ptr<json_stream_t> eval_stream(const Term &t, runtime_environment_t *) THROWS_ONLY(runtime_exc_t);

boost::shared_ptr<scoped_cJSON_t> eval(const Term::Call &c, runtime_environment_t *) THROWS_ONLY(runtime_exc_t);

boost::shared_ptr<json_stream_t> eval_stream(const Term::Call &c, runtime_environment_t *) THROWS_ONLY(runtime_exc_t);

boost::shared_ptr<scoped_cJSON_t> eval_cmp(const Term::Call &c, runtime_environment_t *) THROWS_ONLY(runtime_exc_t);

namespace_repo_t<rdb_protocol_t>::access_t eval(const TableRef &t, runtime_environment_t *) THROWS_ONLY(runtime_exc_t);

class view_t {
public:
    view_t(const namespace_repo_t<rdb_protocol_t>::access_t &_access,
           boost::shared_ptr<json_stream_t> _stream)
        : access(_access), stream(_stream) { }

    namespace_repo_t<rdb_protocol_t>::access_t access;
    boost::shared_ptr<json_stream_t> stream;
};

view_t eval_view(const Term::Table &t, runtime_environment_t *) THROWS_ONLY(runtime_exc_t);

} //namespace query_language

#endif /* RDB_PROTOCOL_QUERY_LANGUAGE_HPP_ */
<|endoftext|>


<commit_before>#include "stdafx.h"
#include "GameTile.h"
#include "lodepng.h"

GameTile::GameTile(int width, int height) {
	this->Width = width;
	this->Height = height;
	Cells = new TileCell[width*height];
}
GameTile::~GameTile() {
	delete [] Cells;
}

//Load a game tile from disk
GameTile * GameTile::LoadTileFromDisk(string tileImagePath) {
	unsigned int width;
	unsigned int height;
	vector<unsigned char> tileData;

	cout << "Starting load of tile \"" << tileImagePath << "\"\n";
	//First load the tile map data from the image
	if (lodepng::decode(tileData,width,height,tileImagePath)) {
		cout << "\tImage load failed.\n";
		//Error
		return NULL;
	}
	cout << "\tLoaded image file, now converting to game tile data.\n";
	return LoadTileFromMemory(tileData,width,height);
}
//Load a game tile from memory
//pending
GameTile * GameTile::LoadTileFromMemory(const vector<unsigned char> & tileData, unsigned int width, unsigned int height) {
	_ASSERTE(tileData.size() == (width*height*4));
	cout << "Starting Load of tile from memory\n";
	GameTile * tile = new GameTile((int)width,(int)height);
	for (unsigned int i = 0; i < tileData.size(); i+= 4) {
		//Load every RGBA pixel into a tile cell
		tile->Cells[i/4].height = tileData[i+0];
		tile->Cells[i/4].materialId = tileData[i+1];
		//Stack height must be calculated separately
		tile->Cells[i/4].stackHeight = 0;
	}

	cout << "\tLoaded game tile data. Now building stacks.\n";
	tile->CalculateStackSizes(1,1,width-1,height-1);

	cout << "\tTile Load Complete.\n";
	return tile;
}

void GameTile::CalculateStackSizes(unsigned int rx, unsigned int ry, unsigned int tox, unsigned int toy) {
	for (unsigned int x = rx; x < tox; x++) {
		for (unsigned int y = ry; y < toy; y++) {
			unsigned char lowestHeight;
			unsigned char checkHeight;
			//Your stack size is the stack necessary to
			//cover up the hole between you and your lowest neighboring voxel
			//so first find the lowest neighboring voxel
			lowestHeight = Cells[y*(int)Width + (x + 1)].height;

			if ((checkHeight = Cells[y*(int)Width + (x - 1)].height) < lowestHeight)
				lowestHeight = checkHeight;
			if ((checkHeight = Cells[(y + 1)*(int)Width + x].height) < lowestHeight)
				lowestHeight = checkHeight;
			if ((checkHeight = Cells[(y - 1)*(int)Width + x].height) < lowestHeight)
				lowestHeight = checkHeight;
			//Now determine the stack height based off of the lowest height around you
			if ((x == 255 || x == 0 )|| (y==0 || y == 255)) lowestHeight -= 3;
			unsigned char myHeight = Cells[y*(int)Width+x].height;
			if (lowestHeight < myHeight)
				Cells[y*(int)Width+x].stackHeight = myHeight-lowestHeight;
		}
	}
}

TileCell * GameTile::GetTileCell(vec2 pos) {
	_ASSERTE((pos.x >= 0) && (pos.y >= 0));
	_ASSERTE((pos.x < (float)Width) && (pos.y < (float)Height));
	//First lookup which tile the position is in
	int tileX = (int)floor(pos.x);
	int tileY = (int)floor(pos.y);

	return &Cells[tileY*Width+tileX];
}

//Carves a square crater from fx,fy to tox,toy to depth "depth" and adds all removed voxels
//to the removedVoxels value
void GameTile::Crater(int fx, int fy, int tox, int toy, int craterBottomZ, vector<vec4> & removedVoxels) {
	_ASSERTE((fx >= 0) && (fy >= 0));
	_ASSERTE((tox < (float)Width) && (toy < (float)Height));
	_ASSERTE((fx <= tox) && (fy <= toy));
	_ASSERTE(craterBottomZ > 0);

	for (int x = fx; x <= tox; x++) {
		for (int y = fy; y <= toy; y++) {
			TileCell& cell = Cells[y*Width+x];
			int height = cell.height;
			int heightDiff = height-craterBottomZ;
			//Skip where the terrain does not intersect the crater
			if (heightDiff < 0)
				break;
			//Keep track of all removed voxels
			while (heightDiff >= 0) {
				removedVoxels.push_back(vec4(x+(tile_x*256),y+(tile_y*256),height,cell.materialId));
				heightDiff--;
				height--;
			}
			//Alter the height to create the crater
			Cells[y*Width+x].height = craterBottomZ-1;
		}
	}
	//Alter the values to be large enough for stack calculation
	fx--;
	fy--;
	tox+=2;
	toy+=2;
	//Limit the values to valid ranges
	if (fx < 1)
		fx = 1;
	if (fy < 1)
		fy = 1;
	if (tox > Width-1)
		tox = Width-1;
	if (toy > Height-1)
		toy = Height-1;
	//Rebuild the stack heights in this region
	CalculateStackSizes(fx,fy,tox,toy);
}

//Save the tile to disk
void GameTile::SaveTile(string saveName) {
	//stub
}
<commit_msg>Added some default stack height to edges in a quick patch for tile holes<commit_after>#include "stdafx.h"
#include "GameTile.h"
#include "lodepng.h"

GameTile::GameTile(int width, int height) {
	this->Width = width;
	this->Height = height;
	Cells = new TileCell[width*height];
}
GameTile::~GameTile() {
	delete [] Cells;
}

//Load a game tile from disk
GameTile * GameTile::LoadTileFromDisk(string tileImagePath) {
	unsigned int width;
	unsigned int height;
	vector<unsigned char> tileData;

	cout << "Starting load of tile \"" << tileImagePath << "\"\n";
	//First load the tile map data from the image
	if (lodepng::decode(tileData,width,height,tileImagePath)) {
		cout << "\tImage load failed.\n";
		//Error
		return NULL;
	}
	cout << "\tLoaded image file, now converting to game tile data.\n";
	return LoadTileFromMemory(tileData,width,height);
}
//Load a game tile from memory
//pending
GameTile * GameTile::LoadTileFromMemory(const vector<unsigned char> & tileData, unsigned int width, unsigned int height) {
	_ASSERTE(tileData.size() == (width*height*4));
	cout << "Starting Load of tile from memory\n";
	GameTile * tile = new GameTile((int)width,(int)height);
	for (unsigned int i = 0; i < tileData.size(); i+= 4) {
		//Load every RGBA pixel into a tile cell
		tile->Cells[i/4].height = tileData[i+0];
		tile->Cells[i/4].materialId = tileData[i+1];
		//Stack height must be calculated separately
		tile->Cells[i/4].stackHeight = 0;
	}

	cout << "\tLoaded game tile data. Now building stacks.\n";
	tile->CalculateStackSizes(1,1,width-1,height-1);

	//Patch edge stack heights to be 2 (3 height) to cover most holes
	for (unsigned int i = 0; i < width; i++) {
		tile->Cells[i].stackHeight = 2;
		tile->Cells[i+(height-1)*width].stackHeight = 2;
	}
	for (unsigned int i = 0; i < height; i++) {
		tile->Cells[i*width + 0].stackHeight = 2;
		tile->Cells[i*width + height - 1].stackHeight = 2;
	}

	cout << "\tTile Load Complete.\n";
	return tile;
}

void GameTile::CalculateStackSizes(unsigned int rx, unsigned int ry, unsigned int tox, unsigned int toy) {
	for (unsigned int x = rx; x < tox; x++) {
		for (unsigned int y = ry; y < toy; y++) {
			unsigned char lowestHeight;
			unsigned char checkHeight;
			//Your stack size is the stack necessary to
			//cover up the hole between you and your lowest neighboring voxel
			//so first find the lowest neighboring voxel
			lowestHeight = Cells[y*(int)Width + (x + 1)].height;

			if ((checkHeight = Cells[y*(int)Width + (x - 1)].height) < lowestHeight)
				lowestHeight = checkHeight;
			if ((checkHeight = Cells[(y + 1)*(int)Width + x].height) < lowestHeight)
				lowestHeight = checkHeight;
			if ((checkHeight = Cells[(y - 1)*(int)Width + x].height) < lowestHeight)
				lowestHeight = checkHeight;
			//Now determine the stack height based off of the lowest height around you
			unsigned char myHeight = Cells[y*(int)Width+x].height;
			if (lowestHeight < myHeight)
				Cells[y*(int)Width+x].stackHeight = myHeight-lowestHeight;
		}
	}
}

TileCell * GameTile::GetTileCell(vec2 pos) {
	_ASSERTE((pos.x >= 0) && (pos.y >= 0));
	_ASSERTE((pos.x < (float)Width) && (pos.y < (float)Height));
	//First lookup which tile the position is in
	int tileX = (int)floor(pos.x);
	int tileY = (int)floor(pos.y);

	return &Cells[tileY*Width+tileX];
}

//Carves a square crater from fx,fy to tox,toy to depth "depth" and adds all removed voxels
//to the removedVoxels value
void GameTile::Crater(int fx, int fy, int tox, int toy, int craterBottomZ, vector<vec4> & removedVoxels) {
	_ASSERTE((fx >= 0) && (fy >= 0));
	_ASSERTE((tox < (float)Width) && (toy < (float)Height));
	_ASSERTE((fx <= tox) && (fy <= toy));
	_ASSERTE(craterBottomZ > 0);

	for (int x = fx; x <= tox; x++) {
		for (int y = fy; y <= toy; y++) {
			TileCell& cell = Cells[y*Width+x];
			int height = cell.height;
			int heightDiff = height-craterBottomZ;
			//Skip where the terrain does not intersect the crater
			if (heightDiff < 0)
				break;
			//Keep track of all removed voxels
			while (heightDiff >= 0) {
				removedVoxels.push_back(vec4(x+(tile_x*256),y+(tile_y*256),height,cell.materialId));
				heightDiff--;
				height--;
			}
			//Alter the height to create the crater
			Cells[y*Width+x].height = craterBottomZ-1;
		}
	}
	//Alter the values to be large enough for stack calculation
	fx--;
	fy--;
	tox+=2;
	toy+=2;
	//Limit the values to valid ranges
	if (fx < 1)
		fx = 1;
	if (fy < 1)
		fy = 1;
	if (tox > Width-1)
		tox = Width-1;
	if (toy > Height-1)
		toy = Height-1;
	//Rebuild the stack heights in this region
	CalculateStackSizes(fx,fy,tox,toy);
}

//Save the tile to disk
void GameTile::SaveTile(string saveName) {
	//stub
}
<|endoftext|>


<commit_before>/**
  @file SaveData.cpp

  The save data format(little endian):
  int32_t record count
  [
    int64_t record time
	int16_t level
	int16_t  year
	int8_t  month
	int8_t  day
	int8_t  hour
	int8_t  minit
	int8_t  second
	] x (record count)
*/
#include "SaveData.h"
#include <vector>
#include <algorithm>
#include <limits>
#include <ctime>

#ifdef __ANDROID__
#include "android_native_app_glue.h"
#include <android/log.h>
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "SunnySideUp.SaveData", __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "SunnySideUp.SaveData", __VA_ARGS__))
#else
#define LOGI(...) ((void)printf(__VA_ARGS__), (void)printf("\n"))
#define LOGE(...) ((void)printf(__VA_ARGS__), (void)printf("\n"))
#endif // __ANDROID__

namespace SunnySideUp {

namespace SaveData {

/// Save data filename.
static const char recordFilename[] = "SunnySideUpRecords";

/// Best record of each level.
std::vector<Record>  bestRecords;

/** Get a value from the byte stream.

  @param p     The pointer to the byte stream.
  @param size  The data size(unit:byte).

  @return A value maked from the byte stream.

  Note that 'p' is advanced 'size' byte.
*/
int64_t GetValue(const uint8_t*& p, size_t size) {
  int64_t result = 0;
  int64_t scale = 1;
  for (size_t i = 0; i < size; ++i, ++p) {
	result += *p * scale;
	scale *= 0x100LL;
  }
  return result;
}

/** Set a value to the byte stream.

  @param p     The pointer to the byte stream.
  @param size  The data size(unit:byte).
  @param value A value that will be storing to 'p'.

  Note that 'p' is advanced 'size' byte.
*/
void SetValue(uint8_t*& p, size_t size, int64_t value) {
  for (size_t i = 0; i < size; ++i, ++p) {
	*p = value % 0xffLL;
	value /= 0x100LL;
  }
}

/** Write the record to file.

  @param  window  The window object.

  @sa PrepareSaveData()
*/
void WriteSaveData(const Mai::Window& window) {
  std::vector<uint8_t>  buf;
  buf.resize(bestRecords.size() * 17 + 4);
  uint8_t* p = buf.data();
  SetValue(p, 4, bestRecords.size());
  for (const auto& record : bestRecords) {
	SetValue(p, 8, record.time);
	SetValue(p, 2, record.level);
	SetValue(p, 2, record.year);
	SetValue(p, 1, record.month);
	SetValue(p, 1, record.day);
	SetValue(p, 1, record.hour);
	SetValue(p, 1, record.minit);
	SetValue(p, 1, record.second);
  }
  window.SaveUserFile(recordFilename, buf.data(), buf.size());
}

/** Load the save data.

  @param  window  The window object.

  @retval true  Success to load the save data.
  @retval false Failure. probably, play at first time.
*/
bool PrepareSaveData(const Mai::Window& window) {
  const size_t size = window.GetUserFileSize(recordFilename);
  if (size == 0) {
	return false;
  }
  std::vector<uint8_t> buf;
  buf.resize(size);
  if (!window.LoadUserFile(recordFilename, buf.data(), size)) {
	LOGI("No save data: %s", recordFilename);
	return false;
  }

  bestRecords.clear();
  const uint8_t* p = buf.data();
  const size_t recordCount = static_cast<size_t>(GetValue(p, 4));
  LOGI("recordCount: %d", recordCount);
  if (recordCount) {
	bestRecords.resize(recordCount);
	for (size_t i = 0; i < recordCount; ++i) {
	  Record record;
	  record.time = static_cast<int64_t>(GetValue(p, 8));
	  record.level = static_cast<int16_t>(GetValue(p, 2));
	  record.year = static_cast<int16_t>(GetValue(p, 2));
	  record.month = static_cast<int8_t>(GetValue(p, 1));
	  record.day = static_cast<int8_t>(GetValue(p, 1));
	  record.hour = static_cast<int8_t>(GetValue(p, 1));
	  record.minit = static_cast<int8_t>(GetValue(p, 1));
	  record.second = static_cast<int8_t>(GetValue(p, 1));
	  LOGI("lv:%d time:%03.3f %d/%02d/%02d %02d:%02d", record.level, static_cast<float>(record.time) / 1000.0f, record.year + 1970, record.month, record.day, record.hour, record.minit);
	}
	std::sort(bestRecords.begin(), bestRecords.end(), [](const Record& lhs, const Record& rhs) { return lhs.level < rhs.level; });
	const auto end = bestRecords.end();
	auto itrStore = bestRecords.begin();
	for (auto itr = itrStore + 1; itr != end; ++itr) {
	  if (itr->level != itrStore->level) {
		++itrStore;
		if (itrStore != itr) {
		  *itrStore = *itr;
		}
		continue;
	  }
	  if (itr->time < itrStore->time) {
		*itrStore = *itr;
	  }
	}
	bestRecords.erase(itrStore + 1, bestRecords.end());
  }
  return true;
}

/** Get a best record.

  @param level  The target level.

  @return Ff the record exist, boost::optional contain a best record for the level.
          Otherwise boost::none.
*/
boost::optional<Record> GetBestRecord(int level) {
  const auto itr = std::find_if(bestRecords.begin(), bestRecords.end(), [level](const Record& e) {return e.level == level; });
  if (itr == bestRecords.end()) {
	return boost::none;
  }
  return *itr;
}

/** Set new record.

  @param window      The window object.
  @param level       The target level.
  @param recordTime  A new time of the level.

  @retval true   The best record was overwritten by the 'recordTime'.
  @retval false  'recordTime' did not exceed the best record.
*/
bool SetNewRecord(const Mai::Window& window, int level, int64_t recordTime) {
  time_t currentTime;
  time(&currentTime);
  const struct tm* pGMT = gmtime(&currentTime);
  if (!pGMT) {
	LOGE("ERROR in SetNewRecord: gmtime failed(time:%lld)", currentTime);
	return false;
  }
  Record record;
  record.time = recordTime;
  record.level = static_cast<int16_t>(level);
  record.year = static_cast<int16_t>(pGMT->tm_year);
  record.month = static_cast<int8_t>(pGMT->tm_mon);
  record.day = static_cast<int8_t>(pGMT->tm_mday);
  record.hour = static_cast<int8_t>(pGMT->tm_hour);
  record.minit = static_cast<int8_t>(pGMT->tm_min);
  record.second = static_cast<int8_t>(pGMT->tm_sec);

  const auto itr = std::find_if(bestRecords.begin(), bestRecords.end(), [level](const Record& e) {return e.level == level; });
  if (itr == bestRecords.end()) {
	LOGI("Add new record:%lld", recordTime);
	bestRecords.push_back(record);
	WriteSaveData(window);
	return true;
  }
  if (record.time < itr->time) {
	LOGI("Update by new record:%lld -> %lld", itr->time, recordTime);
	*itr = record;
	WriteSaveData(window);
	return true;
  }
  return false;
}

} // namespace SaveData;

} // namespace SunnySideUp
<commit_msg>Correct a printf format string.<commit_after>/**
  @file SaveData.cpp

  The save data format(little endian):
  int32_t record count
  [
    int64_t record time
	int16_t level
	int16_t  year
	int8_t  month
	int8_t  day
	int8_t  hour
	int8_t  minit
	int8_t  second
	] x (record count)
*/
#include "SaveData.h"
#include <vector>
#include <algorithm>
#include <limits>
#include <ctime>

#ifdef __ANDROID__
#include "android_native_app_glue.h"
#include <android/log.h>
#define LOGI(...) ((void)__android_log_print(ANDROID_LOG_INFO, "SunnySideUp.SaveData", __VA_ARGS__))
#define LOGE(...) ((void)__android_log_print(ANDROID_LOG_ERROR, "SunnySideUp.SaveData", __VA_ARGS__))
#else
#define LOGI(...) ((void)printf(__VA_ARGS__), (void)printf("\n"))
#define LOGE(...) ((void)printf(__VA_ARGS__), (void)printf("\n"))
#endif // __ANDROID__

namespace SunnySideUp {

namespace SaveData {

/// Save data filename.
static const char recordFilename[] = "SunnySideUpRecords";

/// Best record of each level.
std::vector<Record>  bestRecords;

/** Get a value from the byte stream.

  @param p     The pointer to the byte stream.
  @param size  The data size(unit:byte).

  @return A value maked from the byte stream.

  Note that 'p' is advanced 'size' byte.
*/
int64_t GetValue(const uint8_t*& p, size_t size) {
  int64_t result = 0;
  int64_t scale = 1;
  for (size_t i = 0; i < size; ++i, ++p) {
	result += *p * scale;
	scale *= 0x100LL;
  }
  return result;
}

/** Set a value to the byte stream.

  @param p     The pointer to the byte stream.
  @param size  The data size(unit:byte).
  @param value A value that will be storing to 'p'.

  Note that 'p' is advanced 'size' byte.
*/
void SetValue(uint8_t*& p, size_t size, int64_t value) {
  for (size_t i = 0; i < size; ++i, ++p) {
	*p = value % 0xffLL;
	value /= 0x100LL;
  }
}

/** Write the record to file.

  @param  window  The window object.

  @sa PrepareSaveData()
*/
void WriteSaveData(const Mai::Window& window) {
  std::vector<uint8_t>  buf;
  buf.resize(bestRecords.size() * 17 + 4);
  uint8_t* p = buf.data();
  SetValue(p, 4, bestRecords.size());
  for (const auto& record : bestRecords) {
	SetValue(p, 8, record.time);
	SetValue(p, 2, record.level);
	SetValue(p, 2, record.year);
	SetValue(p, 1, record.month);
	SetValue(p, 1, record.day);
	SetValue(p, 1, record.hour);
	SetValue(p, 1, record.minit);
	SetValue(p, 1, record.second);
  }
  window.SaveUserFile(recordFilename, buf.data(), buf.size());
}

/** Load the save data.

  @param  window  The window object.

  @retval true  Success to load the save data.
  @retval false Failure. probably, play at first time.
*/
bool PrepareSaveData(const Mai::Window& window) {
  const size_t size = window.GetUserFileSize(recordFilename);
  if (size == 0) {
	return false;
  }
  std::vector<uint8_t> buf;
  buf.resize(size);
  if (!window.LoadUserFile(recordFilename, buf.data(), size)) {
	LOGI("No save data: %s", recordFilename);
	return false;
  }

  bestRecords.clear();
  const uint8_t* p = buf.data();
  const size_t recordCount = static_cast<size_t>(GetValue(p, 4));
  LOGI("recordCount: %d", recordCount);
  if (recordCount) {
	bestRecords.resize(recordCount);
	for (size_t i = 0; i < recordCount; ++i) {
	  Record record;
	  record.time = static_cast<int64_t>(GetValue(p, 8));
	  record.level = static_cast<int16_t>(GetValue(p, 2));
	  record.year = static_cast<int16_t>(GetValue(p, 2));
	  record.month = static_cast<int8_t>(GetValue(p, 1));
	  record.day = static_cast<int8_t>(GetValue(p, 1));
	  record.hour = static_cast<int8_t>(GetValue(p, 1));
	  record.minit = static_cast<int8_t>(GetValue(p, 1));
	  record.second = static_cast<int8_t>(GetValue(p, 1));
	  LOGI("lv:%d time:%03.3f %d/%02d/%02d %02d:%02d", record.level, static_cast<float>(record.time) / 1000.0f, record.year + 1970, record.month, record.day, record.hour, record.minit);
	}
	std::sort(bestRecords.begin(), bestRecords.end(), [](const Record& lhs, const Record& rhs) { return lhs.level < rhs.level; });
	const auto end = bestRecords.end();
	auto itrStore = bestRecords.begin();
	for (auto itr = itrStore + 1; itr != end; ++itr) {
	  if (itr->level != itrStore->level) {
		++itrStore;
		if (itrStore != itr) {
		  *itrStore = *itr;
		}
		continue;
	  }
	  if (itr->time < itrStore->time) {
		*itrStore = *itr;
	  }
	}
	bestRecords.erase(itrStore + 1, bestRecords.end());
  }
  return true;
}

/** Get a best record.

  @param level  The target level.

  @return Ff the record exist, boost::optional contain a best record for the level.
          Otherwise boost::none.
*/
boost::optional<Record> GetBestRecord(int level) {
  const auto itr = std::find_if(bestRecords.begin(), bestRecords.end(), [level](const Record& e) {return e.level == level; });
  if (itr == bestRecords.end()) {
	return boost::none;
  }
  return *itr;
}

/** Set new record.

  @param window      The window object.
  @param level       The target level.
  @param recordTime  A new time of the level.

  @retval true   The best record was overwritten by the 'recordTime'.
  @retval false  'recordTime' did not exceed the best record.
*/
bool SetNewRecord(const Mai::Window& window, int level, int64_t recordTime) {
  time_t currentTime;
  time(&currentTime);
  const struct tm* pGMT = gmtime(&currentTime);
  if (!pGMT) {
	LOGE("ERROR in SetNewRecord: gmtime failed(time:%ld)", currentTime);
	return false;
  }
  Record record;
  record.time = recordTime;
  record.level = static_cast<int16_t>(level);
  record.year = static_cast<int16_t>(pGMT->tm_year);
  record.month = static_cast<int8_t>(pGMT->tm_mon);
  record.day = static_cast<int8_t>(pGMT->tm_mday);
  record.hour = static_cast<int8_t>(pGMT->tm_hour);
  record.minit = static_cast<int8_t>(pGMT->tm_min);
  record.second = static_cast<int8_t>(pGMT->tm_sec);

  const auto itr = std::find_if(bestRecords.begin(), bestRecords.end(), [level](const Record& e) {return e.level == level; });
  if (itr == bestRecords.end()) {
	LOGI("Add new record:%lld", recordTime);
	bestRecords.push_back(record);
	WriteSaveData(window);
	return true;
  }
  if (record.time < itr->time) {
	LOGI("Update by new record:%lld -> %lld", itr->time, recordTime);
	*itr = record;
	WriteSaveData(window);
	return true;
  }
  return false;
}

} // namespace SaveData;

} // namespace SunnySideUp
<|endoftext|>


<commit_before>/**
 * @file viterbi_scorer.cpp
 * @author Chase Geigle
 */

#include "sequence/crf/viterbi_scorer.h"

namespace meta
{
namespace sequence
{

crf::viterbi_scorer::viterbi_scorer(const crf& model)
    : model_{&model}
{
    // these only ever need computing once because the underlying model is
    // not changing
    scorer_.transition_scores(*model_);
}

viterbi_trellis crf::viterbi_scorer::viterbi(const sequence& seq)
{
    // we only need the scores for the states as the transition scores, set
    // up during construction, will never change between sequences
    scorer_.state_scores(*model_, seq);

    viterbi_trellis table{seq.size(), model_->num_labels()};

    // initialize first column of trellis. We use the original state() and
    // trans() matrices because we are working in the log domain.
    for (label_id lbl{0}; lbl < model_->num_labels(); ++lbl)
        table.probability(0, lbl, scorer_.state(0, lbl));

    // compute remaining columns of trellis using recursive formulation
    for (uint64_t t = 1; t < seq.size(); ++t)
    {
        for (label_id lbl{0}; lbl < model_->num_labels(); ++lbl)
        {
            double max_score = std::numeric_limits<double>::min();
            for (label_id in{0}; in < model_->num_labels(); ++in)
            {
                auto score = table.probability(t - 1, in)
                             + scorer_.trans(lbl, in);

                if (score > max_score)
                {
                    max_score = score;
                    table.previous_tag(t, lbl, in);
                }
            }
            table.probability(t, lbl, max_score + scorer_.state(t, lbl));
        }
    }
    return table;
}

}
}
<commit_msg>Fix incorrect transition score use in Viterbi.<commit_after>/**
 * @file viterbi_scorer.cpp
 * @author Chase Geigle
 */

#include "sequence/crf/viterbi_scorer.h"

namespace meta
{
namespace sequence
{

crf::viterbi_scorer::viterbi_scorer(const crf& model)
    : model_{&model}
{
    // these only ever need computing once because the underlying model is
    // not changing
    scorer_.transition_scores(*model_);
}

viterbi_trellis crf::viterbi_scorer::viterbi(const sequence& seq)
{
    // we only need the scores for the states as the transition scores, set
    // up during construction, will never change between sequences
    scorer_.state_scores(*model_, seq);

    viterbi_trellis table{seq.size(), model_->num_labels()};

    // initialize first column of trellis. We use the original state() and
    // trans() matrices because we are working in the log domain.
    for (label_id lbl{0}; lbl < model_->num_labels(); ++lbl)
        table.probability(0, lbl, scorer_.state(0, lbl));

    // compute remaining columns of trellis using recursive formulation
    for (uint64_t t = 1; t < seq.size(); ++t)
    {
        for (label_id lbl{0}; lbl < model_->num_labels(); ++lbl)
        {
            double max_score = std::numeric_limits<double>::min();
            for (label_id in{0}; in < model_->num_labels(); ++in)
            {
                auto score = table.probability(t - 1, in)
                             + scorer_.trans(in, lbl);

                if (score > max_score)
                {
                    max_score = score;
                    table.previous_tag(t, lbl, in);
                }
            }
            table.probability(t, lbl, max_score + scorer_.state(t, lbl));
        }
    }
    return table;
}

}
}
<|endoftext|>


<commit_before>/*
DisplayController.h - Library for Controlling a 14x28 bits FlipDot display sign using two FP2800A.
Created by Antonio Carioca, March 3, 2014.
*/

//#include "Arduino.h"

//#include <avr/pgmspace.h>
//#include "application.h"
#include "mark-iv-flip-dot-display-sign-14x28-controller.h"

/* CONSTANTS */
//const int DISPLAY_SIZE = 4;
const int DISPLAY_PIXEL_WIDTH = 28;
const int DISPLAY_PIXEL_HEIGHT = 14;
const int DISPLAY_SUBPANEL_QTY = 2;

//=== F O N T ===
// Font courtesy of aspro648
// coden taken from
// http://www.instructables.com/files/orig/FQC/A1CY/H5EW79JK/FQCA1CYH5EW79JK.txt
// The @ will display as space character.
// NOTE: MOVING ALL THE ARRAY BELOW TO PROGMEM

//DotDisplay::DotDisplay(int dataPin, int clockPin, int latchPin, int enableSubPanel1Pin, int enableSubPanel2Pin, int fontWidth, int fontHeight, prog_uchar fonteParam[][5]){
DotDisplay::DotDisplay(int dataPin, int clockPin, int latchPin,  int enableSubPanel1Pin, int enableSubPanel2Pin, int fontWidth, int fontHeight, byte fonteParam[][5]){

	pinMode(dataPin, OUTPUT);
	pinMode(clockPin, OUTPUT);
	pinMode(latchPin, OUTPUT);
	pinMode(enableSubPanel1Pin, OUTPUT);
	pinMode(enableSubPanel2Pin, OUTPUT);
	//disable FP2800A's
	digitalWrite(enableSubPanel1Pin, LOW);
	digitalWrite(enableSubPanel2Pin, LOW);

	_dataPin = dataPin;
	_clockPin = clockPin;
	_latchPin = latchPin;
	_enableSubPanel1Pin = enableSubPanel1Pin;
	_enableSubPanel2Pin = enableSubPanel2Pin;
	_fontWidth = fontWidth;
	_fontHeight = fontHeight;
	_fonteParam = fonteParam;

	//_maxNumRows = floor((DISPLAY_PIXEL_HEIGHT+1)/(_fontHeight));
	_maxNumRows = (int)((DISPLAY_PIXEL_HEIGHT+1)/(_fontHeight));
	//_maxRowLength = floor((DISPLAY_PIXEL_WIDTH * DISPLAY_SUBPANEL_QTY+1) / (_fontWidth+1));
	_maxRowLength = (int)((DISPLAY_PIXEL_WIDTH * DISPLAY_SUBPANEL_QTY+1) / (_fontWidth+1));
	_maxMessageLength = _maxRowLength * _maxNumRows;

}
/*
void DotDisplay::setSerial(HardwareSerial* hwPrint){
	printer = hwPrint; //operate on the address of print
	if(printer) {
		printer->begin(9600);
	}
}
*/

void DotDisplay::setDot(byte col, byte row, bool on){

	//accidentally reversed two data pins, so reversing back on the code here
	//on = !on;

	//2 pins - Data
	//5 pins - Column
	//4 pins - Rows

	//4 pins - Enable FP2800A (4 subpanels)
	byte subPanel = 1;
	//disable FP2800A's
	digitalWrite(_enableSubPanel1Pin, LOW);
	digitalWrite(_enableSubPanel2Pin, LOW);

	//enables next sunpanel
	if(col>=DISPLAY_PIXEL_WIDTH){
		//subPanel =  floor(col / DISPLAY_PIXEL_WIDTH)+1;
		subPanel =  (int)(col / DISPLAY_PIXEL_WIDTH)+1;
		col=col-DISPLAY_PIXEL_WIDTH;
	}

	/*
	if(printer) {
	printer->print("col: ");
	printer->print(col);
	printer->print(", ");
	printer->print("subPanel: ");
	printer->println(subPanel);
	}
	*/

	// IGNOREx4 + ROWx4 + IGNOREx1 + COLUMNx5 + DATAx2
	byte dataPins = on?1:2;
	byte colFirstThreeDigits = (col % 7)+1;
	//byte colLastTwoDigits = floor(col/7);
	byte colLastTwoDigits = (int)(col/7);
	byte colByte = colFirstThreeDigits | (colLastTwoDigits << 3);
	byte rowFirstThreeDigits = (row % 7)+1;
	byte rowLastDigit = row<7;
	byte rowByte = rowFirstThreeDigits | (rowLastDigit << 3);
	byte firstbyte = (dataPins) | (colByte << 2);
	byte secondbyte = rowByte;

	digitalWrite(_latchPin, LOW);
	shiftOut(_dataPin, _clockPin, LSBFIRST, firstbyte);
	shiftOut(_dataPin, _clockPin, LSBFIRST, secondbyte);
	digitalWrite(_latchPin, HIGH);
	//delay(1);

	//pulse the FP2800A's enable pins
	if(subPanel == 1){
		digitalWrite(_enableSubPanel1Pin, HIGH);
		delay(1);
		digitalWrite(_enableSubPanel1Pin, LOW);
	} else if (subPanel == 2) {
		digitalWrite(_enableSubPanel2Pin, HIGH);
		delay(1);
		digitalWrite(_enableSubPanel2Pin, LOW);
	}
}

//void DotDisplay::updateDisplay(char *textMessage){
void DotDisplay::updateDisplay(char textMessage[], char log[]){
	int currentColumn = 0;
	int currentRow = 0;

	//strcpy(log,"");

	//goes through all characters
	for (int ch = 0; ch < (_maxMessageLength);ch++){
		//get a character from the message
		int alphabetIndex = textMessage[ch] - ' '; //Subtract '@' so we get a number

		//Serial.println(alphabetIndex);
		if ((alphabetIndex < 0) or (ch >=strlen(textMessage))) alphabetIndex=0;

		//push it to the next row if necessary
		if((currentColumn + _fontWidth) > (DISPLAY_PIXEL_WIDTH * DISPLAY_SUBPANEL_QTY)){
			currentColumn=0;
			currentRow=currentRow+_fontHeight;
		}

		//set all the bits in the next _fontWidth columns on the display
		for(byte col = currentColumn; col<(currentColumn+_fontWidth); col++){

			byte calculatedColumn = (col)%(_fontWidth+1);
			//for(byte row = 0; row < _fontHeight; row++)
			int characterRow = 0;
			for(byte row = currentRow; row < (currentRow + _fontHeight); row++){
				//bool isOn = bitRead(pgm_read_byte(&(_fonteParam[alphabetIndex][calculatedColumn])),6-characterRow);
				bool isOn = bitRead((byte)_fonteParam[alphabetIndex][calculatedColumn],6-row);//this index is needed as we are going from back to front

				setDot(col, row, isOn);
				/*
				if(printer) {
					printer->print(isOn);
				}
				*/
				char dot[2];
				if (isOn) strcpy(dot,"1"); else strcpy(dot,"0");
				//strcat(log,dot);

				characterRow++;
			}
			/*
			if(printer) {
				printer->println("");
			}
			*/
			//strcat(log,"");
		}
		/*
		if(printer) {
			printer->println("*******");
		}
		*/
		//strcat(log,"*********");

		currentColumn = currentColumn+(_fontWidth+1);
	}
}
<commit_msg>Renabled a few strcpy's<commit_after>/*
DisplayController.h - Library for Controlling a 14x28 bits FlipDot display sign using two FP2800A.
Created by Antonio Carioca, March 3, 2014.
*/

//#include "Arduino.h"

//#include <avr/pgmspace.h>
//#include "application.h"
#include "mark-iv-flip-dot-display-sign-14x28-controller.h"

/* CONSTANTS */
//const int DISPLAY_SIZE = 4;
const int DISPLAY_PIXEL_WIDTH = 28;
const int DISPLAY_PIXEL_HEIGHT = 14;
const int DISPLAY_SUBPANEL_QTY = 2;

//=== F O N T ===
// Font courtesy of aspro648
// coden taken from
// http://www.instructables.com/files/orig/FQC/A1CY/H5EW79JK/FQCA1CYH5EW79JK.txt
// The @ will display as space character.
// NOTE: MOVING ALL THE ARRAY BELOW TO PROGMEM

//DotDisplay::DotDisplay(int dataPin, int clockPin, int latchPin, int enableSubPanel1Pin, int enableSubPanel2Pin, int fontWidth, int fontHeight, prog_uchar fonteParam[][5]){
DotDisplay::DotDisplay(int dataPin, int clockPin, int latchPin,  int enableSubPanel1Pin, int enableSubPanel2Pin, int fontWidth, int fontHeight, byte fonteParam[][5]){

	pinMode(dataPin, OUTPUT);
	pinMode(clockPin, OUTPUT);
	pinMode(latchPin, OUTPUT);
	pinMode(enableSubPanel1Pin, OUTPUT);
	pinMode(enableSubPanel2Pin, OUTPUT);
	//disable FP2800A's
	digitalWrite(enableSubPanel1Pin, LOW);
	digitalWrite(enableSubPanel2Pin, LOW);

	_dataPin = dataPin;
	_clockPin = clockPin;
	_latchPin = latchPin;
	_enableSubPanel1Pin = enableSubPanel1Pin;
	_enableSubPanel2Pin = enableSubPanel2Pin;
	_fontWidth = fontWidth;
	_fontHeight = fontHeight;
	_fonteParam = fonteParam;

	//_maxNumRows = floor((DISPLAY_PIXEL_HEIGHT+1)/(_fontHeight));
	_maxNumRows = (int)((DISPLAY_PIXEL_HEIGHT+1)/(_fontHeight));
	//_maxRowLength = floor((DISPLAY_PIXEL_WIDTH * DISPLAY_SUBPANEL_QTY+1) / (_fontWidth+1));
	_maxRowLength = (int)((DISPLAY_PIXEL_WIDTH * DISPLAY_SUBPANEL_QTY+1) / (_fontWidth+1));
	_maxMessageLength = _maxRowLength * _maxNumRows;

}
/*
void DotDisplay::setSerial(HardwareSerial* hwPrint){
	printer = hwPrint; //operate on the address of print
	if(printer) {
		printer->begin(9600);
	}
}
*/

void DotDisplay::setDot(byte col, byte row, bool on){

	//accidentally reversed two data pins, so reversing back on the code here
	//on = !on;

	//2 pins - Data
	//5 pins - Column
	//4 pins - Rows

	//4 pins - Enable FP2800A (4 subpanels)
	byte subPanel = 1;
	//disable FP2800A's
	digitalWrite(_enableSubPanel1Pin, LOW);
	digitalWrite(_enableSubPanel2Pin, LOW);

	//enables next sunpanel
	if(col>=DISPLAY_PIXEL_WIDTH){
		//subPanel =  floor(col / DISPLAY_PIXEL_WIDTH)+1;
		subPanel =  (int)(col / DISPLAY_PIXEL_WIDTH)+1;
		col=col-DISPLAY_PIXEL_WIDTH;
	}

	/*
	if(printer) {
	printer->print("col: ");
	printer->print(col);
	printer->print(", ");
	printer->print("subPanel: ");
	printer->println(subPanel);
	}
	*/

	// IGNOREx4 + ROWx4 + IGNOREx1 + COLUMNx5 + DATAx2
	byte dataPins = on?1:2;
	byte colFirstThreeDigits = (col % 7)+1;
	//byte colLastTwoDigits = floor(col/7);
	byte colLastTwoDigits = (int)(col/7);
	byte colByte = colFirstThreeDigits | (colLastTwoDigits << 3);
	byte rowFirstThreeDigits = (row % 7)+1;
	byte rowLastDigit = row<7;
	byte rowByte = rowFirstThreeDigits | (rowLastDigit << 3);
	byte firstbyte = (dataPins) | (colByte << 2);
	byte secondbyte = rowByte;

	digitalWrite(_latchPin, LOW);
	shiftOut(_dataPin, _clockPin, LSBFIRST, firstbyte);
	shiftOut(_dataPin, _clockPin, LSBFIRST, secondbyte);
	digitalWrite(_latchPin, HIGH);
	//delay(1);

	//pulse the FP2800A's enable pins
	if(subPanel == 1){
		digitalWrite(_enableSubPanel1Pin, HIGH);
		delay(1);
		digitalWrite(_enableSubPanel1Pin, LOW);
	} else if (subPanel == 2) {
		digitalWrite(_enableSubPanel2Pin, HIGH);
		delay(1);
		digitalWrite(_enableSubPanel2Pin, LOW);
	}
}

//void DotDisplay::updateDisplay(char *textMessage){
void DotDisplay::updateDisplay(char textMessage[], char log[]){
	int currentColumn = 0;
	int currentRow = 0;

	strcpy(log,"");

	//goes through all characters
	for (int ch = 0; ch < (_maxMessageLength);ch++){
		//get a character from the message
		int alphabetIndex = textMessage[ch] - ' '; //Subtract '@' so we get a number

		//Serial.println(alphabetIndex);
		if ((alphabetIndex < 0) or (ch >=strlen(textMessage))) alphabetIndex=0;

		//push it to the next row if necessary
		if((currentColumn + _fontWidth) > (DISPLAY_PIXEL_WIDTH * DISPLAY_SUBPANEL_QTY)){
			currentColumn=0;
			currentRow=currentRow+_fontHeight;
		}

		//set all the bits in the next _fontWidth columns on the display
		for(byte col = currentColumn; col<(currentColumn+_fontWidth); col++){

			byte calculatedColumn = (col)%(_fontWidth+1);
			//for(byte row = 0; row < _fontHeight; row++)
			int characterRow = 0;
			for(byte row = currentRow; row < (currentRow + _fontHeight); row++){
				//bool isOn = bitRead(pgm_read_byte(&(_fonteParam[alphabetIndex][calculatedColumn])),6-characterRow);
				bool isOn = bitRead((byte)_fonteParam[alphabetIndex][calculatedColumn],6-row);//this index is needed as we are going from back to front

				setDot(col, row, isOn);
				/*
				if(printer) {
					printer->print(isOn);
				}
				*/
				char dot[2];
				if (isOn) {
					strcpy(dot,"1");
				}else {
					strcpy(dot,"0");
				}
				//strcat(log,dot);

				characterRow++;
			}
			/*
			if(printer) {
				printer->println("");
			}
			*/
			strcat(log," ");
		}
		/*
		if(printer) {
			printer->println("*******");
		}
		*/
		strcat(log,"*********");

		currentColumn = currentColumn+(_fontWidth+1);
	}
}
<|endoftext|>