<commit_before>/*  This file is part of the KDE project
    Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
    Copyright (C) 2009 Martin Sandsmark <sandsmark@samfundet.no>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), Nokia Corporation
    (or its successors, if any) and the KDE Free Qt Foundation, which shall
    act as a proxy defined in Section 6 of version 3 of the license.

    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, see <http://www.gnu.org/licenses/>.

*/

#include "audiodataoutput.h"
#include "gsthelper.h"
#include "medianode.h"
#include "mediaobject.h"
#include <QtCore/QVector>
#include <QtCore/QMap>
#include <phonon/audiooutput.h>

namespace Phonon
{
namespace Gstreamer
{
AudioDataOutput::AudioDataOutput(Backend *backend, QObject *parent)
    : QObject(parent),
    MediaNode(backend, AudioSink | AudioSource)
{
    static int count = 0;
    m_name = "AudioDataOutput" + QString::number(count++);

    m_queue = gst_element_factory_make ("identify", NULL);
    gst_object_ref(m_queue);
    m_isValid = true;
}

AudioDataOutput::~AudioDataOutput()
{
    gst_element_set_state(m_queue, GST_STATE_NULL);
    gst_object_unref(m_queue);
}

int AudioDataOutput::dataSize() const
{
    return m_dataSize;
}

int AudioDataOutput::sampleRate() const
{
    return 44100;
}

void AudioDataOutput::setDataSize(int size)
{
    m_dataSize = size;
}

typedef QMap<Phonon::AudioDataOutput::Channel, QVector<float> > FloatMap;
typedef QMap<Phonon::AudioDataOutput::Channel, QVector<qint16> > IntMap;

inline void AudioDataOutput::convertAndEmit(const QVector<qint16> &leftBuffer, const QVector<qint16> &rightBuffer)
{
    //TODO: Floats
    IntMap map;
    map.insert(Phonon::AudioDataOutput::LeftChannel, leftBuffer);
    map.insert(Phonon::AudioDataOutput::RightChannel, rightBuffer);
    emit dataReady(map);
}

void AudioDataOutput::processBuffer(GstPad*, GstBuffer* buffer, gpointer gThat)
{
    // TODO emit endOfMedia
    AudioDataOutput *that = reinterpret_cast<AudioDataOutput*>(gThat);

    // determine the number of channels
    GstStructure* structure = gst_caps_get_structure (GST_BUFFER_CAPS(buffer), 0);
    gst_structure_get_int (structure, "channels", &that->m_channels);

    if (that->m_channels > 2 || that->m_channels < 0) {
        qWarning() << Q_FUNC_INFO << ": Number of channels not supported: " << that->m_channels;
        return;
    }

    gint16 *data = reinterpret_cast<gint16*>(GST_BUFFER_DATA(buffer));
    guint size = GST_BUFFER_SIZE(buffer) / sizeof(gint16);

    that->m_pendingData.reserve(that->m_pendingData.size() + size);

    for (uint i=0; i<size; i++) {
        // 8 bit? interleaved? yay for lacking documentation!
        that->m_pendingData.append(data[i]);
    }

    while (that->m_pendingData.size() > that->m_dataSize * that->m_channels) {
        if (that->m_channels == 1) {
            QVector<qint16> intBuffer(that->m_dataSize);
            memcpy(intBuffer.data(), that->m_pendingData.constData(), that->m_dataSize * sizeof(qint16));

            that->convertAndEmit(intBuffer, intBuffer);
            int newSize = that->m_pendingData.size() - that->m_dataSize;
            memmove(that->m_pendingData.data(), that->m_pendingData.constData() + that->m_dataSize, newSize * sizeof(qint16));
            that->m_pendingData.resize(newSize);
        } else {
            QVector<qint16> left(that->m_dataSize), right(that->m_dataSize);
            for (int i=0; i<that->m_dataSize; i++) {
                left[i] = that->m_pendingData[i*2];
                right[i] = that->m_pendingData[i*2+1];
            }
            that->m_pendingData.resize(that->m_pendingData.size() - that->m_dataSize*2);
            that->convertAndEmit(left, right);
        }
    }
}

void AudioDataOutput::mediaNodeEvent(const MediaNodeEvent *event)
{
    if (event->type() == MediaNodeEvent::MediaObjectConnected && root()) {
        g_object_set(G_OBJECT(audioElement()), "sync", true, (const char*)NULL);
        GstPad *audiopad = gst_element_get_pad (audioElement(), "src");
        gst_pad_add_buffer_probe (audiopad, G_CALLBACK(processBuffer), this);
        gst_object_unref (audiopad);
        return;
    }

    MediaNode::mediaNodeEvent(event);
}

}} //namespace Phonon::Gstreamer

#include "moc_audiodataoutput.cpp"
// vim: sw=4 ts=4

<commit_msg>typo (identify vs. identity)<commit_after>/*  This file is part of the KDE project
    Copyright (C) 2006 Matthias Kretz <kretz@kde.org>
    Copyright (C) 2009 Martin Sandsmark <sandsmark@samfundet.no>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Lesser General Public
    License as published by the Free Software Foundation; either
    version 2.1 of the License, or (at your option) version 3, or any
    later version accepted by the membership of KDE e.V. (or its
    successor approved by the membership of KDE e.V.), Nokia Corporation
    (or its successors, if any) and the KDE Free Qt Foundation, which shall
    act as a proxy defined in Section 6 of version 3 of the license.

    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, see <http://www.gnu.org/licenses/>.

*/

#include "audiodataoutput.h"
#include "gsthelper.h"
#include "medianode.h"
#include "mediaobject.h"
#include <QtCore/QVector>
#include <QtCore/QMap>
#include <phonon/audiooutput.h>

namespace Phonon
{
namespace Gstreamer
{
AudioDataOutput::AudioDataOutput(Backend *backend, QObject *parent)
    : QObject(parent),
    MediaNode(backend, AudioSink | AudioSource)
{
    static int count = 0;
    m_name = "AudioDataOutput" + QString::number(count++);

    m_queue = gst_element_factory_make ("identity", NULL);
    gst_object_ref(m_queue);
    m_isValid = true;
}

AudioDataOutput::~AudioDataOutput()
{
    gst_element_set_state(m_queue, GST_STATE_NULL);
    gst_object_unref(m_queue);
}

int AudioDataOutput::dataSize() const
{
    return m_dataSize;
}

int AudioDataOutput::sampleRate() const
{
    return 44100;
}

void AudioDataOutput::setDataSize(int size)
{
    m_dataSize = size;
}

typedef QMap<Phonon::AudioDataOutput::Channel, QVector<float> > FloatMap;
typedef QMap<Phonon::AudioDataOutput::Channel, QVector<qint16> > IntMap;

inline void AudioDataOutput::convertAndEmit(const QVector<qint16> &leftBuffer, const QVector<qint16> &rightBuffer)
{
    //TODO: Floats
    IntMap map;
    map.insert(Phonon::AudioDataOutput::LeftChannel, leftBuffer);
    map.insert(Phonon::AudioDataOutput::RightChannel, rightBuffer);
    emit dataReady(map);
}

void AudioDataOutput::processBuffer(GstPad*, GstBuffer* buffer, gpointer gThat)
{
    // TODO emit endOfMedia
    AudioDataOutput *that = reinterpret_cast<AudioDataOutput*>(gThat);

    // determine the number of channels
    GstStructure* structure = gst_caps_get_structure (GST_BUFFER_CAPS(buffer), 0);
    gst_structure_get_int (structure, "channels", &that->m_channels);

    if (that->m_channels > 2 || that->m_channels < 0) {
        qWarning() << Q_FUNC_INFO << ": Number of channels not supported: " << that->m_channels;
        return;
    }

    gint16 *data = reinterpret_cast<gint16*>(GST_BUFFER_DATA(buffer));
    guint size = GST_BUFFER_SIZE(buffer) / sizeof(gint16);

    that->m_pendingData.reserve(that->m_pendingData.size() + size);

    for (uint i=0; i<size; i++) {
        // 8 bit? interleaved? yay for lacking documentation!
        that->m_pendingData.append(data[i]);
    }

    while (that->m_pendingData.size() > that->m_dataSize * that->m_channels) {
        if (that->m_channels == 1) {
            QVector<qint16> intBuffer(that->m_dataSize);
            memcpy(intBuffer.data(), that->m_pendingData.constData(), that->m_dataSize * sizeof(qint16));

            that->convertAndEmit(intBuffer, intBuffer);
            int newSize = that->m_pendingData.size() - that->m_dataSize;
            memmove(that->m_pendingData.data(), that->m_pendingData.constData() + that->m_dataSize, newSize * sizeof(qint16));
            that->m_pendingData.resize(newSize);
        } else {
            QVector<qint16> left(that->m_dataSize), right(that->m_dataSize);
            for (int i=0; i<that->m_dataSize; i++) {
                left[i] = that->m_pendingData[i*2];
                right[i] = that->m_pendingData[i*2+1];
            }
            that->m_pendingData.resize(that->m_pendingData.size() - that->m_dataSize*2);
            that->convertAndEmit(left, right);
        }
    }
}

void AudioDataOutput::mediaNodeEvent(const MediaNodeEvent *event)
{
    if (event->type() == MediaNodeEvent::MediaObjectConnected && root()) {
        g_object_set(G_OBJECT(audioElement()), "sync", true, (const char*)NULL);
        GstPad *audiopad = gst_element_get_pad (audioElement(), "src");
        gst_pad_add_buffer_probe (audiopad, G_CALLBACK(processBuffer), this);
        gst_object_unref (audiopad);
        return;
    }

    MediaNode::mediaNodeEvent(event);
}

}} //namespace Phonon::Gstreamer

#include "moc_audiodataoutput.cpp"
// vim: sw=4 ts=4

<|endoftext|>


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

#include "common/main_delegate.h"

#include "browser/browser_client.h"
#include "common/content_client.h"

#include "base/command_line.h"
#include "base/path_service.h"
#include "content/public/common/content_switches.h"
#include "ui/base/resource/resource_bundle.h"

namespace brightray {

MainDelegate::MainDelegate() {
}

MainDelegate::~MainDelegate() {
}

scoped_ptr<ContentClient> MainDelegate::CreateContentClient() {
  return make_scoped_ptr(new ContentClient).Pass();
}

bool MainDelegate::BasicStartupComplete(int* exit_code) {
  content_client_ = CreateContentClient().Pass();
  SetContentClient(content_client_.get());
  return false;
}

void MainDelegate::PreSandboxStartup() {
#if defined(OS_MACOSX)
  OverrideChildProcessPath();
  OverrideFrameworkBundlePath();
#endif
  InitializeResourceBundle();
}

void MainDelegate::InitializeResourceBundle() {
  base::FilePath path;
#if defined(OS_MACOSX)
  path = GetResourcesPakFilePath();
#else
  base::FilePath pak_dir;
  PathService::Get(base::DIR_MODULE, &pak_dir);
  path = pak_dir.Append(FILE_PATH_LITERAL("content_shell.pak"));
#endif

  ui::ResourceBundle::InitSharedInstanceWithPakPath(path);

  std::vector<base::FilePath> pak_paths;
  AddPakPaths(&pak_paths);
  for (auto it = pak_paths.begin(), end = pak_paths.end(); it != end; ++it) {
    ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
        *it, ui::SCALE_FACTOR_NONE);
  }
}

content::ContentBrowserClient* MainDelegate::CreateContentBrowserClient() {
  browser_client_ = CreateBrowserClient().Pass();
  return browser_client_.get();
}

scoped_ptr<BrowserClient> MainDelegate::CreateBrowserClient() {
  return make_scoped_ptr(new BrowserClient).Pass();
}

}  // namespace brightray
<commit_msg>Fix assertion in InitializeICU on launch<commit_after>// Copyright (c) 2012 The Chromium Authors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE-CHROMIUM file.

#include "common/main_delegate.h"

#include "browser/browser_client.h"
#include "common/content_client.h"

#include "base/command_line.h"
#include "base/path_service.h"
#include "content/public/common/content_switches.h"
#include "ui/base/resource/resource_bundle.h"

namespace brightray {

MainDelegate::MainDelegate() {
}

MainDelegate::~MainDelegate() {
}

scoped_ptr<ContentClient> MainDelegate::CreateContentClient() {
  return make_scoped_ptr(new ContentClient).Pass();
}

bool MainDelegate::BasicStartupComplete(int* exit_code) {
  content_client_ = CreateContentClient().Pass();
  SetContentClient(content_client_.get());
#if defined(OS_MACOSX)
  OverrideChildProcessPath();
  OverrideFrameworkBundlePath();
#endif
  return false;
}

void MainDelegate::PreSandboxStartup() {
  InitializeResourceBundle();
}

void MainDelegate::InitializeResourceBundle() {
  base::FilePath path;
#if defined(OS_MACOSX)
  path = GetResourcesPakFilePath();
#else
  base::FilePath pak_dir;
  PathService::Get(base::DIR_MODULE, &pak_dir);
  path = pak_dir.Append(FILE_PATH_LITERAL("content_shell.pak"));
#endif

  ui::ResourceBundle::InitSharedInstanceWithPakPath(path);

  std::vector<base::FilePath> pak_paths;
  AddPakPaths(&pak_paths);
  for (auto it = pak_paths.begin(), end = pak_paths.end(); it != end; ++it) {
    ui::ResourceBundle::GetSharedInstance().AddDataPackFromPath(
        *it, ui::SCALE_FACTOR_NONE);
  }
}

content::ContentBrowserClient* MainDelegate::CreateContentBrowserClient() {
  browser_client_ = CreateBrowserClient().Pass();
  return browser_client_.get();
}

scoped_ptr<BrowserClient> MainDelegate::CreateBrowserClient() {
  return make_scoped_ptr(new BrowserClient).Pass();
}

}  // namespace brightray
<|endoftext|>


<commit_before>
#include <node.h>

#ifdef WIN32
#include <windows.h>
#endif

using namespace v8;
using namespace node;

Handle<Value> load(const Arguments& args)
{
    HandleScope scope;

    if (args.Length() < 1 || !args[0]->IsString()) {
        return ThrowException(
            Exception::Error(String::New("Missing param: load(pythonHome).")));
    }

    String::Utf8Value pythonHome(args[0]->ToString());

#ifdef WIN32
    char lpPathStringA[MAX_PATH];
    wchar_t lpPathStringW[MAX_PATH];

    sprintf(lpPathStringA, "%s", *pythonHome);
    MultiByteToWideChar(CP_UTF8, 0, lpPathStringA, -1, lpPathStringW, MAX_PATH);
    if (!SetEnvironmentVariable(L"PYTHONHOME", lpPathStringW)) {
        return ThrowException(
            Exception::Error(String::New("Failed to set environment variable: PYTHONHOME.")));
    }

    sprintf(lpPathStringA, "%s\\python27.dll", *pythonHome);
    MultiByteToWideChar(CP_UTF8, 0, lpPathStringA, -1, lpPathStringW, MAX_PATH);
    if (LoadLibrary(lpPathStringW) == NULL) {
        return ThrowException(
            Exception::Error(String::New("Failed to load library: python27.dll.")));
    }

    sprintf(lpPathStringA, "%s\\pywintypes27.dll", *pythonHome);
    MultiByteToWideChar(CP_UTF8, 0,lpPathStringA, -1, lpPathStringW, MAX_PATH);
    if (LoadLibrary(lpPathStringW) == NULL) {
        return ThrowException(
            Exception::Error(String::New("Failed to load library: pywintypes27.dll.")));
    }

    sprintf(lpPathStringA, "%s\\pythoncomloader27.dll", *pythonHome);
    MultiByteToWideChar(CP_UTF8, 0, lpPathStringA, -1, lpPathStringW, MAX_PATH);
    if (LoadLibrary(lpPathStringW) == NULL) {
        return ThrowException(
            Exception::Error(String::New("Failed to load library: pythoncomloader27.dll.")));
    }

    sprintf(lpPathStringA, "%s\\pythoncom27.dll", *pythonHome);
    MultiByteToWideChar(CP_UTF8, 0, lpPathStringA, -1, lpPathStringW, MAX_PATH);
    if (LoadLibrary(lpPathStringW) == NULL) {
        return ThrowException(
            Exception::Error(String::New("FFailed to load library: pythoncom27.dll.")));
    }
#elif __APPLE__
    setenv("PYTHONHOME", *pythonHome, 1);
#endif

    return Undefined();
}

void init(Handle<Object> exports)
{
    HandleScope scope;

    // module.exports.load
    exports->Set(String::NewSymbol("load"),
        FunctionTemplate::New(load)->GetFunction());
}

NODE_MODULE(binding, init)
<commit_msg>update for nodejs(0.12.0), v8(3.28.73); available for nw.js(0.11.6), nodejs(0.11.13-pre), v8(3.22.24.19)<commit_after>
#include <node.h>

#ifdef WIN32
#include <windows.h>
#endif

using namespace v8;
using namespace node;

void load(const FunctionCallbackInfo<Value>& args)
{
    HandleScope scope(args.GetIsolate());

    if (args.Length() < 1 || !args[0]->IsString()) {
        args.GetReturnValue().Set(args.GetIsolate()->ThrowException(
            Exception::Error(String::NewFromUtf8(args.GetIsolate(), "Missing param: load(pythonHome)."))));
        return;
    }

    String::Utf8Value pythonHome(args[0]->ToString());

#ifdef WIN32
    char lpPathStringA[MAX_PATH];
    wchar_t lpPathStringW[MAX_PATH];

    sprintf(lpPathStringA, "%s", *pythonHome);
    MultiByteToWideChar(CP_UTF8, 0, lpPathStringA, -1, lpPathStringW, MAX_PATH);
    if (!SetEnvironmentVariable(L"PYTHONHOME", lpPathStringW)) {
        args.GetReturnValue().Set(args.GetIsolate()->ThrowException(
            Exception::Error(String::NewFromUtf8(args.GetIsolate(), "Failed to set environment variable: PYTHONHOME."))));
        return;
    }

    sprintf(lpPathStringA, "%s\\python27.dll", *pythonHome);
    MultiByteToWideChar(CP_UTF8, 0, lpPathStringA, -1, lpPathStringW, MAX_PATH);
    if (LoadLibrary(lpPathStringW) == NULL) {
        args.GetReturnValue().Set(args.GetIsolate()->ThrowException(
            Exception::Error(String::NewFromUtf8(args.GetIsolate(), "Failed to load library: python27.dll."))));
        return;
    }

    sprintf(lpPathStringA, "%s\\pywintypes27.dll", *pythonHome);
    MultiByteToWideChar(CP_UTF8, 0,lpPathStringA, -1, lpPathStringW, MAX_PATH);
    if (LoadLibrary(lpPathStringW) == NULL) {
        args.GetReturnValue().Set(args.GetIsolate()->ThrowException(
            Exception::Error(String::NewFromUtf8(args.GetIsolate(), "Failed to load library: pywintypes27.dll."))));
        return;
    }

    sprintf(lpPathStringA, "%s\\pythoncomloader27.dll", *pythonHome);
    MultiByteToWideChar(CP_UTF8, 0, lpPathStringA, -1, lpPathStringW, MAX_PATH);
    if (LoadLibrary(lpPathStringW) == NULL) {
        args.GetReturnValue().Set(args.GetIsolate()->ThrowException(
            Exception::Error(String::NewFromUtf8(args.GetIsolate(), "Failed to load library: pythoncomloader27.dll."))));
        return;
    }

    sprintf(lpPathStringA, "%s\\pythoncom27.dll", *pythonHome);
    MultiByteToWideChar(CP_UTF8, 0, lpPathStringA, -1, lpPathStringW, MAX_PATH);
    if (LoadLibrary(lpPathStringW) == NULL) {
        args.GetReturnValue().Set(args.GetIsolate()->ThrowException(
            Exception::Error(String::NewFromUtf8(args.GetIsolate(), "Failed to load library: pythoncom27.dll."))));
        return;
    }
#elif __APPLE__
    setenv("PYTHONHOME", *pythonHome, 1);
#endif

    args.GetReturnValue().Set(Undefined(args.GetIsolate()));
}

void init(Handle<Object> exports)
{
    HandleScope scope(Isolate::GetCurrent());

    // module.exports.load
    exports->Set(String::NewFromUtf8(Isolate::GetCurrent(), "load", String::kInternalizedString),
        FunctionTemplate::New(Isolate::GetCurrent(), load)->GetFunction());
}

NODE_MODULE(binding, init)
<|endoftext|>


<commit_before>#include "SafierWind.hpp"
#include "DebugUtils.hpp"
#include "IDiskHump.hpp"
#include <cmath>
#include <string>

struct SafierWindModel
{
    double dxi0;
    double a_1, a_2, a_3, a_4, a_5, a_6, a_7, a_8;
    double b_0, b_1, b_2, b_3, b_4, b_5, b_6, b_7, b_8, b_9;
};

namespace
{
    constexpr SafierWindModel modelB{1.73,
        -0.30, 0.54, 1.14, 0.26, 1.76, 0.92, 0.09, 0.27,
        0.035, 7.7, 1.01, 0.31, 1.1, 0.40, -0.10, 0.0, 1.25, 0.60};

    constexpr SafierWindModel modelC{1.73,
        0.21, 0.30, 1.23, 0.21, 1.27, 0.92, 0.04, 0.28,
        0.035, 12.16, 0.65, 0.33, 1.0, 0.40, 0.50, 0.0, 1.25, 0.60};

    constexpr SafierWindModel modelD {1.73,
        0.49, 0.17, 1.27, 0.11, 0.89, 0.97, 0.02, 0.31,
        0.035, 20.08, 0.42, 0.34, 1.0, 0.40, 0.90, 0.0, 1.00, 0.60};

    constexpr SafierWindModel modelI{1.73,
        0.18, 0.14, 1.86, 0.26, 1.30, 0.92, 0.02, 0.24,
        0.035, 33.52, 0.55, 0.26, 2.5, 0.50, 1.00, 0.0, 0.75, 1.00};

    constexpr SafierWindModel modelE{3.73,
        -0.51, 0.62, 1.02, 0.03, 2.46, 0.91, 0.01, 0.32,
        0.01, 6.95, 0.53, 0.30, 1.0, 0.40, 0.90, 0.0, 1.00, 0.60};

    constexpr SafierWindModel modelF{3.73,
        -0.22, 0.50, 0.98, 0.09, 2.78, 0.92, 0.01, 0.27,
        0.01, 11.62, 0.67, 0.20, 1.8, 0.40, 1.00, 0.0, 0.85, 0.55};

    constexpr SafierWindModel modelG {3.73,
        0.07, 0.05, 0.42, 0.05, 2.95, 0.94, 0.008, 0.26,
        0.01, 18.70, 0.78, 0.14, 3.3, 0.55, 1.00, 0.0, 0.30, 1.10};

    SafierWindModel const* getModel(char const key)
    {
        if (key == 'B')
        {
            return &modelB;
        } else if (key == 'C') {
            return &modelC;
        } else if (key == 'D') {
            return &modelD;
        } else if (key == 'I') {
            return &modelI;
        } else if (key == 'E') {
            return &modelE;
        } else if (key == 'F') {
            return &modelF;
        } else if (key == 'G') {
            return &modelG;
        }

        return nullptr;
    }

    double rho0(const SafierWindModel* const model, double mOut, double mStar, double h0, double rRatio)
    {
        return 1.064e-15 * (mOut/1e-7) * std::pow(mStar/0.5, -0.5) / std::log(rRatio) /
            model->b_0/(1.0-h0*model->dxi0);
    }

    double xi(const SafierWindModel* const model, double h)
    {
        double xi1 = (1+model->a_1*h + model->a_2*pow(h, model->a_3)) * exp(-model->a_4*h);
        double xi2 = model->a_5 * pow(h, model->a_6)  * exp(-4*model->a_7*pow(h, model->a_8));
        return xi1 + xi2;
    }

    double psi(const SafierWindModel* const model, double h)
    {
        double psi1 = (model->b_0 + model->b_6*h + model->b_7*h*h) * exp(-model->b_8 * pow(h, model->b_9));
        double psi2 = model->b_1 * exp(-1.0/(model->b_2*pow(h, model->b_3)))  * exp(-model->b_4/(h*model->b_5));
        return psi1 + psi2;
    }

    double dXidChi(const SafierWindModel* const model, double h)
    {
        double dXidChi1 = (model->a_1 + model->a_2*model->a_3*pow(h, model->a_3 - 1.0) - model->a_4 - model->a_1*model->a_4*h - model->a_2*model->a_4*pow(h, model->a_3))
                            *exp(-model->a_4*h);
        double dXidChi2 = (model->a_5 * model->a_6 * pow(h, model->a_6-1.0) -4*model->a_5*model->a_7*model->a_8*pow(h,model->a_6)*pow(h, model->a_8 -1.0) )
                            * exp(-4*model->a_7*pow(h, model->a_8));

        return dXidChi1 + dXidChi2;
    }

    double eta(const SafierWindModel* const model, double chi, double h0)
    {
        double const h = fabs(chi) - h0;
        double const xi = ::xi(model, h);
        double const psi = ::psi(model, h);
        double const dxi = dXidChi(model, h);
        return model->b_0 * (1. - h0*model->dxi0) / (xi*psi*(xi-chi*dxi));
    }
}

SafierWind::SafierWind(
        char const model,
        double const mOut,
        double const mStar,
        double const h0,
        double const rMin,
        double const rMax,
        IDiskHumpCPtr hump)
    : model_{ getModel(model) }
    , rho0_{ rho0(model_, mOut, mStar, h0, rMax / rMin) }
    , h0_{ h0 }
    , hump_{ std::move(hump) }
{
    DATA_ASSERT(
        std::string("BCDIEFG").find(model) != std::string::npos,
        "Safier Wind model must be B, C, D, I, E, F, or G");

    DATA_ASSERT(mOut > 0., "mOut (the mass outflow rate of the wind) must be positive.");
    DATA_ASSERT(mStar > 0., "mStar (the stellar mass) must be positive.");
    DATA_ASSERT(h0 > 0., "h0 (density of the sphere envelope) must be positive.");
    DATA_ASSERT(rMin > 0., "rMin (inner radius of the wind formation region) must be positive.");
    DATA_ASSERT(rMax > 0., "rMax (outer radius of the wind formation region) must be positive.");
    DATA_ASSERT(rMax > rMin, "rMax (outer radius) must be greater than rMin (inner radius of the wind formation region).");
}

double SafierWind::density(Vector3d const& position) const
{
    double r = sqrt(position.x()*position.x() + position.y()*position.y());
    double chi = position.z()/r;

    if (chi < h0_ || rho0_ == 0.0)
    {
        return 0.0;
    }

    double const rho = rho0_ * std::pow(r, -1.5) * eta(model_, chi, h0_);

    if (hump_)
    {
        return hump_->hump(rho, position);
    }

    return rho;
}
<commit_msg>Fix Safier wind to be applied not only to the top half but also to the bottom half of the disc<commit_after>#include "SafierWind.hpp"
#include "DebugUtils.hpp"
#include "IDiskHump.hpp"
#include <cmath>
#include <string>

struct SafierWindModel
{
    double dxi0;
    double a_1, a_2, a_3, a_4, a_5, a_6, a_7, a_8;
    double b_0, b_1, b_2, b_3, b_4, b_5, b_6, b_7, b_8, b_9;
};

namespace
{
    constexpr SafierWindModel modelB{1.73,
        -0.30, 0.54, 1.14, 0.26, 1.76, 0.92, 0.09, 0.27,
        0.035, 7.7, 1.01, 0.31, 1.1, 0.40, -0.10, 0.0, 1.25, 0.60};

    constexpr SafierWindModel modelC{1.73,
        0.21, 0.30, 1.23, 0.21, 1.27, 0.92, 0.04, 0.28,
        0.035, 12.16, 0.65, 0.33, 1.0, 0.40, 0.50, 0.0, 1.25, 0.60};

    constexpr SafierWindModel modelD {1.73,
        0.49, 0.17, 1.27, 0.11, 0.89, 0.97, 0.02, 0.31,
        0.035, 20.08, 0.42, 0.34, 1.0, 0.40, 0.90, 0.0, 1.00, 0.60};

    constexpr SafierWindModel modelI{1.73,
        0.18, 0.14, 1.86, 0.26, 1.30, 0.92, 0.02, 0.24,
        0.035, 33.52, 0.55, 0.26, 2.5, 0.50, 1.00, 0.0, 0.75, 1.00};

    constexpr SafierWindModel modelE{3.73,
        -0.51, 0.62, 1.02, 0.03, 2.46, 0.91, 0.01, 0.32,
        0.01, 6.95, 0.53, 0.30, 1.0, 0.40, 0.90, 0.0, 1.00, 0.60};

    constexpr SafierWindModel modelF{3.73,
        -0.22, 0.50, 0.98, 0.09, 2.78, 0.92, 0.01, 0.27,
        0.01, 11.62, 0.67, 0.20, 1.8, 0.40, 1.00, 0.0, 0.85, 0.55};

    constexpr SafierWindModel modelG {3.73,
        0.07, 0.05, 0.42, 0.05, 2.95, 0.94, 0.008, 0.26,
        0.01, 18.70, 0.78, 0.14, 3.3, 0.55, 1.00, 0.0, 0.30, 1.10};

    SafierWindModel const* getModel(char const key)
    {
        if (key == 'B')
        {
            return &modelB;
        } else if (key == 'C') {
            return &modelC;
        } else if (key == 'D') {
            return &modelD;
        } else if (key == 'I') {
            return &modelI;
        } else if (key == 'E') {
            return &modelE;
        } else if (key == 'F') {
            return &modelF;
        } else if (key == 'G') {
            return &modelG;
        }

        return nullptr;
    }

    double rho0(const SafierWindModel* const model, double mOut, double mStar, double h0, double rRatio)
    {
        return 1.064e-15 * (mOut/1e-7) * std::pow(mStar/0.5, -0.5) / std::log(rRatio) /
            model->b_0/(1.0-h0*model->dxi0);
    }

    double xi(const SafierWindModel* const model, double h)
    {
        double xi1 = (1+model->a_1*h + model->a_2*pow(h, model->a_3)) * exp(-model->a_4*h);
        double xi2 = model->a_5 * pow(h, model->a_6)  * exp(-4*model->a_7*pow(h, model->a_8));
        return xi1 + xi2;
    }

    double psi(const SafierWindModel* const model, double h)
    {
        double psi1 = (model->b_0 + model->b_6*h + model->b_7*h*h) * exp(-model->b_8 * pow(h, model->b_9));
        double psi2 = model->b_1 * exp(-1.0/(model->b_2*pow(h, model->b_3)))  * exp(-model->b_4/(h*model->b_5));
        return psi1 + psi2;
    }

    double dXidChi(const SafierWindModel* const model, double h)
    {
        double dXidChi1 = (model->a_1 + model->a_2*model->a_3*pow(h, model->a_3 - 1.0) - model->a_4 - model->a_1*model->a_4*h - model->a_2*model->a_4*pow(h, model->a_3))
                            *exp(-model->a_4*h);
        double dXidChi2 = (model->a_5 * model->a_6 * pow(h, model->a_6-1.0) -4*model->a_5*model->a_7*model->a_8*pow(h,model->a_6)*pow(h, model->a_8 -1.0) )
                            * exp(-4*model->a_7*pow(h, model->a_8));

        return dXidChi1 + dXidChi2;
    }

    double eta(const SafierWindModel* const model, double chi, double h0)
    {
        double const h = fabs(chi) - h0;
        double const xi = ::xi(model, h);
        double const psi = ::psi(model, h);
        double const dxi = dXidChi(model, h);
        return model->b_0 * (1. - h0*model->dxi0) / (xi*psi*(xi-chi*dxi));
    }
}

SafierWind::SafierWind(
        char const model,
        double const mOut,
        double const mStar,
        double const h0,
        double const rMin,
        double const rMax,
        IDiskHumpCPtr hump)
    : model_{ getModel(model) }
    , rho0_{ rho0(model_, mOut, mStar, h0, rMax / rMin) }
    , h0_{ h0 }
    , hump_{ std::move(hump) }
{
    DATA_ASSERT(
        std::string("BCDIEFG").find(model) != std::string::npos,
        "Safier Wind model must be B, C, D, I, E, F, or G");

    DATA_ASSERT(mOut > 0., "mOut (the mass outflow rate of the wind) must be positive.");
    DATA_ASSERT(mStar > 0., "mStar (the stellar mass) must be positive.");
    DATA_ASSERT(h0 > 0., "h0 (density of the sphere envelope) must be positive.");
    DATA_ASSERT(rMin > 0., "rMin (inner radius of the wind formation region) must be positive.");
    DATA_ASSERT(rMax > 0., "rMax (outer radius of the wind formation region) must be positive.");
    DATA_ASSERT(rMax > rMin, "rMax (outer radius) must be greater than rMin (inner radius of the wind formation region).");
}

double SafierWind::density(Vector3d const& position) const
{
    double const r = std::sqrt(position.x()*position.x() + position.y()*position.y());
    double const chi = std::abs(position.z()/r);

    if (chi < h0_ || rho0_ == 0.0)
    {
        return 0.0;
    }

    double const rho = rho0_ * std::pow(r, -1.5) * eta(model_, chi, h0_);

    if (hump_)
    {
        return hump_->hump(rho, position);
    }

    return rho;
}
<|endoftext|>


<commit_before>//===-- ABI.cpp -------------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "lldb/Target/ABI.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Expression/ExpressionVariable.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"

using namespace lldb;
using namespace lldb_private;

ABISP
ABI::FindPlugin(lldb::ProcessSP process_sp, const ArchSpec &arch) {
  ABISP abi_sp;
  ABICreateInstance create_callback;

  for (uint32_t idx = 0;
       (create_callback = PluginManager::GetABICreateCallbackAtIndex(idx)) !=
       nullptr;
       ++idx) {
    abi_sp = create_callback(process_sp, arch);

    if (abi_sp)
      return abi_sp;
  }
  abi_sp.reset();
  return abi_sp;
}

ABI::~ABI() = default;

bool ABI::GetRegisterInfoByName(ConstString name, RegisterInfo &info) {
  uint32_t count = 0;
  const RegisterInfo *register_info_array = GetRegisterInfoArray(count);
  if (register_info_array) {
    const char *unique_name_cstr = name.GetCString();
    uint32_t i;
    for (i = 0; i < count; ++i) {
      if (register_info_array[i].name == unique_name_cstr) {
        info = register_info_array[i];
        return true;
      }
    }
    for (i = 0; i < count; ++i) {
      if (register_info_array[i].alt_name == unique_name_cstr) {
        info = register_info_array[i];
        return true;
      }
    }
  }
  return false;
}

bool ABI::GetRegisterInfoByKind(RegisterKind reg_kind, uint32_t reg_num,
                                RegisterInfo &info) {
  if (reg_kind < eRegisterKindEHFrame || reg_kind >= kNumRegisterKinds)
    return false;

  uint32_t count = 0;
  const RegisterInfo *register_info_array = GetRegisterInfoArray(count);
  if (register_info_array) {
    for (uint32_t i = 0; i < count; ++i) {
      if (register_info_array[i].kinds[reg_kind] == reg_num) {
        info = register_info_array[i];
        return true;
      }
    }
  }
  return false;
}

ValueObjectSP ABI::GetReturnValueObject(Thread &thread, CompilerType &ast_type,
                                        bool persistent) const {
  if (!ast_type.IsValid())
    return ValueObjectSP();

  ValueObjectSP return_valobj_sp;

  return_valobj_sp = GetReturnValueObjectImpl(thread, ast_type);
  if (!return_valobj_sp)
    return return_valobj_sp;

  // Now turn this into a persistent variable.
  // FIXME: This code is duplicated from Target::EvaluateExpression, and it is
  // used in similar form in a couple
  // of other places.  Figure out the correct Create function to do all this
  // work.

  if (persistent) {
    Target &target = *thread.CalculateTarget();
    PersistentExpressionState *persistent_expression_state =
        target.GetPersistentExpressionStateForLanguage(
            ast_type.GetMinimumLanguage());

    if (!persistent_expression_state)
      return ValueObjectSP();

    auto prefix = persistent_expression_state->GetPersistentVariablePrefix();
    ConstString persistent_variable_name =
        persistent_expression_state->GetNextPersistentVariableName(target,
                                                                   prefix);

    lldb::ValueObjectSP const_valobj_sp;

    // Check in case our value is already a constant value
    if (return_valobj_sp->GetIsConstant()) {
      const_valobj_sp = return_valobj_sp;
      const_valobj_sp->SetName(persistent_variable_name);
    } else
      const_valobj_sp =
          return_valobj_sp->CreateConstantValue(persistent_variable_name);

    lldb::ValueObjectSP live_valobj_sp = return_valobj_sp;

    return_valobj_sp = const_valobj_sp;

    ExpressionVariableSP clang_expr_variable_sp(
        persistent_expression_state->CreatePersistentVariable(
            return_valobj_sp));

    assert(clang_expr_variable_sp);

    // Set flags and live data as appropriate

    const Value &result_value = live_valobj_sp->GetValue();

    switch (result_value.GetValueType()) {
    case Value::eValueTypeHostAddress:
    case Value::eValueTypeFileAddress:
      // we don't do anything with these for now
      break;
    case Value::eValueTypeScalar:
    case Value::eValueTypeVector:
      clang_expr_variable_sp->m_flags |=
          ExpressionVariable::EVIsFreezeDried;
      clang_expr_variable_sp->m_flags |=
          ExpressionVariable::EVIsLLDBAllocated;
      clang_expr_variable_sp->m_flags |=
          ExpressionVariable::EVNeedsAllocation;
      break;
    case Value::eValueTypeLoadAddress:
      clang_expr_variable_sp->m_live_sp = live_valobj_sp;
      clang_expr_variable_sp->m_flags |=
          ExpressionVariable::EVIsProgramReference;
      break;
    }

    return_valobj_sp = clang_expr_variable_sp->GetValueObject();
  }
  return return_valobj_sp;
}

ValueObjectSP ABI::GetReturnValueObject(Thread &thread, llvm::Type &ast_type,
                                        bool persistent) const {
  ValueObjectSP return_valobj_sp;
  return_valobj_sp = GetReturnValueObjectImpl(thread, ast_type);
  return return_valobj_sp;
}

// specialized to work with llvm IR types
//
// for now we will specify a default implementation so that we don't need to
// modify other ABIs
lldb::ValueObjectSP ABI::GetReturnValueObjectImpl(Thread &thread,
                                                  llvm::Type &ir_type) const {
  ValueObjectSP return_valobj_sp;

  /* this is a dummy and will only be called if an ABI does not override this */

  return return_valobj_sp;
}

bool ABI::PrepareTrivialCall(Thread &thread, lldb::addr_t sp,
                             lldb::addr_t functionAddress,
                             lldb::addr_t returnAddress, llvm::Type &returntype,
                             llvm::ArrayRef<ABI::CallArgument> args) const {
  // dummy prepare trivial call
  llvm_unreachable("Should never get here!");
}

bool ABI::GetFallbackRegisterLocation(
    const RegisterInfo *reg_info,
    UnwindPlan::Row::RegisterLocation &unwind_regloc) {
  // Did the UnwindPlan fail to give us the caller's stack pointer? The stack
  // pointer is defined to be the same as THIS frame's CFA, so return the CFA
  // value as the caller's stack pointer.  This is true on x86-32/x86-64 at
  // least.
  if (reg_info->kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_SP) {
    unwind_regloc.SetIsCFAPlusOffset(0);
    return true;
  }

  // If a volatile register is being requested, we don't want to forward the
  // next frame's register contents up the stack -- the register is not
  // retrievable at this frame.
  if (RegisterIsVolatile(reg_info)) {
    unwind_regloc.SetUndefined();
    return true;
  }

  return false;
}
<commit_msg>[Target][NFCI] Rename variable<commit_after>//===-- ABI.cpp -------------------------------------------------*- C++ -*-===//
//
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
// See https://llvm.org/LICENSE.txt for license information.
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
//
//===----------------------------------------------------------------------===//

#include "lldb/Target/ABI.h"
#include "lldb/Core/PluginManager.h"
#include "lldb/Core/Value.h"
#include "lldb/Core/ValueObjectConstResult.h"
#include "lldb/Expression/ExpressionVariable.h"
#include "lldb/Symbol/CompilerType.h"
#include "lldb/Symbol/TypeSystem.h"
#include "lldb/Target/Target.h"
#include "lldb/Target/Thread.h"

using namespace lldb;
using namespace lldb_private;

ABISP
ABI::FindPlugin(lldb::ProcessSP process_sp, const ArchSpec &arch) {
  ABISP abi_sp;
  ABICreateInstance create_callback;

  for (uint32_t idx = 0;
       (create_callback = PluginManager::GetABICreateCallbackAtIndex(idx)) !=
       nullptr;
       ++idx) {
    abi_sp = create_callback(process_sp, arch);

    if (abi_sp)
      return abi_sp;
  }
  abi_sp.reset();
  return abi_sp;
}

ABI::~ABI() = default;

bool ABI::GetRegisterInfoByName(ConstString name, RegisterInfo &info) {
  uint32_t count = 0;
  const RegisterInfo *register_info_array = GetRegisterInfoArray(count);
  if (register_info_array) {
    const char *unique_name_cstr = name.GetCString();
    uint32_t i;
    for (i = 0; i < count; ++i) {
      if (register_info_array[i].name == unique_name_cstr) {
        info = register_info_array[i];
        return true;
      }
    }
    for (i = 0; i < count; ++i) {
      if (register_info_array[i].alt_name == unique_name_cstr) {
        info = register_info_array[i];
        return true;
      }
    }
  }
  return false;
}

bool ABI::GetRegisterInfoByKind(RegisterKind reg_kind, uint32_t reg_num,
                                RegisterInfo &info) {
  if (reg_kind < eRegisterKindEHFrame || reg_kind >= kNumRegisterKinds)
    return false;

  uint32_t count = 0;
  const RegisterInfo *register_info_array = GetRegisterInfoArray(count);
  if (register_info_array) {
    for (uint32_t i = 0; i < count; ++i) {
      if (register_info_array[i].kinds[reg_kind] == reg_num) {
        info = register_info_array[i];
        return true;
      }
    }
  }
  return false;
}

ValueObjectSP ABI::GetReturnValueObject(Thread &thread, CompilerType &ast_type,
                                        bool persistent) const {
  if (!ast_type.IsValid())
    return ValueObjectSP();

  ValueObjectSP return_valobj_sp;

  return_valobj_sp = GetReturnValueObjectImpl(thread, ast_type);
  if (!return_valobj_sp)
    return return_valobj_sp;

  // Now turn this into a persistent variable.
  // FIXME: This code is duplicated from Target::EvaluateExpression, and it is
  // used in similar form in a couple
  // of other places.  Figure out the correct Create function to do all this
  // work.

  if (persistent) {
    Target &target = *thread.CalculateTarget();
    PersistentExpressionState *persistent_expression_state =
        target.GetPersistentExpressionStateForLanguage(
            ast_type.GetMinimumLanguage());

    if (!persistent_expression_state)
      return ValueObjectSP();

    auto prefix = persistent_expression_state->GetPersistentVariablePrefix();
    ConstString persistent_variable_name =
        persistent_expression_state->GetNextPersistentVariableName(target,
                                                                   prefix);

    lldb::ValueObjectSP const_valobj_sp;

    // Check in case our value is already a constant value
    if (return_valobj_sp->GetIsConstant()) {
      const_valobj_sp = return_valobj_sp;
      const_valobj_sp->SetName(persistent_variable_name);
    } else
      const_valobj_sp =
          return_valobj_sp->CreateConstantValue(persistent_variable_name);

    lldb::ValueObjectSP live_valobj_sp = return_valobj_sp;

    return_valobj_sp = const_valobj_sp;

    ExpressionVariableSP expr_variable_sp(
        persistent_expression_state->CreatePersistentVariable(
            return_valobj_sp));

    assert(expr_variable_sp);

    // Set flags and live data as appropriate

    const Value &result_value = live_valobj_sp->GetValue();

    switch (result_value.GetValueType()) {
    case Value::eValueTypeHostAddress:
    case Value::eValueTypeFileAddress:
      // we don't do anything with these for now
      break;
    case Value::eValueTypeScalar:
    case Value::eValueTypeVector:
      expr_variable_sp->m_flags |=
          ExpressionVariable::EVIsFreezeDried;
      expr_variable_sp->m_flags |=
          ExpressionVariable::EVIsLLDBAllocated;
      expr_variable_sp->m_flags |=
          ExpressionVariable::EVNeedsAllocation;
      break;
    case Value::eValueTypeLoadAddress:
      expr_variable_sp->m_live_sp = live_valobj_sp;
      expr_variable_sp->m_flags |=
          ExpressionVariable::EVIsProgramReference;
      break;
    }

    return_valobj_sp = expr_variable_sp->GetValueObject();
  }
  return return_valobj_sp;
}

ValueObjectSP ABI::GetReturnValueObject(Thread &thread, llvm::Type &ast_type,
                                        bool persistent) const {
  ValueObjectSP return_valobj_sp;
  return_valobj_sp = GetReturnValueObjectImpl(thread, ast_type);
  return return_valobj_sp;
}

// specialized to work with llvm IR types
//
// for now we will specify a default implementation so that we don't need to
// modify other ABIs
lldb::ValueObjectSP ABI::GetReturnValueObjectImpl(Thread &thread,
                                                  llvm::Type &ir_type) const {
  ValueObjectSP return_valobj_sp;

  /* this is a dummy and will only be called if an ABI does not override this */

  return return_valobj_sp;
}

bool ABI::PrepareTrivialCall(Thread &thread, lldb::addr_t sp,
                             lldb::addr_t functionAddress,
                             lldb::addr_t returnAddress, llvm::Type &returntype,
                             llvm::ArrayRef<ABI::CallArgument> args) const {
  // dummy prepare trivial call
  llvm_unreachable("Should never get here!");
}

bool ABI::GetFallbackRegisterLocation(
    const RegisterInfo *reg_info,
    UnwindPlan::Row::RegisterLocation &unwind_regloc) {
  // Did the UnwindPlan fail to give us the caller's stack pointer? The stack
  // pointer is defined to be the same as THIS frame's CFA, so return the CFA
  // value as the caller's stack pointer.  This is true on x86-32/x86-64 at
  // least.
  if (reg_info->kinds[eRegisterKindGeneric] == LLDB_REGNUM_GENERIC_SP) {
    unwind_regloc.SetIsCFAPlusOffset(0);
    return true;
  }

  // If a volatile register is being requested, we don't want to forward the
  // next frame's register contents up the stack -- the register is not
  // retrievable at this frame.
  if (RegisterIsVolatile(reg_info)) {
    unwind_regloc.SetUndefined();
    return true;
  }

  return false;
}
<|endoftext|>


<commit_before>#pragma once

#include <Automaton.h>

class Atm_player : public Machine {
 public:
  enum { IDLE, START, SOUND, QUIET, NEXT, REPEAT, FINISH };                          // STATES
  enum { EVT_START, EVT_STOP, EVT_TOGGLE, EVT_TIMER, EVT_EOPAT, EVT_REPEAT, ELSE };  // EVENTS
  Atm_player( void ) : Machine(){};
  Atm_player& begin( int pin = -1 );
  Atm_player& trace( Stream& stream );
  Atm_player& trigger( int event );
  int state( void );
  Atm_player& onNote( atm_cb_push_t callback, int idx = 0 );
  Atm_player& onNote( Machine& machine, int event = 0 );
  Atm_player& onNote( bool status, atm_cb_push_t callback, int idx = 0 );
  Atm_player& onNote( bool status, Machine& machine, int event = 0 );
  Atm_player& onFinish( atm_cb_push_t callback, int idx = 0 );
  Atm_player& onFinish( Machine& machine, int event = 0 );
  Atm_player& play( int* pat, int size );
  Atm_player& play( int freq, int period, int pause = 0 );
  Atm_player& repeat( uint16_t v );
  Atm_player& speed( float v );
  Atm_player& pitch( float v );

 private:
  int pin;
  int* pattern;
  int patternsize;
  int step;
  uint16_t repeatCount;
  float speedFactor, pitchFactor;
  int stub[3];
  atm_timer_millis timer;
  atm_counter counter_repeat;
  atm_connector onnote[2], onfinish;
  enum { ENT_IDLE, ENT_START, ENT_SOUND, ENT_QUIET, ENT_NEXT, ENT_REPEAT, ENT_FINISH };  // ACTIONS
  int event( int id );
  void action( int id );
};

/*
Automaton::SMDL::begin - State Machine Definition Language

<?xml version="1.0" encoding="UTF-8"?>
<machines>
  <machine name="Atm_player">
    <states>
      <IDLE index="0" sleep="1" on_enter="ENT_IDLE">
        <EVT_START>START</EVT_START>
        <EVT_TOGGLE>START</EVT_TOGGLE>
      </IDLE>
      <START index="1" on_enter="ENT_START">
        <ELSE>SOUND</ELSE>
      </START>
      <SOUND index="2" on_enter="ENT_SOUND">
        <EVT_STOP>IDLE</EVT_STOP>
        <EVT_TOGGLE>IDLE</EVT_TOGGLE>
        <EVT_TIMER>QUIET</EVT_TIMER>
      </SOUND>
      <QUIET index="3" on_enter="ENT_QUIET">
        <EVT_STOP>IDLE</EVT_STOP>
        <EVT_TOGGLE>IDLE</EVT_TOGGLE>
        <EVT_TIMER>NEXT</EVT_TIMER>
      </QUIET>
      <NEXT index="4" on_enter="ENT_NEXT">
        <EVT_STOP>IDLE</EVT_STOP>
        <EVT_TOGGLE>IDLE</EVT_TOGGLE>
        <EVT_EOPAT>REPEAT</EVT_EOPAT>
        <ELSE>SOUND</ELSE>
      </NEXT>
      <REPEAT index="5" on_enter="ENT_REPEAT">
        <EVT_STOP>IDLE</EVT_STOP>
        <EVT_TOGGLE>IDLE</EVT_TOGGLE>
        <EVT_REPEAT>FINISH</EVT_REPEAT>
        <ELSE>START</ELSE>
      </REPEAT>
      <FINISH index="6" on_enter="ENT_FINISH">
        <EVT_REPEAT>IDLE</EVT_REPEAT>
        <ELSE>START</ELSE>
      </FINISH>
    </states>
    <events>
      <EVT_START index="0"/>
      <EVT_STOP index="1"/>
      <EVT_TOGGLE index="2"/>
      <EVT_TIMER index="3"/>
      <EVT_EOPAT index="4"/>
      <EVT_REPEAT index="5"/>
    </events>
    <connectors>
    </connectors>
    <methods>
    </methods>
  </machine>
</machines>

Automaton::SMDL::end
*/
<commit_msg>Changed SDML -> ATML<commit_after>#pragma once

#include <Automaton.h>

class Atm_player : public Machine {
 public:
  enum { IDLE, START, SOUND, QUIET, NEXT, REPEAT, FINISH };                          // STATES
  enum { EVT_START, EVT_STOP, EVT_TOGGLE, EVT_TIMER, EVT_EOPAT, EVT_REPEAT, ELSE };  // EVENTS
  Atm_player( void ) : Machine(){};
  Atm_player& begin( int pin = -1 );
  Atm_player& trace( Stream& stream );
  Atm_player& trigger( int event );
  int state( void );
  Atm_player& onNote( atm_cb_push_t callback, int idx = 0 );
  Atm_player& onNote( Machine& machine, int event = 0 );
  Atm_player& onNote( bool status, atm_cb_push_t callback, int idx = 0 );
  Atm_player& onNote( bool status, Machine& machine, int event = 0 );
  Atm_player& onFinish( atm_cb_push_t callback, int idx = 0 );
  Atm_player& onFinish( Machine& machine, int event = 0 );
  Atm_player& play( int* pat, int size );
  Atm_player& play( int freq, int period, int pause = 0 );
  Atm_player& repeat( uint16_t v );
  Atm_player& speed( float v );
  Atm_player& pitch( float v );

 private:
  int pin;
  int* pattern;
  int patternsize;
  int step;
  uint16_t repeatCount;
  float speedFactor, pitchFactor;
  int stub[3];
  atm_timer_millis timer;
  atm_counter counter_repeat;
  atm_connector onnote[2], onfinish;
  enum { ENT_IDLE, ENT_START, ENT_SOUND, ENT_QUIET, ENT_NEXT, ENT_REPEAT, ENT_FINISH };  // ACTIONS
  int event( int id );
  void action( int id );
};

/*
Automaton::ATML::begin - State Machine Definition Language

<?xml version="1.0" encoding="UTF-8"?>
<machines>
  <machine name="Atm_player">
    <states>
      <IDLE index="0" sleep="1" on_enter="ENT_IDLE">
        <EVT_START>START</EVT_START>
        <EVT_TOGGLE>START</EVT_TOGGLE>
      </IDLE>
      <START index="1" on_enter="ENT_START">
        <ELSE>SOUND</ELSE>
      </START>
      <SOUND index="2" on_enter="ENT_SOUND">
        <EVT_STOP>IDLE</EVT_STOP>
        <EVT_TOGGLE>IDLE</EVT_TOGGLE>
        <EVT_TIMER>QUIET</EVT_TIMER>
      </SOUND>
      <QUIET index="3" on_enter="ENT_QUIET">
        <EVT_STOP>IDLE</EVT_STOP>
        <EVT_TOGGLE>IDLE</EVT_TOGGLE>
        <EVT_TIMER>NEXT</EVT_TIMER>
      </QUIET>
      <NEXT index="4" on_enter="ENT_NEXT">
        <EVT_STOP>IDLE</EVT_STOP>
        <EVT_TOGGLE>IDLE</EVT_TOGGLE>
        <EVT_EOPAT>REPEAT</EVT_EOPAT>
        <ELSE>SOUND</ELSE>
      </NEXT>
      <REPEAT index="5" on_enter="ENT_REPEAT">
        <EVT_STOP>IDLE</EVT_STOP>
        <EVT_TOGGLE>IDLE</EVT_TOGGLE>
        <EVT_REPEAT>FINISH</EVT_REPEAT>
        <ELSE>START</ELSE>
      </REPEAT>
      <FINISH index="6" on_enter="ENT_FINISH">
        <EVT_REPEAT>IDLE</EVT_REPEAT>
        <ELSE>START</ELSE>
      </FINISH>
    </states>
    <events>
      <EVT_START index="0"/>
      <EVT_STOP index="1"/>
      <EVT_TOGGLE index="2"/>
      <EVT_TIMER index="3"/>
      <EVT_EOPAT index="4"/>
      <EVT_REPEAT index="5"/>
    </events>
    <connectors>
    </connectors>
    <methods>
    </methods>
  </machine>
</machines>

Automaton::ATML::end
*/
<|endoftext|>


<commit_before>#ifndef BROKER_H_
#define BROKER_H_

#include "dtypes.hpp"
#include "message.hpp"
#include <vector>
#include <deque>
#include <string>
#include <unordered_map>
#include <memory>
#include <iostream>
#include <boost/algorithm/string.hpp>

class MqttSubscriber {
public:
    virtual void newMessage(const std::string& topic, const std::vector<ubyte>& payload) = 0;
};

using TopicParts = std::deque<std::string>;

class OldSubscription {
public:

    friend class SubscriptionTree;

    OldSubscription(MqttSubscriber& subscriber, MqttSubscribe::Topic topic,
                 TopicParts topicParts);

    void newMessage(const std::string& topic, const std::vector<ubyte>& payload);

    bool isSubscriber(const MqttSubscriber& subscriber) const;
    bool isSubscription(const MqttSubscriber& subscriber,
                        std::vector<std::string> topics) const;
    bool isTopic(const std::vector<std::string>& topics) const;

    ubyte qos() const { return _qos; }

private:
    MqttSubscriber& _subscriber;
    std::string _part;
    std::string _topic;
    ubyte _qos;
};

class SubscriptionTree {
private:

    struct Node {
        using NodePtr = Node*;
        Node(std::string pt, NodePtr pr):part(pt), parent(pr) {}
        ~Node() { for(auto l: leaves) delete l; }
        std::string part;
        NodePtr parent;
        std::unordered_map<std::string, NodePtr> branches;
        std::vector<OldSubscription*> leaves;
    };

public:

    using NodePtr = Node::NodePtr;

    SubscriptionTree();

    void addSubscription(OldSubscription* s, const TopicParts& parts);
    void removeSubscription(MqttSubscriber& subscriber,
                            std::unordered_map<std::string, NodePtr>& nodes);
    void removeSubscription(MqttSubscriber& subscriber,
                            std::vector<std::string> topic,
                            std::unordered_map<std::string, NodePtr>& nodes);
    void publish(std::string topic, TopicParts topParts,
                 const std::vector<ubyte>& payload);
    void publish(std::string topic,
                 TopicParts::const_iterator topPartsBegin,
                 TopicParts::const_iterator topPartsEnd,
                 const std::vector<ubyte>& payload,
                 std::unordered_map<std::string, NodePtr>& nodes);
    void publishLeaves(std::string topic, const std::vector<ubyte>& payload,
                       TopicParts::const_iterator topPartsBegin,
                       TopicParts::const_iterator topPartsEnd,
                       std::vector<OldSubscription*> subscriptions);
    void publishLeaf(OldSubscription* sub, std::string topic, const std::vector<ubyte>& payload);
    void useCache(bool u) { _useCache = u; }

    bool _useCache;
    std::unordered_map<std::string, std::vector<OldSubscription*>> _cache;
    std::unordered_map<std::string, NodePtr> _nodes;
    friend class OldMqttBroker;

    void addSubscriptionImpl(OldSubscription* s,
                             TopicParts parts,
                             NodePtr parent,
                             std::unordered_map<std::string, NodePtr>& nodes);
    NodePtr addOrFindNode(std::string part, NodePtr parent,
                        std::unordered_map<std::string, NodePtr>& nodes);
    void clearCache() { if(_useCache) _cache.clear(); }

    void removeNode(NodePtr parent, NodePtr child);
};

class OldMqttBroker {
public:

    void subscribe(MqttSubscriber& subscriber, std::vector<std::string> topics);
    void subscribe(MqttSubscriber& subscriber, std::vector<MqttSubscribe::Topic> topics);
    void unsubscribe(MqttSubscriber& subscriber);
    void unsubscribe(MqttSubscriber& subscriber, std::vector<std::string> topics);
    void publish(const std::string& topic, const std::string& payload);
    void publish(const std::string& topic, const std::vector<ubyte>& payload);

    void useCache(bool u) { _subscriptions.useCache(u); }

private:

    SubscriptionTree _subscriptions;

    void publish(const std::string& topic,
                 const TopicParts& topParts,
                 const std::vector<ubyte>& payload);
};

#include "string_span.h"

template<typename S> class Subscription;

template<typename S>
class MqttBroker {
public:

    MqttBroker(bool useCache):
        _useCache{useCache}
    {
    }

    void subscribe(S& subscriber, std::vector<std::string> topics) {
        std::vector<MqttSubscribe::Topic> newTopics(topics.size());
        std::transform(topics.cbegin(), topics.cend(), newTopics.begin(),
                       [](auto t) { return MqttSubscribe::Topic(t, 0); });
        subscribe(subscriber, newTopics);
    }

    void subscribe(S& subscriber, std::vector<MqttSubscribe::Topic> topics) {
        invalidateCache();
        for(const auto& topic: topics) {
            std::deque<std::string> subParts;
            boost::split(subParts, topic.topic, boost::is_any_of("/"));
            auto& node = addOrFindNode(_tree, subParts);
            node.leaves.emplace_back(Subscription<S>{&subscriber, topic.topic});
        }
    }

    void unsubscribe(const S& subscriber) {
        std::vector<std::string> topics{};
        unsubscribe(subscriber, topics);
    }

    void unsubscribe(const S& subscriber, const std::vector<std::string>& topics) {
        invalidateCache();
        unsubscribeImpl(_tree, subscriber, topics);
    }

    void publish(const gsl::cstring_span<> topicSpan, const gsl::span<ubyte> bytes) {
        const auto topic = gsl::to_string(topicSpan);

        if(_useCache && _cache.find(topic) != _cache.end()) {
            for(auto subscriber: _cache[topic]) subscriber->newMessage(bytes);
            return;
        }

        std::deque<std::string> pubParts;
        boost::split(pubParts, topic, boost::is_any_of("/"));
        publishImpl(_tree, pubParts, topic, bytes);
    }

private:

    struct Node;
    using NodePtr = std::shared_ptr<Node>;

    struct Node {
        std::unordered_map<std::string, NodePtr> children;
        std::vector<Subscription<S>> leaves;
    };

    bool _useCache;
    std::unordered_map<std::string, std::vector<S*>> _cache;
    Node _tree;

    void invalidateCache() {
        if(_useCache) _cache.clear();
    }

    static Node& addOrFindNode(Node& tree, std::deque<std::string>& parts) {
        if(parts.size() == 0) return tree;

        const auto part = parts[0]; //copying is good here
        //create if not already here
        if(tree.children.find(part) == tree.children.end()) {
            tree.children[part] = std::make_shared<Node>();
        }

        parts.pop_front();
        return addOrFindNode(*tree.children[part], parts);
    }

    void publishImpl(Node& tree, std::deque<std::string>& pubParts,
                     const std::string& topic, const gsl::span<ubyte> bytes) {

        if(pubParts.size() == 0) return;

        const std::string front = pubParts[0];
        pubParts.pop_front();

        for(const auto& part: std::vector<std::string>{front, "#", "+"}) {
            if(tree.children.find(part) != tree.children.end()) {
                Node& node = *tree.children[part];
                if(pubParts.size() == 0 || part == "#") publishNode(node, topic, bytes);

                if(pubParts.size() == 0 && node.children.find("#") != node.children.end()) {
                    //So that "finance/#" matches "finance"
                    publishNode(*node.children["#"], topic, bytes);
                }

                publishImpl(node, pubParts, topic, bytes);
            }
        }
    }

    void publishNode(Node& node, const std::string& topic, gsl::span<ubyte> bytes) {
        for(auto& subscription: node.leaves) {
            subscription.subscriber->newMessage(bytes);
            if(_useCache) _cache[topic].emplace_back(subscription.subscriber);
        }
    }

    void unsubscribeImpl(Node& tree, const S& subscriber, const std::vector<std::string>& topics) {
        (void)tree; (void)subscriber; (void)topics;

        decltype(tree.leaves) leaves;
        std::copy_if(tree.leaves.cbegin(), tree.leaves.cend(), std::back_inserter(leaves),
                     [&subscriber, &topics](auto&& a) {
                         return !a.isSubscriber(subscriber, topics);
                     });
        std::swap(tree.leaves, leaves);

        if(tree.children.size() == 0) return;

        for(const auto& item: tree.children) {
            unsubscribeImpl(*item.second, subscriber, topics);
        }
    }
};

template<typename S>
class Subscription {
public:

    Subscription(S* subscriber, gsl::cstring_span<> topic) noexcept :
        subscriber{subscriber}, topic{gsl::to_string(topic)} {
    }

    bool isSubscriber(const S& sub, const std::vector<std::string>& topics) const {
        const auto isSameTopic = topics.size() == 0 ||
            std::find(topics.cbegin(), topics.cend(), topic) != topics.end();
        return isSameTopic && subscriber == ⊂
    }

    S* subscriber;
    std::string topic;
};

#endif // BROKER_H_
<commit_msg>not_null<commit_after>#ifndef BROKER_H_
#define BROKER_H_

#include "dtypes.hpp"
#include "message.hpp"
#include <vector>
#include <deque>
#include <string>
#include <unordered_map>
#include <memory>
#include <iostream>
#include <boost/algorithm/string.hpp>

class MqttSubscriber {
public:
    virtual void newMessage(const std::string& topic, const std::vector<ubyte>& payload) = 0;
};

using TopicParts = std::deque<std::string>;

class OldSubscription {
public:

    friend class SubscriptionTree;

    OldSubscription(MqttSubscriber& subscriber, MqttSubscribe::Topic topic,
                 TopicParts topicParts);

    void newMessage(const std::string& topic, const std::vector<ubyte>& payload);

    bool isSubscriber(const MqttSubscriber& subscriber) const;
    bool isSubscription(const MqttSubscriber& subscriber,
                        std::vector<std::string> topics) const;
    bool isTopic(const std::vector<std::string>& topics) const;

    ubyte qos() const { return _qos; }

private:
    MqttSubscriber& _subscriber;
    std::string _part;
    std::string _topic;
    ubyte _qos;
};

class SubscriptionTree {
private:

    struct Node {
        using NodePtr = Node*;
        Node(std::string pt, NodePtr pr):part(pt), parent(pr) {}
        ~Node() { for(auto l: leaves) delete l; }
        std::string part;
        NodePtr parent;
        std::unordered_map<std::string, NodePtr> branches;
        std::vector<OldSubscription*> leaves;
    };

public:

    using NodePtr = Node::NodePtr;

    SubscriptionTree();

    void addSubscription(OldSubscription* s, const TopicParts& parts);
    void removeSubscription(MqttSubscriber& subscriber,
                            std::unordered_map<std::string, NodePtr>& nodes);
    void removeSubscription(MqttSubscriber& subscriber,
                            std::vector<std::string> topic,
                            std::unordered_map<std::string, NodePtr>& nodes);
    void publish(std::string topic, TopicParts topParts,
                 const std::vector<ubyte>& payload);
    void publish(std::string topic,
                 TopicParts::const_iterator topPartsBegin,
                 TopicParts::const_iterator topPartsEnd,
                 const std::vector<ubyte>& payload,
                 std::unordered_map<std::string, NodePtr>& nodes);
    void publishLeaves(std::string topic, const std::vector<ubyte>& payload,
                       TopicParts::const_iterator topPartsBegin,
                       TopicParts::const_iterator topPartsEnd,
                       std::vector<OldSubscription*> subscriptions);
    void publishLeaf(OldSubscription* sub, std::string topic, const std::vector<ubyte>& payload);
    void useCache(bool u) { _useCache = u; }

    bool _useCache;
    std::unordered_map<std::string, std::vector<OldSubscription*>> _cache;
    std::unordered_map<std::string, NodePtr> _nodes;
    friend class OldMqttBroker;

    void addSubscriptionImpl(OldSubscription* s,
                             TopicParts parts,
                             NodePtr parent,
                             std::unordered_map<std::string, NodePtr>& nodes);
    NodePtr addOrFindNode(std::string part, NodePtr parent,
                        std::unordered_map<std::string, NodePtr>& nodes);
    void clearCache() { if(_useCache) _cache.clear(); }

    void removeNode(NodePtr parent, NodePtr child);
};

class OldMqttBroker {
public:

    void subscribe(MqttSubscriber& subscriber, std::vector<std::string> topics);
    void subscribe(MqttSubscriber& subscriber, std::vector<MqttSubscribe::Topic> topics);
    void unsubscribe(MqttSubscriber& subscriber);
    void unsubscribe(MqttSubscriber& subscriber, std::vector<std::string> topics);
    void publish(const std::string& topic, const std::string& payload);
    void publish(const std::string& topic, const std::vector<ubyte>& payload);

    void useCache(bool u) { _subscriptions.useCache(u); }

private:

    SubscriptionTree _subscriptions;

    void publish(const std::string& topic,
                 const TopicParts& topParts,
                 const std::vector<ubyte>& payload);
};

#include "gsl.h"

template<typename S> class Subscription;

template<typename S>
class MqttBroker {
public:

    MqttBroker(bool useCache):
        _useCache{useCache}
    {
    }

    void subscribe(S& subscriber, std::vector<std::string> topics) {
        std::vector<MqttSubscribe::Topic> newTopics(topics.size());
        std::transform(topics.cbegin(), topics.cend(), newTopics.begin(),
                       [](auto t) { return MqttSubscribe::Topic(t, 0); });
        subscribe(subscriber, newTopics);
    }

    void subscribe(S& subscriber, std::vector<MqttSubscribe::Topic> topics) {
        invalidateCache();
        for(const auto& topic: topics) {
            std::deque<std::string> subParts;
            boost::split(subParts, topic.topic, boost::is_any_of("/"));
            auto& node = addOrFindNode(_tree, subParts);
            node.leaves.emplace_back(Subscription<S>{&subscriber, topic.topic});
        }
    }

    void unsubscribe(const S& subscriber) {
        std::vector<std::string> topics{};
        unsubscribe(subscriber, topics);
    }

    void unsubscribe(const S& subscriber, const std::vector<std::string>& topics) {
        invalidateCache();
        unsubscribeImpl(_tree, subscriber, topics);
    }

    void publish(const gsl::cstring_span<> topicSpan, const gsl::span<ubyte> bytes) {
        const auto topic = gsl::to_string(topicSpan);

        if(_useCache && _cache.find(topic) != _cache.end()) {
            for(auto subscriber: _cache[topic]) subscriber->newMessage(bytes);
            return;
        }

        std::deque<std::string> pubParts;
        boost::split(pubParts, topic, boost::is_any_of("/"));
        publishImpl(_tree, pubParts, topic, bytes);
    }

private:

    struct Node;
    using NodePtr = std::shared_ptr<Node>;

    struct Node {
        std::unordered_map<std::string, NodePtr> children;
        std::vector<Subscription<S>> leaves;
    };

    bool _useCache;
    std::unordered_map<std::string, std::vector<S*>> _cache;
    Node _tree;

    void invalidateCache() {
        if(_useCache) _cache.clear();
    }

    static Node& addOrFindNode(Node& tree, std::deque<std::string>& parts) {
        if(parts.size() == 0) return tree;

        const auto part = parts[0]; //copying is good here
        //create if not already here
        if(tree.children.find(part) == tree.children.end()) {
            tree.children[part] = std::make_shared<Node>();
        }

        parts.pop_front();
        return addOrFindNode(*tree.children[part], parts);
    }

    void publishImpl(Node& tree, std::deque<std::string>& pubParts,
                     const std::string& topic, const gsl::span<ubyte> bytes) {

        if(pubParts.size() == 0) return;

        const std::string front = pubParts[0];
        pubParts.pop_front();

        for(const auto& part: std::vector<std::string>{front, "#", "+"}) {
            if(tree.children.find(part) != tree.children.end()) {
                Node& node = *tree.children[part];
                if(pubParts.size() == 0 || part == "#") publishNode(node, topic, bytes);

                if(pubParts.size() == 0 && node.children.find("#") != node.children.end()) {
                    //So that "finance/#" matches "finance"
                    publishNode(*node.children["#"], topic, bytes);
                }

                publishImpl(node, pubParts, topic, bytes);
            }
        }
    }

    void publishNode(Node& node, const std::string& topic, gsl::span<ubyte> bytes) {
        for(auto& subscription: node.leaves) {
            subscription.subscriber->newMessage(bytes);
            if(_useCache) _cache[topic].emplace_back(subscription.subscriber);
        }
    }

    void unsubscribeImpl(Node& tree, const S& subscriber, const std::vector<std::string>& topics) {
        (void)tree; (void)subscriber; (void)topics;

        decltype(tree.leaves) leaves;
        std::copy_if(tree.leaves.cbegin(), tree.leaves.cend(), std::back_inserter(leaves),
                     [&subscriber, &topics](auto&& a) {
                         return !a.isSubscriber(subscriber, topics);
                     });
        std::swap(tree.leaves, leaves);

        if(tree.children.size() == 0) return;

        for(const auto& item: tree.children) {
            unsubscribeImpl(*item.second, subscriber, topics);
        }
    }
};

template<typename S>
class Subscription {
public:

    Subscription(gsl::not_null<S*> subscriber, gsl::cstring_span<> topic) noexcept :
        subscriber{subscriber}, topic{gsl::to_string(topic)} {
    }

    bool isSubscriber(const S& sub, const std::vector<std::string>& topics) const {
        const auto isSameTopic = topics.size() == 0 ||
            std::find(topics.cbegin(), topics.cend(), topic) != topics.end();
        return isSameTopic && subscriber == ⊂
    }

    gsl::not_null<S*> subscriber;
    std::string topic;
};

#endif // BROKER_H_
<|endoftext|>


<commit_before>#include <bitcoin/blockchain/organizer.hpp>

#include <bitcoin/utility/assert.hpp>

namespace libbitcoin {

block_detail::block_detail(const message::block& actual_block)
  : block_hash_(hash_block_header(actual_block)),
    processed_(false), info_{block_status::orphan, 0}
{
    actual_block_ = std::make_shared<message::block>(actual_block);
}

const message::block& block_detail::actual() const
{
    return *actual_block_;
}
std::shared_ptr<message::block> block_detail::actual_ptr() const
{
    return actual_block_;
}

void block_detail::mark_processed()
{
    processed_ = true;
}
bool block_detail::is_processed()
{
    return processed_;
}

const hash_digest& block_detail::hash() const
{
    return block_hash_;
}

void block_detail::set_info(const block_info& replace_info)
{
    info_ = replace_info;
}
const block_info& block_detail::info() const
{
    return info_;
}

void block_detail::set_errc(const std::error_code& ec)
{
    ec_ = ec;
}
const std::error_code& block_detail::errc() const
{
    return ec_;
}

orphans_pool::orphans_pool(size_t pool_size)
  : pool_(pool_size)
{
}

void orphans_pool::add(block_detail_ptr incoming_block)
{
    // No duplicates
    for (block_detail_ptr current_block: pool_)
        if (current_block->actual() == incoming_block->actual())
            return;
    pool_.push_back(incoming_block);
}

block_detail_list orphans_pool::trace(block_detail_ptr end_block)
{
    block_detail_list traced_chain;
    traced_chain.push_back(end_block);
    while (true)
    {
    resume_loop:
        const hash_digest& previous_hash =
            traced_chain.back()->actual().previous_block_hash;
        for (const block_detail_ptr current_block: pool_)
            if (current_block->hash() == previous_hash)
            {
                traced_chain.push_back(current_block);
                goto resume_loop;
            }
        break;
    }
    BITCOIN_ASSERT(traced_chain.size() > 0);
    std::reverse(traced_chain.begin(), traced_chain.end());
    return traced_chain;
}

block_detail_list orphans_pool::unprocessed()
{
    block_detail_list unprocessed_blocks;
    for (const block_detail_ptr current_block: pool_)
    {
        if (!current_block->is_processed())
            unprocessed_blocks.push_back(current_block);
    }
    // Earlier blocks come into pool first. Lets match that
    // Helps avoid fragmentation, but isn't neccessary
    std::reverse(unprocessed_blocks.begin(), unprocessed_blocks.end());
    return unprocessed_blocks;
}

void orphans_pool::remove(block_detail_ptr remove_block)
{
    auto it = std::find(pool_.begin(), pool_.end(), remove_block);
    BITCOIN_ASSERT(it != pool_.end());
    pool_.erase(it);
}

organizer::organizer(orphans_pool_ptr orphans, chain_keeper_ptr chain)
  : orphans_(orphans), chain_(chain)
{
}

void organizer::start()
{
    // Load unprocessed blocks
    process_queue_ = orphans_->unprocessed();
    // As we loop, we pop blocks off and process them
    while (!process_queue_.empty())
    {
        block_detail_ptr process_block = process_queue_.back();
        process_queue_.pop_back();

        // process() can remove blocks from the queue too
        chain_->start();
        process(process_block);
        // May have already been stopped by replace_chain
        chain_->stop();
    }
}

void organizer::process(block_detail_ptr process_block)
{
    // Trace the chain in the orphan pool
    block_detail_list orphan_chain = orphans_->trace(process_block);
    int fork_index =
        chain_->find_index(orphan_chain[0]->actual().previous_block_hash);
    if (fork_index != -1)
        // replace_chain will call chain_->stop()
        replace_chain(fork_index, orphan_chain);
    // Don't mark all orphan_chain as processed here because there might be
    // a winning fork from an earlier block
}

void organizer::replace_chain(int fork_index,
    block_detail_list& orphan_chain)
{
    big_number orphan_work = 0;
    // Starting from beginning of the chain, validate blocks
    for (int orphan_index = 0; orphan_index < orphan_chain.size();
        ++orphan_index)
    {
        std::error_code invalid_reason =
            verify(fork_index, orphan_chain, orphan_index);
        // Invalid block found
        if (invalid_reason)
        {
            clip_orphans(orphan_chain, orphan_index, invalid_reason);
            // Stop summing work once we discover an invalid block
            break;
        }
        const message::block& orphan_block =
            orphan_chain[orphan_index]->actual();
        orphan_work += block_work(orphan_block.bits);
    }
    // All remaining blocks in orphan_chain should all be valid now
    // Compare the difficulty of the 2 forks (original and orphan)
    big_number main_work = chain_->end_slice_difficulty(fork_index + 1);
    if (orphan_work <= main_work)
        return;
    // Replace! Switch!
    block_detail_list replaced_slice = chain_->end_slice(fork_index + 1);
    // We add the arriving blocks first to the main chain because if
    // we add the blocks being replaced back to the pool first then
    // the we can push the arrival blocks off the bottom of the
    // circular buffer.
    // Then when we try to remove the block from the orphans pool,
    // if will fail to find it. I would rather not add an exception
    // there so that problems will show earlier.
    // All arrival_blocks should be blocks from the pool.
    int arrival_index = fork_index;
    for (block_detail_ptr arrival_block: orphan_chain)
    {
        orphans_->remove(arrival_block);
        ++arrival_index;
        arrival_block->set_info({block_status::confirmed, arrival_index});
        chain_->add(arrival_block);
    }
    // Now add the old blocks back to the pool
    for (block_detail_ptr replaced_block: replaced_slice)
    {
        replaced_block->mark_processed();
        replaced_block->set_info({block_status::orphan, 0});
        orphans_->add(replaced_block);
    }
    chain_->stop();
    notify_reorganize(fork_index, orphan_chain, replaced_slice);
}

void lazy_remove(block_detail_list& process_queue,
    block_detail_ptr remove_block)
{
    auto it = std::find(process_queue.begin(), process_queue.end(),
        remove_block);
    if (it != process_queue.end())
        process_queue.erase(it);
}

void organizer::clip_orphans(block_detail_list& orphan_chain,
    int orphan_index, const std::error_code& invalid_reason)
{
    auto orphan_start = orphan_chain.begin() + orphan_index;
    // Remove from orphans pool
    for (auto it = orphan_start; it != orphan_chain.end(); ++it)
    {
        if (it == orphan_start)
            (*it)->set_errc(invalid_reason);
        else
            (*it)->set_errc(error::previous_block_invalid);
        (*it)->set_info({block_status::rejected, 0});
        orphans_->remove(*it);
        // Also erase from process_queue so we avoid trying to re-process
        // invalid blocks and remove try to remove non-existant blocks.
        lazy_remove(process_queue_, *it);
    }
    orphan_chain.erase(orphan_start, orphan_chain.end());
}

void organizer::notify_reorganize(
    size_t fork_point,
    const block_detail_list& orphan_chain,
    const block_detail_list& replaced_slice)
{
    // Strip out the meta-info, to convert to format which can
    // be passed to subscribe handlers
    // orphan_chain = arrival blocks
    // replaced slice = replaced chain
    blockchain::block_list arrival_blocks, replaced_blocks;
    for (block_detail_ptr arrival_block: orphan_chain)
        arrival_blocks.push_back(arrival_block->actual_ptr());
    for (block_detail_ptr replaced_block: replaced_slice)
        replaced_blocks.push_back(replaced_block->actual_ptr());
    reorganize_occured(fork_point, arrival_blocks, replaced_blocks);
}

} // namespace libbitcoin

<commit_msg>BUGFIX: mark as processed blocks removed from queue.<commit_after>#include <bitcoin/blockchain/organizer.hpp>

#include <bitcoin/utility/assert.hpp>

namespace libbitcoin {

block_detail::block_detail(const message::block& actual_block)
  : block_hash_(hash_block_header(actual_block)),
    processed_(false), info_{block_status::orphan, 0}
{
    actual_block_ = std::make_shared<message::block>(actual_block);
}

const message::block& block_detail::actual() const
{
    return *actual_block_;
}
std::shared_ptr<message::block> block_detail::actual_ptr() const
{
    return actual_block_;
}

void block_detail::mark_processed()
{
    processed_ = true;
}
bool block_detail::is_processed()
{
    return processed_;
}

const hash_digest& block_detail::hash() const
{
    return block_hash_;
}

void block_detail::set_info(const block_info& replace_info)
{
    info_ = replace_info;
}
const block_info& block_detail::info() const
{
    return info_;
}

void block_detail::set_errc(const std::error_code& ec)
{
    ec_ = ec;
}
const std::error_code& block_detail::errc() const
{
    return ec_;
}

orphans_pool::orphans_pool(size_t pool_size)
  : pool_(pool_size)
{
}

void orphans_pool::add(block_detail_ptr incoming_block)
{
    // No duplicates
    for (block_detail_ptr current_block: pool_)
        if (current_block->actual() == incoming_block->actual())
            return;
    pool_.push_back(incoming_block);
}

block_detail_list orphans_pool::trace(block_detail_ptr end_block)
{
    block_detail_list traced_chain;
    traced_chain.push_back(end_block);
    while (true)
    {
    resume_loop:
        const hash_digest& previous_hash =
            traced_chain.back()->actual().previous_block_hash;
        for (const block_detail_ptr current_block: pool_)
            if (current_block->hash() == previous_hash)
            {
                traced_chain.push_back(current_block);
                goto resume_loop;
            }
        break;
    }
    BITCOIN_ASSERT(traced_chain.size() > 0);
    std::reverse(traced_chain.begin(), traced_chain.end());
    return traced_chain;
}

block_detail_list orphans_pool::unprocessed()
{
    block_detail_list unprocessed_blocks;
    for (const block_detail_ptr current_block: pool_)
    {
        if (!current_block->is_processed())
            unprocessed_blocks.push_back(current_block);
    }
    // Earlier blocks come into pool first. Lets match that
    // Helps avoid fragmentation, but isn't neccessary
    std::reverse(unprocessed_blocks.begin(), unprocessed_blocks.end());
    return unprocessed_blocks;
}

void orphans_pool::remove(block_detail_ptr remove_block)
{
    auto it = std::find(pool_.begin(), pool_.end(), remove_block);
    BITCOIN_ASSERT(it != pool_.end());
    pool_.erase(it);
}

organizer::organizer(orphans_pool_ptr orphans, chain_keeper_ptr chain)
  : orphans_(orphans), chain_(chain)
{
}

void organizer::start()
{
    // Load unprocessed blocks
    process_queue_ = orphans_->unprocessed();
    // As we loop, we pop blocks off and process them
    while (!process_queue_.empty())
    {
        block_detail_ptr process_block = process_queue_.back();
        process_queue_.pop_back();

        // process() can remove blocks from the queue too
        chain_->start();
        process(process_block);
        // May have already been stopped by replace_chain
        chain_->stop();
    }
}

void organizer::process(block_detail_ptr process_block)
{
    // Trace the chain in the orphan pool
    block_detail_list orphan_chain = orphans_->trace(process_block);
    int fork_index =
        chain_->find_index(orphan_chain[0]->actual().previous_block_hash);
    if (fork_index != -1)
        // replace_chain will call chain_->stop()
        replace_chain(fork_index, orphan_chain);
    // Don't mark all orphan_chain as processed here because there might be
    // a winning fork from an earlier block
    process_block->mark_processed();
}

void organizer::replace_chain(int fork_index,
    block_detail_list& orphan_chain)
{
    big_number orphan_work = 0;
    // Starting from beginning of the chain, validate blocks
    for (int orphan_index = 0; orphan_index < orphan_chain.size();
        ++orphan_index)
    {
        std::error_code invalid_reason =
            verify(fork_index, orphan_chain, orphan_index);
        // Invalid block found
        if (invalid_reason)
        {
            clip_orphans(orphan_chain, orphan_index, invalid_reason);
            // Stop summing work once we discover an invalid block
            break;
        }
        const message::block& orphan_block =
            orphan_chain[orphan_index]->actual();
        orphan_work += block_work(orphan_block.bits);
    }
    // All remaining blocks in orphan_chain should all be valid now
    // Compare the difficulty of the 2 forks (original and orphan)
    big_number main_work = chain_->end_slice_difficulty(fork_index + 1);
    if (orphan_work <= main_work)
        return;
    // Replace! Switch!
    block_detail_list replaced_slice = chain_->end_slice(fork_index + 1);
    // We add the arriving blocks first to the main chain because if
    // we add the blocks being replaced back to the pool first then
    // the we can push the arrival blocks off the bottom of the
    // circular buffer.
    // Then when we try to remove the block from the orphans pool,
    // if will fail to find it. I would rather not add an exception
    // there so that problems will show earlier.
    // All arrival_blocks should be blocks from the pool.
    int arrival_index = fork_index;
    for (block_detail_ptr arrival_block: orphan_chain)
    {
        orphans_->remove(arrival_block);
        ++arrival_index;
        arrival_block->set_info({block_status::confirmed, arrival_index});
        chain_->add(arrival_block);
    }
    // Now add the old blocks back to the pool
    for (block_detail_ptr replaced_block: replaced_slice)
    {
        replaced_block->mark_processed();
        replaced_block->set_info({block_status::orphan, 0});
        orphans_->add(replaced_block);
    }
    chain_->stop();
    notify_reorganize(fork_index, orphan_chain, replaced_slice);
}

void lazy_remove(block_detail_list& process_queue,
    block_detail_ptr remove_block)
{
    auto it = std::find(process_queue.begin(), process_queue.end(),
        remove_block);
    if (it != process_queue.end())
        process_queue.erase(it);
    remove_block->mark_processed();
}

void organizer::clip_orphans(block_detail_list& orphan_chain,
    int orphan_index, const std::error_code& invalid_reason)
{
    auto orphan_start = orphan_chain.begin() + orphan_index;
    // Remove from orphans pool
    for (auto it = orphan_start; it != orphan_chain.end(); ++it)
    {
        if (it == orphan_start)
            (*it)->set_errc(invalid_reason);
        else
            (*it)->set_errc(error::previous_block_invalid);
        (*it)->set_info({block_status::rejected, 0});
        orphans_->remove(*it);
        // Also erase from process_queue so we avoid trying to re-process
        // invalid blocks and remove try to remove non-existant blocks.
        lazy_remove(process_queue_, *it);
    }
    orphan_chain.erase(orphan_start, orphan_chain.end());
}

void organizer::notify_reorganize(
    size_t fork_point,
    const block_detail_list& orphan_chain,
    const block_detail_list& replaced_slice)
{
    // Strip out the meta-info, to convert to format which can
    // be passed to subscribe handlers
    // orphan_chain = arrival blocks
    // replaced slice = replaced chain
    blockchain::block_list arrival_blocks, replaced_blocks;
    for (block_detail_ptr arrival_block: orphan_chain)
        arrival_blocks.push_back(arrival_block->actual_ptr());
    for (block_detail_ptr replaced_block: replaced_slice)
        replaced_blocks.push_back(replaced_block->actual_ptr());
    reorganize_occured(fork_point, arrival_blocks, replaced_blocks);
}

} // namespace libbitcoin

<|endoftext|>