<commit_before>// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "ConnEx.h"

#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <stdio.h>

#include <k4ainternal/logging.h>

#define CONNEX_CMD_PORT "port"
#define CONNEX_CMD_VOLTS "volts"
#define CONNEX_CMD_AMPS "amps"
#define CONNEX_CMD_VERSION "version"

// This is the version expected to come back from the connection exerciser.
// This consists of the hardcoded HMD Validation Kit version and the type of shield.
#define CONN_EX_VERSION "0108"

typedef struct connection_exerciser_internal_t
{
    HANDLE serialHandle;
} connection_exerciser_internal_t;

static HANDLE OpenComPort(LPCSTR comPort)
{
    // Open serial port
    HANDLE serialHandle;

    serialHandle = CreateFile(comPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
    if (serialHandle == INVALID_HANDLE_VALUE || serialHandle == NULL)
    {
        DWORD lastError = GetLastError();

        if (lastError != ERROR_FILE_NOT_FOUND)
        {
            LOG_ERROR("Failed to open %s. Last Error=%d", comPort, lastError);
        }
        return INVALID_HANDLE_VALUE;
    }

    // Do some basic settings
    DCB serialParams = { 0 };
    serialParams.DCBlength = sizeof(serialParams);

    if (!GetCommState(serialHandle, &serialParams))
    {
        LOG_ERROR("GetCommState Failed. Last Error=%d", comPort, GetLastError());
        CloseHandle(serialHandle);
        return INVALID_HANDLE_VALUE;
    }

    serialParams.BaudRate = CBR_9600;
    serialParams.ByteSize = 8;
    serialParams.StopBits = ONESTOPBIT;
    serialParams.Parity = NOPARITY;
    serialParams.fDtrControl = DTR_CONTROL_DISABLE;
    serialParams.fRtsControl = RTS_CONTROL_DISABLE;
    if (!SetCommState(serialHandle, &serialParams))
    {
        LOG_ERROR("SetCommState Failed. Last Error=%d", comPort, GetLastError());
        CloseHandle(serialHandle);
        return INVALID_HANDLE_VALUE;
    }

    // Set timeouts
    COMMTIMEOUTS timeout = { 0 };
    if (!GetCommTimeouts(serialHandle, &timeout))
    {
        LOG_ERROR("GetCommTimeouts Failed. Last Error=%d", comPort, GetLastError());
        CloseHandle(serialHandle);
        return INVALID_HANDLE_VALUE;
    }

    timeout.ReadTotalTimeoutConstant = 500;
    if (!SetCommTimeouts(serialHandle, &timeout))
    {
        LOG_ERROR("SetCommTimeouts Failed. Last Error=%d", comPort, GetLastError());
        CloseHandle(serialHandle);
        return INVALID_HANDLE_VALUE;
    }

    return serialHandle;
}

connection_exerciser::connection_exerciser()
{
    state = new (std::nothrow) connection_exerciser_internal_t();
}

connection_exerciser::~connection_exerciser()
{
    if (state->serialHandle != INVALID_HANDLE_VALUE)
    {
        CloseHandle(state->serialHandle);
    }
    delete state;
}

k4a_result_t connection_exerciser::set_usb_port(int port)
{
    char usbPort[16] = { 0 };
    if (sprintf_s(usbPort, "%d", port) == -1)
    {
        LOG_ERROR("Failed to generate the USB port command.");
        return K4A_RESULT_FAILED;
    }

    return TRACE_CALL(send_command(CONNEX_CMD_PORT, usbPort));
}

int connection_exerciser::get_usb_port()
{
    char buffer[16] = { 0 };
    if (K4A_FAILED(TRACE_CALL(send_command(CONNEX_CMD_PORT, nullptr, buffer))))
    {
        return -1;
    }

    int rawValue;
    sscanf_s(buffer, "%d", &rawValue);
    return rawValue;
}

float connection_exerciser::get_voltage_reading()
{
    char buffer[16] = { 0 };
    if (K4A_FAILED(TRACE_CALL(send_command(CONNEX_CMD_VOLTS, nullptr, buffer))))
    {
        return -1;
    }

    int rawValue;
    if (sscanf_s(buffer, "%d", &rawValue) == -1)
    {
        LOG_ERROR("Failed to parse response.");
        return -1;
    }
    return (float)(rawValue / 100.0);
}

float connection_exerciser::get_current_reading()
{
    char buffer[16] = { 0 };
    if (K4A_FAILED(TRACE_CALL(send_command(CONNEX_CMD_AMPS, nullptr, buffer))))
    {
        return -1;
    }

    int rawValue;
    if (sscanf_s(buffer, "%d", &rawValue) == -1)
    {
        LOG_ERROR("Failed to parse response.");
        return -1;
    }

    // The "1000" digit appears to be a sign digit. A negative number would be 1000 + the value. With this scheme
    // "negative zero" is possible and needs to be converted to 0.
    if (rawValue >= 1000)
    {
        rawValue = 1000 - rawValue;
    }

    return (float)(rawValue / 100.0);
}

template<size_t size>
inline k4a_result_t connection_exerciser::send_command(const char *command,
                                                       const char *parameter,
                                                       char (&response)[size])
{
    return send_command(command, parameter, response, size);
}

inline k4a_result_t connection_exerciser::send_command(const char *command, const char *parameter)
{
    return send_command(command, parameter, nullptr, 0);
}

k4a_result_t connection_exerciser::send_command(const char *command, const char *parameter, char *response, size_t size)
{
    RETURN_VALUE_IF_ARG(K4A_RESULT_FAILED, command == NULL);

    DWORD command_length = 0;
    DWORD bytes_transfered = 0;
    char buffer[1024] = { 0 };

    if (parameter != nullptr)
    {
        if ((command_length = sprintf_s(buffer, "%s %s\r\n", command, parameter)) == -1)
        {
            LOG_ERROR("Failed to generate the command.");
            return K4A_RESULT_FAILED;
        }
    }
    else
    {
        if ((command_length = sprintf_s(buffer, "%s\r\n", command)) == -1)
        {
            LOG_ERROR("Failed to generate the command.");
            return K4A_RESULT_FAILED;
        }
    }

    if (WriteFile(state->serialHandle, buffer, command_length, nullptr, nullptr) == 0)
    {
        LOG_ERROR("WriteFile failed with %d", GetLastError());
        return K4A_RESULT_FAILED;
    }
    buffer[0] = '\0';

    if (ReadFile(state->serialHandle, buffer, sizeof(buffer), &bytes_transfered, nullptr) == 0)
    {
        LOG_ERROR("ReadFile failed with %d", GetLastError());
        return K4A_RESULT_FAILED;
    }

    buffer[bytes_transfered] = '\0';

    if (response != nullptr)
    {
        strcpy_s(response, size, buffer);
        for (size_t i = strlen(response) - 1; i >= 0; --i)
        {
            if (response[i] == '\n' || response[i] == '\r')
            {
                response[i] = '\0';
            }
            else
            {
                break;
            }
        }
    }

    return K4A_RESULT_SUCCEEDED;
}

k4a_result_t connection_exerciser::find_connection_exerciser()
{
    LOG_INFO("Searching for a connection exerciser...", 0);

    char comPort[16] = { 0 };
    char buffer[1024] = { 0 };

    if (state->serialHandle != INVALID_HANDLE_VALUE)
    {
        CloseHandle(state->serialHandle);
        state->serialHandle = INVALID_HANDLE_VALUE;
    }

    for (int i = 1; i < 10; ++i)
    {
        sprintf_s(comPort, "COM%d", i);
        LOG_INFO("Opening %s", comPort);
        state->serialHandle = OpenComPort(comPort);

        if (state->serialHandle != INVALID_HANDLE_VALUE)
        {
            if (K4A_SUCCEEDED(TRACE_CALL(send_command(CONNEX_CMD_VERSION, nullptr, buffer))) &&
                strcmp(buffer, CONN_EX_VERSION) == 0)
            {
                return K4A_RESULT_SUCCEEDED;
            }
            else
            {
                CloseHandle(state->serialHandle);
                state->serialHandle = INVALID_HANDLE_VALUE;
            }
        }
    }

    return K4A_RESULT_FAILED;
}
<commit_msg>Fix compile error for std::nothrow (#1560)<commit_after>// Copyright (c) Microsoft Corporation. All rights reserved.
// Licensed under the MIT License.

#include "ConnEx.h"

#define VC_EXTRALEAN
#define WIN32_LEAN_AND_MEAN
#include <Windows.h>
#include <stdio.h>
#include <new>

#include <k4ainternal/logging.h>

#define CONNEX_CMD_PORT "port"
#define CONNEX_CMD_VOLTS "volts"
#define CONNEX_CMD_AMPS "amps"
#define CONNEX_CMD_VERSION "version"

// This is the version expected to come back from the connection exerciser.
// This consists of the hardcoded HMD Validation Kit version and the type of shield.
#define CONN_EX_VERSION "0108"

typedef struct connection_exerciser_internal_t
{
    HANDLE serialHandle;
} connection_exerciser_internal_t;

static HANDLE OpenComPort(LPCSTR comPort)
{
    // Open serial port
    HANDLE serialHandle;

    serialHandle = CreateFile(comPort, GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING, 0, NULL);
    if (serialHandle == INVALID_HANDLE_VALUE || serialHandle == NULL)
    {
        DWORD lastError = GetLastError();

        if (lastError != ERROR_FILE_NOT_FOUND)
        {
            LOG_ERROR("Failed to open %s. Last Error=%d", comPort, lastError);
        }
        return INVALID_HANDLE_VALUE;
    }

    // Do some basic settings
    DCB serialParams = { 0 };
    serialParams.DCBlength = sizeof(serialParams);

    if (!GetCommState(serialHandle, &serialParams))
    {
        LOG_ERROR("GetCommState Failed. Last Error=%d", comPort, GetLastError());
        CloseHandle(serialHandle);
        return INVALID_HANDLE_VALUE;
    }

    serialParams.BaudRate = CBR_9600;
    serialParams.ByteSize = 8;
    serialParams.StopBits = ONESTOPBIT;
    serialParams.Parity = NOPARITY;
    serialParams.fDtrControl = DTR_CONTROL_DISABLE;
    serialParams.fRtsControl = RTS_CONTROL_DISABLE;
    if (!SetCommState(serialHandle, &serialParams))
    {
        LOG_ERROR("SetCommState Failed. Last Error=%d", comPort, GetLastError());
        CloseHandle(serialHandle);
        return INVALID_HANDLE_VALUE;
    }

    // Set timeouts
    COMMTIMEOUTS timeout = { 0 };
    if (!GetCommTimeouts(serialHandle, &timeout))
    {
        LOG_ERROR("GetCommTimeouts Failed. Last Error=%d", comPort, GetLastError());
        CloseHandle(serialHandle);
        return INVALID_HANDLE_VALUE;
    }

    timeout.ReadTotalTimeoutConstant = 500;
    if (!SetCommTimeouts(serialHandle, &timeout))
    {
        LOG_ERROR("SetCommTimeouts Failed. Last Error=%d", comPort, GetLastError());
        CloseHandle(serialHandle);
        return INVALID_HANDLE_VALUE;
    }

    return serialHandle;
}

connection_exerciser::connection_exerciser()
{
    state = new (std::nothrow) connection_exerciser_internal_t();
}

connection_exerciser::~connection_exerciser()
{
    if (state->serialHandle != INVALID_HANDLE_VALUE)
    {
        CloseHandle(state->serialHandle);
    }
    delete state;
}

k4a_result_t connection_exerciser::set_usb_port(int port)
{
    char usbPort[16] = { 0 };
    if (sprintf_s(usbPort, "%d", port) == -1)
    {
        LOG_ERROR("Failed to generate the USB port command.");
        return K4A_RESULT_FAILED;
    }

    return TRACE_CALL(send_command(CONNEX_CMD_PORT, usbPort));
}

int connection_exerciser::get_usb_port()
{
    char buffer[16] = { 0 };
    if (K4A_FAILED(TRACE_CALL(send_command(CONNEX_CMD_PORT, nullptr, buffer))))
    {
        return -1;
    }

    int rawValue;
    sscanf_s(buffer, "%d", &rawValue);
    return rawValue;
}

float connection_exerciser::get_voltage_reading()
{
    char buffer[16] = { 0 };
    if (K4A_FAILED(TRACE_CALL(send_command(CONNEX_CMD_VOLTS, nullptr, buffer))))
    {
        return -1;
    }

    int rawValue;
    if (sscanf_s(buffer, "%d", &rawValue) == -1)
    {
        LOG_ERROR("Failed to parse response.");
        return -1;
    }
    return (float)(rawValue / 100.0);
}

float connection_exerciser::get_current_reading()
{
    char buffer[16] = { 0 };
    if (K4A_FAILED(TRACE_CALL(send_command(CONNEX_CMD_AMPS, nullptr, buffer))))
    {
        return -1;
    }

    int rawValue;
    if (sscanf_s(buffer, "%d", &rawValue) == -1)
    {
        LOG_ERROR("Failed to parse response.");
        return -1;
    }

    // The "1000" digit appears to be a sign digit. A negative number would be 1000 + the value. With this scheme
    // "negative zero" is possible and needs to be converted to 0.
    if (rawValue >= 1000)
    {
        rawValue = 1000 - rawValue;
    }

    return (float)(rawValue / 100.0);
}

template<size_t size>
inline k4a_result_t connection_exerciser::send_command(const char *command,
                                                       const char *parameter,
                                                       char (&response)[size])
{
    return send_command(command, parameter, response, size);
}

inline k4a_result_t connection_exerciser::send_command(const char *command, const char *parameter)
{
    return send_command(command, parameter, nullptr, 0);
}

k4a_result_t connection_exerciser::send_command(const char *command, const char *parameter, char *response, size_t size)
{
    RETURN_VALUE_IF_ARG(K4A_RESULT_FAILED, command == NULL);

    DWORD command_length = 0;
    DWORD bytes_transfered = 0;
    char buffer[1024] = { 0 };

    if (parameter != nullptr)
    {
        if ((command_length = sprintf_s(buffer, "%s %s\r\n", command, parameter)) == -1)
        {
            LOG_ERROR("Failed to generate the command.");
            return K4A_RESULT_FAILED;
        }
    }
    else
    {
        if ((command_length = sprintf_s(buffer, "%s\r\n", command)) == -1)
        {
            LOG_ERROR("Failed to generate the command.");
            return K4A_RESULT_FAILED;
        }
    }

    if (WriteFile(state->serialHandle, buffer, command_length, nullptr, nullptr) == 0)
    {
        LOG_ERROR("WriteFile failed with %d", GetLastError());
        return K4A_RESULT_FAILED;
    }
    buffer[0] = '\0';

    if (ReadFile(state->serialHandle, buffer, sizeof(buffer), &bytes_transfered, nullptr) == 0)
    {
        LOG_ERROR("ReadFile failed with %d", GetLastError());
        return K4A_RESULT_FAILED;
    }

    buffer[bytes_transfered] = '\0';

    if (response != nullptr)
    {
        strcpy_s(response, size, buffer);
        for (size_t i = strlen(response) - 1; i >= 0; --i)
        {
            if (response[i] == '\n' || response[i] == '\r')
            {
                response[i] = '\0';
            }
            else
            {
                break;
            }
        }
    }

    return K4A_RESULT_SUCCEEDED;
}

k4a_result_t connection_exerciser::find_connection_exerciser()
{
    LOG_INFO("Searching for a connection exerciser...", 0);

    char comPort[16] = { 0 };
    char buffer[1024] = { 0 };

    if (state->serialHandle != INVALID_HANDLE_VALUE)
    {
        CloseHandle(state->serialHandle);
        state->serialHandle = INVALID_HANDLE_VALUE;
    }

    for (int i = 1; i < 10; ++i)
    {
        sprintf_s(comPort, "COM%d", i);
        LOG_INFO("Opening %s", comPort);
        state->serialHandle = OpenComPort(comPort);

        if (state->serialHandle != INVALID_HANDLE_VALUE)
        {
            if (K4A_SUCCEEDED(TRACE_CALL(send_command(CONNEX_CMD_VERSION, nullptr, buffer))) &&
                strcmp(buffer, CONN_EX_VERSION) == 0)
            {
                return K4A_RESULT_SUCCEEDED;
            }
            else
            {
                CloseHandle(state->serialHandle);
                state->serialHandle = INVALID_HANDLE_VALUE;
            }
        }
    }

    return K4A_RESULT_FAILED;
}
<|endoftext|>


<commit_before>/*
 * RtAudio Bridge for DPF
 * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef RTAUDIO_BRIDGE_HPP_INCLUDED
#define RTAUDIO_BRIDGE_HPP_INCLUDED

#include "NativeBridge.hpp"

#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS == 0
# error RtAudio without audio does not make sense
#endif

#if defined(DISTRHO_OS_MAC)
# define __MACOSX_CORE__
# define RTAUDIO_API_TYPE MACOSX_CORE
# define RTMIDI_API_TYPE MACOSX_CORE
#elif defined(DISTRHO_OS_WINDOWS) && !defined(_MSC_VER)
# define __WINDOWS_DS__
# define RTAUDIO_API_TYPE WINDOWS_DS
# define RTMIDI_API_TYPE WINDOWS_MM
#else
# if defined(HAVE_PULSEAUDIO)
#  define __LINUX_PULSE__
#  define RTAUDIO_API_TYPE LINUX_PULSE
# elif defined(HAVE_ALSA)
#  define __LINUX_ALSA__
 # define RTAUDIO_API_TYPE LINUX_ALSA
# endif
# ifdef HAVE_ALSA
#  define RTMIDI_API_TYPE LINUX_ALSA
# endif
#endif

#ifdef RTAUDIO_API_TYPE
# include "rtaudio/RtAudio.h"
# include "rtmidi/RtMidi.h"
# include "../../extra/ScopedPointer.hpp"
# include "../../extra/String.hpp"

using DISTRHO_NAMESPACE::ScopedPointer;
using DISTRHO_NAMESPACE::String;

struct RtAudioBridge : NativeBridge {
    // pointer to RtAudio instance
    ScopedPointer<RtAudio> handle;
    bool captureEnabled = false;
   #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_INPUT
    std::vector<RtMidiIn> midiIns;
   #endif
   #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
    std::vector<RtMidiOut> midiOuts;
   #endif

    // caching
    String name;
    uint nextBufferSize = 512;

    RtAudioBridge()
    {
       #if defined(RTMIDI_API_TYPE) && (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT)
        midiAvailable = true;
       #endif
    }

    const char* getVersion() const noexcept
    {
        return RTAUDIO_VERSION;
    }

    bool open(const char* const clientName) override
    {
        name = clientName;
        return _open(false);
    }

    bool close() override
    {
        DISTRHO_SAFE_ASSERT_RETURN(handle != nullptr, false);

        if (handle->isStreamRunning())
        {
            try {
                handle->abortStream();
            } DISTRHO_SAFE_EXCEPTION("handle->abortStream()");
        }

       #if DISTRHO_PLUGIN_NUM_INPUTS > 0
        freeBuffers();
       #endif
        handle = nullptr;
        return true;
    }

    bool activate() override
    {
        DISTRHO_SAFE_ASSERT_RETURN(handle != nullptr, false);

        try {
            handle->startStream();
        } DISTRHO_SAFE_EXCEPTION_RETURN("handle->startStream()", false);

        return true;
    }

    bool deactivate() override
    {
        DISTRHO_SAFE_ASSERT_RETURN(handle != nullptr, false);

        try {
            handle->stopStream();
        } DISTRHO_SAFE_EXCEPTION_RETURN("handle->stopStream()", false);

        return true;
    }

    bool isAudioInputEnabled() const override
    {
       #if DISTRHO_PLUGIN_NUM_INPUTS > 0
        return captureEnabled;
       #else
        return false;
       #endif
    }

    bool requestAudioInput() override
    {
       #if DISTRHO_PLUGIN_NUM_INPUTS > 0
        // stop audio first
        deactivate();
        close();

        // try to open with capture enabled
        const bool ok = _open(true);

        if (ok)
            captureEnabled = true;
        else
            _open(false);

        activate();
        return ok;
       #else
        return false;
       #endif
    }

    bool isMIDIEnabled() const override
    {
        d_stdout("%s %d", __PRETTY_FUNCTION__, __LINE__);
       #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_INPUT
        if (!midiIns.empty())
            return true;
       #endif
       #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
        if (!midiOuts.empty())
            return true;
       #endif
        return false;
    }

    bool requestMIDI() override
    {
        d_stdout("%s %d", __PRETTY_FUNCTION__, __LINE__);
        // clear ports in use first
       #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_INPUT
        if (!midiIns.empty())
        {
            try {
                midiIns.clear();
            } catch (const RtMidiError& err) {
                d_safe_exception(err.getMessage().c_str(), __FILE__, __LINE__);
                return false;
            } DISTRHO_SAFE_EXCEPTION_RETURN("midiIns.clear()", false);
        }
       #endif
       #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
        if (!midiOuts.size())
        {
            try {
                midiOuts.clear();
            } catch (const RtMidiError& err) {
                d_safe_exception(err.getMessage().c_str(), __FILE__, __LINE__);
                return false;
            } DISTRHO_SAFE_EXCEPTION_RETURN("midiOuts.clear()", false);
        }
       #endif

        // query port count
       #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_INPUT
        uint midiInCount;
        try {
            RtMidiIn midiIn(RtMidi::RTMIDI_API_TYPE, name.buffer());
            midiInCount = midiIn.getPortCount();
        } catch (const RtMidiError& err) {
            d_safe_exception(err.getMessage().c_str(), __FILE__, __LINE__);
            return false;
        } DISTRHO_SAFE_EXCEPTION_RETURN("midiIn.getPortCount()", false);
       #endif
       #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
        uint midiOutCount;
        try {
            RtMidiOut midiOut(RtMidi::RTMIDI_API_TYPE, name.buffer());
            midiOutCount = midiOut.getPortCount();
        } catch (const RtMidiError& err) {
            d_safe_exception(err.getMessage().c_str(), __FILE__, __LINE__);
            return false;
        } DISTRHO_SAFE_EXCEPTION_RETURN("midiOut.getPortCount()", false);
       #endif

        // open all possible ports
       #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_INPUT
        for (uint i=0; i<midiInCount; ++i)
        {
            try {
                RtMidiIn midiIn(RtMidi::RTMIDI_API_TYPE, name.buffer());
                midiIn.setCallback(RtMidiCallback, this);
                midiIn.openPort(i);
                midiIns.push_back(std::move(midiIn));
            } catch (const RtMidiError& err) {
                d_safe_exception(err.getMessage().c_str(), __FILE__, __LINE__);
            } DISTRHO_SAFE_EXCEPTION("midiIn.openPort()");
        }
       #endif
       #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
        for (uint i=0; i<midiOutCount; ++i)
        {
            try {
                RtMidiOut midiOut(RtMidi::RTMIDI_API_TYPE, name.buffer());
                midiOut.openPort(i);
                midiOuts.push_back(std::move(midiOut));
            } catch (const RtMidiError& err) {
                d_safe_exception(err.getMessage().c_str(), __FILE__, __LINE__);
            } DISTRHO_SAFE_EXCEPTION("midiOut.openPort()");
        }
       #endif

        return true;
    }

    /* RtAudio in macOS uses a different than usual way to handle audio block size,
     * where RTAUDIO_MINIMIZE_LATENCY makes CoreAudio use very low latencies (around 15 samples).
     * As such, dynamic buffer sizes are meaningless there.
     */
   #ifndef DISTRHO_OS_MAC
    bool supportsBufferSizeChanges() const override
    {
        return true;
    }

    bool requestBufferSizeChange(const uint32_t newBufferSize) override
    {
        // stop audio first
        deactivate();
        close();

        // try to open with new buffer size
        nextBufferSize = newBufferSize;

        const bool ok = _open(captureEnabled);

        if (!ok)
        {
            // revert to old buffer size if new one failed
            nextBufferSize = bufferSize;
            _open(captureEnabled);
        }

        if (bufferSizeCallback != nullptr)
            bufferSizeCallback(bufferSize, jackBufferSizeArg);

        activate();
        return ok;
    }
   #endif

    bool _open(const bool withInput)
    {
        ScopedPointer<RtAudio> rtAudio;

        try {
            rtAudio = new RtAudio(RtAudio::RTAUDIO_API_TYPE);
        } DISTRHO_SAFE_EXCEPTION_RETURN("new RtAudio()", false);

        uint rtAudioBufferFrames = nextBufferSize;

       #if DISTRHO_PLUGIN_NUM_INPUTS > 0
        RtAudio::StreamParameters inParams;
       #endif
        RtAudio::StreamParameters* inParamsPtr = nullptr;

       #if DISTRHO_PLUGIN_NUM_INPUTS > 0
        if (withInput)
        {
            inParams.deviceId = rtAudio->getDefaultInputDevice();
            inParams.nChannels = DISTRHO_PLUGIN_NUM_INPUTS;
            inParamsPtr = &inParams;
        }
       #endif

       #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
        RtAudio::StreamParameters outParams;
        outParams.deviceId = rtAudio->getDefaultOutputDevice();
        outParams.nChannels = DISTRHO_PLUGIN_NUM_OUTPUTS;
        RtAudio::StreamParameters* const outParamsPtr = &outParams;
       #else
        RtAudio::StreamParameters* const outParamsPtr = nullptr;
       #endif

        RtAudio::StreamOptions opts;
        opts.flags = RTAUDIO_NONINTERLEAVED | RTAUDIO_MINIMIZE_LATENCY | RTAUDIO_ALSA_USE_DEFAULT;
        opts.streamName = name.buffer();

        try {
            rtAudio->openStream(outParamsPtr, inParamsPtr, RTAUDIO_FLOAT32, 48000, &rtAudioBufferFrames,
                                RtAudioCallback, this, &opts, nullptr);
        } catch (const RtAudioError& err) {
            d_safe_exception(err.getMessage().c_str(), __FILE__, __LINE__);
            return false;
        } DISTRHO_SAFE_EXCEPTION_RETURN("rtAudio->openStream()", false);

        handle = rtAudio;
        bufferSize = rtAudioBufferFrames;
        sampleRate = handle->getStreamSampleRate();
        allocBuffers(!withInput, true);
        return true;
    }

    static int RtAudioCallback(void* const outputBuffer,
                              #if DISTRHO_PLUGIN_NUM_INPUTS > 0
                               void* const inputBuffer,
                              #else
                               void*,
                              #endif
                               const uint numFrames,
                               const double /* streamTime */,
                               const RtAudioStreamStatus /* status */,
                               void* const userData)
    {
        RtAudioBridge* const self = static_cast<RtAudioBridge*>(userData);

        if (self->jackProcessCallback == nullptr)
        {
            if (outputBuffer != nullptr)
                std::memset((float*)outputBuffer, 0, sizeof(float)*numFrames*DISTRHO_PLUGIN_NUM_OUTPUTS);
            return 0;
        }

       #if DISTRHO_PLUGIN_NUM_INPUTS > 0
        if (float* const insPtr = static_cast<float*>(inputBuffer))
        {
            for (uint i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i)
                self->audioBuffers[i] = insPtr + (i * numFrames);
        }
       #endif

       #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
        if (float* const outsPtr = static_cast<float*>(outputBuffer))
        {
            for (uint i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
                self->audioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + i] = outsPtr + (i * numFrames);
        }
       #endif

        self->jackProcessCallback(numFrames, self->jackProcessArg);

        return 0;
    }

   #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_INPUT
    static void RtMidiCallback(double /*timeStamp*/, std::vector<uchar>* message, void* userData)
    {
        const size_t len = message->size();
        DISTRHO_SAFE_ASSERT_RETURN(len > 0 && len <= kMaxMIDIInputMessageSize,);

        RtAudioBridge* const self = static_cast<RtAudioBridge*>(userData);

        // TODO timestamp handling
        self->midiInBufferPending.writeByte(static_cast<uint8_t>(len));
        self->midiInBufferPending.writeCustomData(message->data(), len);
        for (uint8_t i=0; i<len; ++i)
            self->midiInBufferPending.writeByte(0);
        self->midiInBufferPending.commitWrite();
    }
   #endif
};

#endif // RTAUDIO_API_TYPE
#endif // RTAUDIO_BRIDGE_HPP_INCLUDED
<commit_msg>Fix missing native midi in some setups<commit_after>/*
 * RtAudio Bridge for DPF
 * Copyright (C) 2021-2022 Filipe Coelho <falktx@falktx.com>
 *
 * Permission to use, copy, modify, and/or distribute this software for any purpose with
 * or without fee is hereby granted, provided that the above copyright notice and this
 * permission notice appear in all copies.
 *
 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 */

#ifndef RTAUDIO_BRIDGE_HPP_INCLUDED
#define RTAUDIO_BRIDGE_HPP_INCLUDED

#include "NativeBridge.hpp"

#if DISTRHO_PLUGIN_NUM_INPUTS+DISTRHO_PLUGIN_NUM_OUTPUTS == 0
# error RtAudio without audio does not make sense
#endif

#if defined(DISTRHO_OS_MAC)
# define __MACOSX_CORE__
# define RTAUDIO_API_TYPE MACOSX_CORE
# define RTMIDI_API_TYPE MACOSX_CORE
#elif defined(DISTRHO_OS_WINDOWS) && !defined(_MSC_VER)
# define __WINDOWS_DS__
# define __WINDOWS_MM__
# define RTAUDIO_API_TYPE WINDOWS_DS
# define RTMIDI_API_TYPE WINDOWS_MM
#else
# if defined(HAVE_PULSEAUDIO)
#  define __LINUX_PULSE__
#  define RTAUDIO_API_TYPE LINUX_PULSE
# elif defined(HAVE_ALSA)
#  define RTAUDIO_API_TYPE LINUX_ALSA
# endif
# ifdef HAVE_ALSA
#  define __LINUX_ALSA__
#  define RTMIDI_API_TYPE LINUX_ALSA
# endif
#endif

#ifdef RTAUDIO_API_TYPE
# include "rtaudio/RtAudio.h"
# include "rtmidi/RtMidi.h"
# include "../../extra/ScopedPointer.hpp"
# include "../../extra/String.hpp"

using DISTRHO_NAMESPACE::ScopedPointer;
using DISTRHO_NAMESPACE::String;

struct RtAudioBridge : NativeBridge {
    // pointer to RtAudio instance
    ScopedPointer<RtAudio> handle;
    bool captureEnabled = false;
   #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_INPUT
    std::vector<RtMidiIn> midiIns;
   #endif
   #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
    std::vector<RtMidiOut> midiOuts;
   #endif

    // caching
    String name;
    uint nextBufferSize = 512;

    RtAudioBridge()
    {
       #if defined(RTMIDI_API_TYPE) && (DISTRHO_PLUGIN_WANT_MIDI_INPUT || DISTRHO_PLUGIN_WANT_MIDI_OUTPUT)
        midiAvailable = true;
       #endif
    }

    const char* getVersion() const noexcept
    {
        return RTAUDIO_VERSION;
    }

    bool open(const char* const clientName) override
    {
        name = clientName;
        return _open(false);
    }

    bool close() override
    {
        DISTRHO_SAFE_ASSERT_RETURN(handle != nullptr, false);

        if (handle->isStreamRunning())
        {
            try {
                handle->abortStream();
            } DISTRHO_SAFE_EXCEPTION("handle->abortStream()");
        }

       #if DISTRHO_PLUGIN_NUM_INPUTS > 0
        freeBuffers();
       #endif
        handle = nullptr;
        return true;
    }

    bool activate() override
    {
        DISTRHO_SAFE_ASSERT_RETURN(handle != nullptr, false);

        try {
            handle->startStream();
        } DISTRHO_SAFE_EXCEPTION_RETURN("handle->startStream()", false);

        return true;
    }

    bool deactivate() override
    {
        DISTRHO_SAFE_ASSERT_RETURN(handle != nullptr, false);

        try {
            handle->stopStream();
        } DISTRHO_SAFE_EXCEPTION_RETURN("handle->stopStream()", false);

        return true;
    }

    bool isAudioInputEnabled() const override
    {
       #if DISTRHO_PLUGIN_NUM_INPUTS > 0
        return captureEnabled;
       #else
        return false;
       #endif
    }

    bool requestAudioInput() override
    {
       #if DISTRHO_PLUGIN_NUM_INPUTS > 0
        // stop audio first
        deactivate();
        close();

        // try to open with capture enabled
        const bool ok = _open(true);

        if (ok)
            captureEnabled = true;
        else
            _open(false);

        activate();
        return ok;
       #else
        return false;
       #endif
    }

    bool isMIDIEnabled() const override
    {
        d_stdout("%s %d", __PRETTY_FUNCTION__, __LINE__);
       #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_INPUT
        if (!midiIns.empty())
            return true;
       #endif
       #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
        if (!midiOuts.empty())
            return true;
       #endif
        return false;
    }

    bool requestMIDI() override
    {
        d_stdout("%s %d", __PRETTY_FUNCTION__, __LINE__);
        // clear ports in use first
       #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_INPUT
        if (!midiIns.empty())
        {
            try {
                midiIns.clear();
            } catch (const RtMidiError& err) {
                d_safe_exception(err.getMessage().c_str(), __FILE__, __LINE__);
                return false;
            } DISTRHO_SAFE_EXCEPTION_RETURN("midiIns.clear()", false);
        }
       #endif
       #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
        if (!midiOuts.size())
        {
            try {
                midiOuts.clear();
            } catch (const RtMidiError& err) {
                d_safe_exception(err.getMessage().c_str(), __FILE__, __LINE__);
                return false;
            } DISTRHO_SAFE_EXCEPTION_RETURN("midiOuts.clear()", false);
        }
       #endif

        // query port count
       #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_INPUT
        uint midiInCount;
        try {
            RtMidiIn midiIn(RtMidi::RTMIDI_API_TYPE, name.buffer());
            midiInCount = midiIn.getPortCount();
        } catch (const RtMidiError& err) {
            d_safe_exception(err.getMessage().c_str(), __FILE__, __LINE__);
            return false;
        } DISTRHO_SAFE_EXCEPTION_RETURN("midiIn.getPortCount()", false);
       #endif
       #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
        uint midiOutCount;
        try {
            RtMidiOut midiOut(RtMidi::RTMIDI_API_TYPE, name.buffer());
            midiOutCount = midiOut.getPortCount();
        } catch (const RtMidiError& err) {
            d_safe_exception(err.getMessage().c_str(), __FILE__, __LINE__);
            return false;
        } DISTRHO_SAFE_EXCEPTION_RETURN("midiOut.getPortCount()", false);
       #endif

        // open all possible ports
       #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_INPUT
        for (uint i=0; i<midiInCount; ++i)
        {
            try {
                RtMidiIn midiIn(RtMidi::RTMIDI_API_TYPE, name.buffer());
                midiIn.setCallback(RtMidiCallback, this);
                midiIn.openPort(i);
                midiIns.push_back(std::move(midiIn));
            } catch (const RtMidiError& err) {
                d_safe_exception(err.getMessage().c_str(), __FILE__, __LINE__);
            } DISTRHO_SAFE_EXCEPTION("midiIn.openPort()");
        }
       #endif
       #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_OUTPUT
        for (uint i=0; i<midiOutCount; ++i)
        {
            try {
                RtMidiOut midiOut(RtMidi::RTMIDI_API_TYPE, name.buffer());
                midiOut.openPort(i);
                midiOuts.push_back(std::move(midiOut));
            } catch (const RtMidiError& err) {
                d_safe_exception(err.getMessage().c_str(), __FILE__, __LINE__);
            } DISTRHO_SAFE_EXCEPTION("midiOut.openPort()");
        }
       #endif

        return true;
    }

    /* RtAudio in macOS uses a different than usual way to handle audio block size,
     * where RTAUDIO_MINIMIZE_LATENCY makes CoreAudio use very low latencies (around 15 samples).
     * As such, dynamic buffer sizes are meaningless there.
     */
   #ifndef DISTRHO_OS_MAC
    bool supportsBufferSizeChanges() const override
    {
        return true;
    }

    bool requestBufferSizeChange(const uint32_t newBufferSize) override
    {
        // stop audio first
        deactivate();
        close();

        // try to open with new buffer size
        nextBufferSize = newBufferSize;

        const bool ok = _open(captureEnabled);

        if (!ok)
        {
            // revert to old buffer size if new one failed
            nextBufferSize = bufferSize;
            _open(captureEnabled);
        }

        if (bufferSizeCallback != nullptr)
            bufferSizeCallback(bufferSize, jackBufferSizeArg);

        activate();
        return ok;
    }
   #endif

    bool _open(const bool withInput)
    {
        ScopedPointer<RtAudio> rtAudio;

        try {
            rtAudio = new RtAudio(RtAudio::RTAUDIO_API_TYPE);
        } DISTRHO_SAFE_EXCEPTION_RETURN("new RtAudio()", false);

        uint rtAudioBufferFrames = nextBufferSize;

       #if DISTRHO_PLUGIN_NUM_INPUTS > 0
        RtAudio::StreamParameters inParams;
       #endif
        RtAudio::StreamParameters* inParamsPtr = nullptr;

       #if DISTRHO_PLUGIN_NUM_INPUTS > 0
        if (withInput)
        {
            inParams.deviceId = rtAudio->getDefaultInputDevice();
            inParams.nChannels = DISTRHO_PLUGIN_NUM_INPUTS;
            inParamsPtr = &inParams;
        }
       #endif

       #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
        RtAudio::StreamParameters outParams;
        outParams.deviceId = rtAudio->getDefaultOutputDevice();
        outParams.nChannels = DISTRHO_PLUGIN_NUM_OUTPUTS;
        RtAudio::StreamParameters* const outParamsPtr = &outParams;
       #else
        RtAudio::StreamParameters* const outParamsPtr = nullptr;
       #endif

        RtAudio::StreamOptions opts;
        opts.flags = RTAUDIO_NONINTERLEAVED | RTAUDIO_MINIMIZE_LATENCY | RTAUDIO_ALSA_USE_DEFAULT;
        opts.streamName = name.buffer();

        try {
            rtAudio->openStream(outParamsPtr, inParamsPtr, RTAUDIO_FLOAT32, 48000, &rtAudioBufferFrames,
                                RtAudioCallback, this, &opts, nullptr);
        } catch (const RtAudioError& err) {
            d_safe_exception(err.getMessage().c_str(), __FILE__, __LINE__);
            return false;
        } DISTRHO_SAFE_EXCEPTION_RETURN("rtAudio->openStream()", false);

        handle = rtAudio;
        bufferSize = rtAudioBufferFrames;
        sampleRate = handle->getStreamSampleRate();
        allocBuffers(!withInput, true);
        return true;
    }

    static int RtAudioCallback(void* const outputBuffer,
                              #if DISTRHO_PLUGIN_NUM_INPUTS > 0
                               void* const inputBuffer,
                              #else
                               void*,
                              #endif
                               const uint numFrames,
                               const double /* streamTime */,
                               const RtAudioStreamStatus /* status */,
                               void* const userData)
    {
        RtAudioBridge* const self = static_cast<RtAudioBridge*>(userData);

        if (self->jackProcessCallback == nullptr)
        {
            if (outputBuffer != nullptr)
                std::memset((float*)outputBuffer, 0, sizeof(float)*numFrames*DISTRHO_PLUGIN_NUM_OUTPUTS);
            return 0;
        }

       #if DISTRHO_PLUGIN_NUM_INPUTS > 0
        if (float* const insPtr = static_cast<float*>(inputBuffer))
        {
            for (uint i=0; i<DISTRHO_PLUGIN_NUM_INPUTS; ++i)
                self->audioBuffers[i] = insPtr + (i * numFrames);
        }
       #endif

       #if DISTRHO_PLUGIN_NUM_OUTPUTS > 0
        if (float* const outsPtr = static_cast<float*>(outputBuffer))
        {
            for (uint i=0; i<DISTRHO_PLUGIN_NUM_OUTPUTS; ++i)
                self->audioBuffers[DISTRHO_PLUGIN_NUM_INPUTS + i] = outsPtr + (i * numFrames);
        }
       #endif

        self->jackProcessCallback(numFrames, self->jackProcessArg);

        return 0;
    }

   #if defined(RTMIDI_API_TYPE) && DISTRHO_PLUGIN_WANT_MIDI_INPUT
    static void RtMidiCallback(double /*timeStamp*/, std::vector<uchar>* message, void* userData)
    {
        const size_t len = message->size();
        DISTRHO_SAFE_ASSERT_RETURN(len > 0 && len <= kMaxMIDIInputMessageSize,);

        RtAudioBridge* const self = static_cast<RtAudioBridge*>(userData);

        // TODO timestamp handling
        self->midiInBufferPending.writeByte(static_cast<uint8_t>(len));
        self->midiInBufferPending.writeCustomData(message->data(), len);
        for (uint8_t i=0; i<len; ++i)
            self->midiInBufferPending.writeByte(0);
        self->midiInBufferPending.commitWrite();
    }
   #endif
};

#endif // RTAUDIO_API_TYPE
#endif // RTAUDIO_BRIDGE_HPP_INCLUDED
<|endoftext|>


<commit_before>#ifndef STAN_MATH_PRIM_MAT_FUN_OPENCL_COPY_HPP
#define STAN_MATH_PRIM_MAT_FUN_OPENCL_COPY_HPP
#ifdef STAN_OPENCL

#include <stan/math/opencl/opencl_context.hpp>
#include <stan/math/opencl/kernel_cl.hpp>
#include <stan/math/opencl/matrix_cl.hpp>
#include <stan/math/opencl/kernels/copy.hpp>
#include <stan/math/opencl/kernels/pack.hpp>
#include <stan/math/opencl/kernels/unpack.hpp>
#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/scal/err/check_size_match.hpp>
#include <CL/cl.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
#include <type_traits>

namespace stan {
namespace math {

/**
 * Copies the source Eigen matrix to
 * the destination matrix that is stored
 * on the OpenCL device.
 *
 * @tparam T type of data in the Eigen matrix
 * @param dst destination matrix on the OpenCL device
 * @param src source Eigen matrix
 *
 * @throw std::invalid_argument if the
 * matrices do not have matching dimensions
 */
template <int R, int C>
void copy(matrix_cl& dst, const Eigen::Matrix<double, R, C>& src) {
  check_size_match("copy (Eigen -> (OpenCL))", "src.rows()", src.rows(),
                   "dst.rows()", dst.rows());
  check_size_match("copy (Eigen -> (OpenCL))", "src.cols()", src.cols(),
                   "dst.cols()", dst.cols());
<<<<<< 0) {
    cl::CommandQueue queue = opencl_context.queue();
    try {
      /**
       * Writes the contents of src to the OpenCL buffer
       * starting at the offset 0
       * CL_FALSE denotes that the call is non-blocking
       * This means that future kernels need to know about the copy_event
       * So that they do not execute until this transfer finishes.
       */
      cl::Event copy_event;
      queue.enqueueWriteBuffer(dst.buffer(), CL_FALSE, 0,
                               sizeof(double) * dst.size(), src.data(), NULL,
                               &copy_event);
      dst.add_event(copy_event);
    } catch (const cl::Error& e) {
      check_opencl_error("copy Eigen->(OpenCL)", e);
    }
=======
  if (src.size() == 0) {
    return;
  }
  cl::CommandQueue queue = opencl_context.queue();
  try {
    /**
     * Writes the contents of src to the OpenCL buffer
     * starting at the offset 0
     * CL_TRUE denotes that the call is blocking
     * We do not want to execute any further kernels
     * on the device until we are sure that the data is transferred)
     */
    queue.enqueueWriteBuffer(dst.buffer(), CL_TRUE, 0,
                             sizeof(double) * dst.size(), src.data());
  } catch (const cl::Error& e) {
    check_opencl_error("copy Eigen->(OpenCL)", e);
>>>>>>> upstream/develop
  }
}

/**
 * Copies the source matrix that is stored
 * on the OpenCL device to the destination Eigen
 * matrix.
 *
 * @tparam T type of data in the Eigen matrix
 * @param dst destination Eigen matrix
 * @param src source matrix on the OpenCL device
 *
 * @throw std::invalid_argument if the
 * matrices do not have matching dimensions
 */
template <int R, int C>
void copy(Eigen::Matrix<double, R, C>& dst, const matrix_cl& src) {
  check_size_match("copy ((OpenCL) -> Eigen)", "src.rows()", src.rows(),
                   "dst.rows()", dst.rows());
  check_size_match("copy ((OpenCL) -> Eigen)", "src.cols()", src.cols(),
                   "dst.cols()", dst.cols());
<<<<<< 0) {
    cl::CommandQueue queue = opencl_context.queue();
    try {
      /**
       * Reads the contents of the OpenCL buffer
       * starting at the offset 0 to the Eigen
       * matrix
       * CL_TRUE denotes that the call is blocking
       * We do not want to pass data back to the CPU until all of the jobs
       * called on the source matrix are finished.
       */
      cl::Event copy_event;
      queue.enqueueReadBuffer(src.buffer(), CL_TRUE, 0,
                              sizeof(double) * dst.size(), dst.data(),
                              &src.events(), &copy_event);
      copy_event.wait();
    } catch (const cl::Error& e) {
      check_opencl_error("copy (OpenCL)->Eigen", e);
    }
=======
  if (src.size() == 0) {
    return;
  }
  cl::CommandQueue queue = opencl_context.queue();
  try {
    /**
     * Reads the contents of the OpenCL buffer
     * starting at the offset 0 to the Eigen
     * matrix
     * CL_TRUE denotes that the call is blocking
     * We do not want to execute any further kernels
     * on the device until we are sure that the data is transferred)
     */
    queue.enqueueReadBuffer(src.buffer(), CL_TRUE, 0,
                            sizeof(double) * dst.size(), dst.data());
  } catch (const cl::Error& e) {
    check_opencl_error("copy (OpenCL)->Eigen", e);
  }
}

/**
 * Packs the flat triagnular matrix on the OpenCL device and
 * copies it to the std::vector.
 *
 * @tparam triangular_view the triangularity of the source matrix
 * @param src the flat triangular source matrix on the OpenCL device
 * @return the packed std::vector
 */
template <TriangularViewCL triangular_view>
inline std::vector<double> packed_copy(const matrix_cl& src) {
  const int packed_size = src.rows() * (src.rows() + 1) / 2;
  std::vector<double> dst(packed_size);
  if (dst.size() == 0) {
    return dst;
  }
  cl::CommandQueue queue = opencl_context.queue();
  try {
    matrix_cl packed(packed_size, 1);
    stan::math::opencl_kernels::pack(cl::NDRange(src.rows(), src.rows()),
                                     packed.buffer(), src.buffer(), src.rows(),
                                     src.rows(), triangular_view);
    queue.enqueueReadBuffer(packed.buffer(), CL_TRUE, 0,
                            sizeof(double) * packed_size, dst.data());
  } catch (const cl::Error& e) {
    check_opencl_error("packed_copy (OpenCL->std::vector)", e);
>>>>>>> upstream/develop
  }
  return dst;
}

/**
 * Copies the packed triangular matrix from
 * the source std::vector to an OpenCL buffer and
 * unpacks it to a flat matrix on the OpenCL device.
 *
 * @tparam triangular_view the triangularity of the source matrix
 * @param src the packed source std::vector
 * @param rows the number of rows in the flat matrix
 * @return the destination flat matrix on the OpenCL device
 * @throw std::invalid_argument if the
 * size of the vector does not match the expected size
 * for the packed triangular matrix
 */
template <TriangularViewCL triangular_view>
inline matrix_cl packed_copy(const std::vector<double>& src, int rows) {
  const int packed_size = rows * (rows + 1) / 2;
  check_size_match("copy (packed std::vector -> OpenCL)", "src.size()",
                   src.size(), "rows * (rows + 1) / 2", packed_size);
  matrix_cl dst(rows, rows);
  if (dst.size() == 0) {
    return dst;
  }
  cl::CommandQueue queue = opencl_context.queue();
  try {
    matrix_cl packed(packed_size, 1);
    queue.enqueueWriteBuffer(packed.buffer(), CL_TRUE, 0,
                             sizeof(double) * packed_size, src.data());
    stan::math::opencl_kernels::unpack(cl::NDRange(dst.rows(), dst.rows()),
                                       dst.buffer(), packed.buffer(),
                                       dst.rows(), dst.rows(), triangular_view);
  } catch (const cl::Error& e) {
    check_opencl_error("packed_copy (std::vector->OpenCL)", e);
  }
  return dst;
}

/**
 * Copies the source matrix to the
 * destination matrix. Both matrices
 * are stored on the OpenCL device.
 *
 * @param dst destination matrix
 * @param src source matrix
 *
 * @throw std::invalid_argument if the
 * matrices do not have matching dimensions
 */
inline void copy(matrix_cl& dst, const matrix_cl& src) {
  check_size_match("copy ((OpenCL) -> (OpenCL))", "src.rows()", src.rows(),
                   "dst.rows()", dst.rows());
  check_size_match("copy ((OpenCL) -> (OpenCL))", "src.cols()", src.cols(),
                   "dst.cols()", dst.cols());
<<<<<< 0) {
    try {
      /**
       * Copies the contents of the src buffer to the dst buffer
       * see the matrix_cl(matrix_cl&) constructor
       *  for explanation
       */
      cl::Event copy_event
          = opencl_kernels::copy(cl::NDRange(dst.rows(), dst.cols()), src, dst,
                                 dst.rows(), dst.cols());
      dst.add_event(copy_event);
    } catch (const cl::Error& e) {
      std::cout << e.err() << std::endl;
      check_opencl_error("copy (OpenCL)->(OpenCL)", e);
    }
=======
  if (src.size() == 0) {
    return;
  }
  cl::CommandQueue queue = opencl_context.queue();
  try {
    /**
     * Copies the contents of the src buffer to the dst buffer
     * see the matrix_cl(matrix_cl&) constructor
     *  for explanation
     */
    queue.enqueueCopyBuffer(src.buffer(), dst.buffer(), 0, 0,
                            sizeof(double) * src.size());
  } catch (const cl::Error& e) {
    std::cout << e.err() << std::endl;
    check_opencl_error("copy (OpenCL)->(OpenCL)", e);
>>>>>>> upstream/develop
  }
}

/**
 * Copy A 1 by 1 source matrix from the Device to  the host.
 * @tparam An arithmetic type to pass the value from the OpenCL matrix to.
 * @param dst Arithmetic to receive the matrix_cl value.
 * @param src A 1x1 matrix on the device.
 */
template <typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
inline void copy(T& dst, const matrix_cl& src) {
  check_size_match("copy ((OpenCL) -> (OpenCL))", "src.rows()", src.rows(),
                   "dst.rows()", 1);
  check_size_match("copy ((OpenCL) -> (OpenCL))", "src.cols()", src.cols(),
                   "dst.cols()", 1);
  try {
    cl::CommandQueue queue = opencl_context.queue();
    cl::Event copy_event;
    queue.enqueueReadBuffer(src.buffer(), CL_TRUE, 0, sizeof(int), &dst,
                            &src.events(), &copy_event);
  } catch (const cl::Error& e) {
    std::cout << e.err() << std::endl;
    check_opencl_error("copy (OpenCL)->(OpenCL)", e);
  }
}

/**
 * Copy an arithmetic type to the device.
 * @tparam An arithmetic type to pass the value from the OpenCL matrix to.
 * @param src Arithmetic to receive the matrix_cl value.
 * @param dst A 1x1 matrix on the device.
 */
template <typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
inline void copy(matrix_cl& dst, const T& src) {
  check_size_match("copy ((OpenCL) -> (OpenCL))", "src.rows()", dst.rows(),
                   "dst.rows()", 1);
  check_size_match("copy ((OpenCL) -> (OpenCL))", "src.cols()", dst.cols(),
                   "dst.cols()", 1);
  try {
    cl::CommandQueue queue = opencl_context.queue();
    cl::Event copy_event;
    queue.enqueueWriteBuffer(dst.buffer(), CL_FALSE, 0, sizeof(T), &src,
                             &dst.events(), &copy_event);
    dst.add_event(copy_event);
  } catch (const cl::Error& e) {
    std::cout << e.err() << std::endl;
    check_opencl_error("copy (OpenCL)->(OpenCL)", e);
  }
}

}  // namespace math
}  // namespace stan
#endif
#endif
<commit_msg>Fix merge errors<commit_after>#ifndef STAN_MATH_PRIM_MAT_FUN_OPENCL_COPY_HPP
#define STAN_MATH_PRIM_MAT_FUN_OPENCL_COPY_HPP
#ifdef STAN_OPENCL

#include <stan/math/opencl/opencl_context.hpp>
#include <stan/math/opencl/kernel_cl.hpp>
#include <stan/math/opencl/matrix_cl.hpp>
#include <stan/math/opencl/kernels/copy.hpp>
#include <stan/math/opencl/kernels/pack.hpp>
#include <stan/math/opencl/kernels/unpack.hpp>
#include <stan/math/prim/mat/fun/Eigen.hpp>
#include <stan/math/prim/scal/err/check_size_match.hpp>
#include <CL/cl.hpp>
#include <iostream>
#include <vector>
#include <algorithm>
#include <type_traits>

namespace stan {
namespace math {

/**
 * Copies the source Eigen matrix to
 * the destination matrix that is stored
 * on the OpenCL device.
 *
 * @tparam T type of data in the Eigen matrix
 * @param dst destination matrix on the OpenCL device
 * @param src source Eigen matrix
 *
 * @throw std::invalid_argument if the
 * matrices do not have matching dimensions
 */
template <int R, int C>
void copy(matrix_cl& dst, const Eigen::Matrix<double, R, C>& src) {
  check_size_match("copy (Eigen -> (OpenCL))", "src.rows()", src.rows(),
                   "dst.rows()", dst.rows());
  check_size_match("copy (Eigen -> (OpenCL))", "src.cols()", src.cols(),
                   "dst.cols()", dst.cols());
  if (src.size() > 0) {
    cl::CommandQueue queue = opencl_context.queue();
    try {
      /**
       * Writes the contents of src to the OpenCL buffer
       * starting at the offset 0
       * CL_FALSE denotes that the call is non-blocking
       * This means that future kernels need to know about the copy_event
       * So that they do not execute until this transfer finishes.
       */
      cl::Event copy_event;
      queue.enqueueWriteBuffer(dst.buffer(), CL_FALSE, 0,
                               sizeof(double) * dst.size(), src.data(), NULL,
                               &copy_event);
      dst.add_event(copy_event);
    } catch (const cl::Error& e) {
      check_opencl_error("copy Eigen->(OpenCL)", e);
    }
  }
}

/**
 * Copies the source matrix that is stored
 * on the OpenCL device to the destination Eigen
 * matrix.
 *
 * @tparam T type of data in the Eigen matrix
 * @param dst destination Eigen matrix
 * @param src source matrix on the OpenCL device
 *
 * @throw std::invalid_argument if the
 * matrices do not have matching dimensions
 */
template <int R, int C>
void copy(Eigen::Matrix<double, R, C>& dst, const matrix_cl& src) {
  check_size_match("copy ((OpenCL) -> Eigen)", "src.rows()", src.rows(),
                   "dst.rows()", dst.rows());
  check_size_match("copy ((OpenCL) -> Eigen)", "src.cols()", src.cols(),
                   "dst.cols()", dst.cols());
  if (src.size() > 0) {
    cl::CommandQueue queue = opencl_context.queue();
    try {
      /**
       * Reads the contents of the OpenCL buffer
       * starting at the offset 0 to the Eigen
       * matrix
       * CL_TRUE denotes that the call is blocking
       * We do not want to pass data back to the CPU until all of the jobs
       * called on the source matrix are finished.
       */
      cl::Event copy_event;
      queue.enqueueReadBuffer(src.buffer(), CL_TRUE, 0,
                              sizeof(double) * dst.size(), dst.data(),
                              &src.events(), &copy_event);
      copy_event.wait();
    } catch (const cl::Error& e) {
      check_opencl_error("copy (OpenCL)->Eigen", e);
    }
  }
}

/**
 * Packs the flat triagnular matrix on the OpenCL device and
 * copies it to the std::vector.
 *
 * @tparam triangular_view the triangularity of the source matrix
 * @param src the flat triangular source matrix on the OpenCL device
 * @return the packed std::vector
 */
template <TriangularViewCL triangular_view>
inline std::vector<double> packed_copy(const matrix_cl& src) {
  const int packed_size = src.rows() * (src.rows() + 1) / 2;
  std::vector<double> dst(packed_size);
  if (dst.size() == 0) {
    return dst;
  }
  cl::CommandQueue queue = opencl_context.queue();
  try {
    matrix_cl packed(packed_size, 1);
    stan::math::opencl_kernels::pack(cl::NDRange(src.rows(), src.rows()),
                                     packed.buffer(), src.buffer(), src.rows(),
                                     src.rows(), triangular_view);
    queue.enqueueReadBuffer(packed.buffer(), CL_TRUE, 0,
                            sizeof(double) * packed_size, dst.data());
  } catch (const cl::Error& e) {
    check_opencl_error("packed_copy (OpenCL->std::vector)", e);
  }
  return dst;
}

/**
 * Copies the packed triangular matrix from
 * the source std::vector to an OpenCL buffer and
 * unpacks it to a flat matrix on the OpenCL device.
 *
 * @tparam triangular_view the triangularity of the source matrix
 * @param src the packed source std::vector
 * @param rows the number of rows in the flat matrix
 * @return the destination flat matrix on the OpenCL device
 * @throw std::invalid_argument if the
 * size of the vector does not match the expected size
 * for the packed triangular matrix
 */
template <TriangularViewCL triangular_view>
inline matrix_cl packed_copy(const std::vector<double>& src, int rows) {
  const int packed_size = rows * (rows + 1) / 2;
  check_size_match("copy (packed std::vector -> OpenCL)", "src.size()",
                   src.size(), "rows * (rows + 1) / 2", packed_size);
  matrix_cl dst(rows, rows);
  if (dst.size() == 0) {
    return dst;
  }
  cl::CommandQueue queue = opencl_context.queue();
  try {
    matrix_cl packed(packed_size, 1);
    queue.enqueueWriteBuffer(packed.buffer(), CL_TRUE, 0,
                             sizeof(double) * packed_size, src.data());
    stan::math::opencl_kernels::unpack(cl::NDRange(dst.rows(), dst.rows()),
                                       dst.buffer(), packed.buffer(),
                                       dst.rows(), dst.rows(), triangular_view);
  } catch (const cl::Error& e) {
    check_opencl_error("packed_copy (std::vector->OpenCL)", e);
  }
  return dst;
}

/**
 * Copies the source matrix to the
 * destination matrix. Both matrices
 * are stored on the OpenCL device.
 *
 * @param dst destination matrix
 * @param src source matrix
 *
 * @throw std::invalid_argument if the
 * matrices do not have matching dimensions
 */
inline void copy(matrix_cl& dst, const matrix_cl& src) {
  check_size_match("copy ((OpenCL) -> (OpenCL))", "src.rows()", src.rows(),
                   "dst.rows()", dst.rows());
  check_size_match("copy ((OpenCL) -> (OpenCL))", "src.cols()", src.cols(),
                   "dst.cols()", dst.cols());
  if (src.size() == 0) {
    return;
  }
  try {
    /**
     * Copies the contents of the src buffer to the dst buffer
     * see the matrix_cl(matrix_cl&) constructor
     *  for explanation
     */
    cl::Event copy_event;
    queue.enqueueCopyBuffer(src.buffer(), dst.buffer(), 0, 0,
                             sizeof(double) * src.size(), NULL, &copy_event);
    dst.add_event(copy_event);
  } catch (const cl::Error& e) {
    check_opencl_error("copy (OpenCL)->(OpenCL)", e);
  }
}

/**
 * Copy A 1 by 1 source matrix from the Device to  the host.
 * @tparam An arithmetic type to pass the value from the OpenCL matrix to.
 * @param dst Arithmetic to receive the matrix_cl value.
 * @param src A 1x1 matrix on the device.
 */
template <typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
inline void copy(T& dst, const matrix_cl& src) {
  check_size_match("copy ((OpenCL) -> (OpenCL))", "src.rows()", src.rows(),
                   "dst.rows()", 1);
  check_size_match("copy ((OpenCL) -> (OpenCL))", "src.cols()", src.cols(),
                   "dst.cols()", 1);
  try {
    cl::CommandQueue queue = opencl_context.queue();
    cl::Event copy_event;
    queue.enqueueReadBuffer(src.buffer(), CL_TRUE, 0, sizeof(int), &dst,
                            &src.events(), &copy_event);
  } catch (const cl::Error& e) {
    check_opencl_error("copy (OpenCL)->(OpenCL)", e);
  }
}

/**
 * Copy an arithmetic type to the device.
 * @tparam An arithmetic type to pass the value from the OpenCL matrix to.
 * @param src Arithmetic to receive the matrix_cl value.
 * @param dst A 1x1 matrix on the device.
 */
template <typename T, std::enable_if_t<std::is_arithmetic<T>::value, int> = 0>
inline void copy(matrix_cl& dst, const T& src) {
  check_size_match("copy ((OpenCL) -> (OpenCL))", "src.rows()", dst.rows(),
                   "dst.rows()", 1);
  check_size_match("copy ((OpenCL) -> (OpenCL))", "src.cols()", dst.cols(),
                   "dst.cols()", 1);
  try {
    cl::CommandQueue queue = opencl_context.queue();
    cl::Event copy_event;
    queue.enqueueWriteBuffer(dst.buffer(), CL_FALSE, 0, sizeof(T), &src,
                             &dst.events(), &copy_event);
    dst.add_event(copy_event);
  } catch (const cl::Error& e) {
    check_opencl_error("copy (OpenCL)->(OpenCL)", e);
  }
}

}  // namespace math
}  // namespace stan
#endif
#endif
<|endoftext|>


<commit_before>#ifndef STAN_MATH_REV_FUN_SUM_HPP
#define STAN_MATH_REV_FUN_SUM_HPP

#include <stan/math/rev/core.hpp>
#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/fun/sum.hpp>
#include <stan/math/rev/fun/typedefs.hpp>
#include <stan/math/prim/fun/Eigen.hpp>
#include <vector>

namespace stan {
namespace math {

/**
 * Class for sums of variables constructed with standard vectors.
 * There's an extension for Eigen matrices.
 */
class sum_v_vari : public vari {
 protected:
  vari** v_;
  size_t length_;

  inline static double sum_of_val(const std::vector<var>& v) {
    double result = 0;
    for (auto x : v) {
      result += x.val();
    }
    return result;
  }

 public:
  explicit sum_v_vari(double value, vari** v, size_t length)
      : vari(value), v_(v), length_(length) {}

  explicit sum_v_vari(const std::vector<var>& v1)
      : vari(sum_of_val(v1)),
      v_(reinterpret_cast<vari**>(ChainableStack::instance_->memalloc_.alloc(
          v1.size() * sizeof(vari*)))),
        length_(v1.size()) {
    for (size_t i = 0; i < length_; i++) {
      v_[i] = v1[i].vi_;
    }
  }

  virtual void chain() {
    for (size_t i = 0; i < length_; i++) {
      v_[i]->adj_ += adj_;
    }
  }
};

/**
 * Returns the sum of the entries of the specified vector.
 *
 * @param m Vector.
 * @return Sum of vector entries.
 */
inline var sum(const std::vector<var>& m) {
  if (m.empty()) {
    return 0.0;
  }
  return var(new sum_v_vari(m));
}

/**
 * Returns the sum of the coefficients of the specified
 * matrix.
 *
 * @tparam T type of the matrix of vector. Can be either a var matrix or
 *  matrix of vars.
 * @param x Specified var_value containing a matrix or vector.
 * @return Sum of coefficients of matrix.
 */
 template <typename T, require_var_matrix_t<T>* = nullptr>
 inline var sum(const T& x) {
   var res(sum(value_of(x)));
   arena_t<T> x_arena = x;
   reverse_pass_callback([res, x_arena]() mutable {
     x_arena.adj().array() += res.adj();
   });
   return res;
 }

}  // namespace math
}  // namespace stan
#endif
<commit_msg>fix headers<commit_after>#ifndef STAN_MATH_REV_FUN_SUM_HPP
#define STAN_MATH_REV_FUN_SUM_HPP

#include <stan/math/prim/fun/Eigen.hpp>
#include <stan/math/rev/core.hpp>
#include <stan/math/rev/meta.hpp>
#include <stan/math/rev/functor/arena_matrix.hpp>
#include <stan/math/rev/functor/reverse_pass_callback.hpp>
#include <stan/math/rev/fun/sum.hpp>
#include <stan/math/rev/fun/value_of.hpp>
#include <stan/math/rev/fun/typedefs.hpp>
#include <vector>

namespace stan {
namespace math {

/**
 * Class for sums of variables constructed with standard vectors.
 * There's an extension for Eigen matrices.
 */
class sum_v_vari : public vari {
 protected:
  vari** v_;
  size_t length_;

  inline static double sum_of_val(const std::vector<var>& v) {
    double result = 0;
    for (auto x : v) {
      result += x.val();
    }
    return result;
  }

 public:
  explicit sum_v_vari(double value, vari** v, size_t length)
      : vari(value), v_(v), length_(length) {}

  explicit sum_v_vari(const std::vector<var>& v1)
      : vari(sum_of_val(v1)),
      v_(reinterpret_cast<vari**>(ChainableStack::instance_->memalloc_.alloc(
          v1.size() * sizeof(vari*)))),
        length_(v1.size()) {
    for (size_t i = 0; i < length_; i++) {
      v_[i] = v1[i].vi_;
    }
  }

  virtual void chain() {
    for (size_t i = 0; i < length_; i++) {
      v_[i]->adj_ += adj_;
    }
  }
};

/**
 * Returns the sum of the entries of the specified vector.
 *
 * @param m Vector.
 * @return Sum of vector entries.
 */
inline var sum(const std::vector<var>& m) {
  if (m.empty()) {
    return 0.0;
  }
  return var(new sum_v_vari(m));
}

/**
 * Returns the sum of the coefficients of the specified
 * matrix.
 *
 * @tparam T type of the matrix of vector. Can be either a var matrix or
 *  matrix of vars.
 * @param x Specified var_value containing a matrix or vector.
 * @return Sum of coefficients of matrix.
 */
 template <typename T, require_var_matrix_t<T>* = nullptr>
 inline var sum(const T& x) {
   var res(sum(value_of(x)));
   arena_t<T> x_arena = x;
   reverse_pass_callback([res, x_arena]() mutable {
     x_arena.adj().array() += res.adj();
   });
   return res;
 }

}  // namespace math
}  // namespace stan
#endif
<|endoftext|>


<commit_before>/*
 * MRustC - Rust Compiler
 * - By John Hodge (Mutabah/thePowersGang)
 *
 * include/string_view.hpp
 * - Clone of the `string_view` class (introduced in C++17)
 */
#pragma once
#include <string>
#include <cstddef>  // size_t
#include <iostream> // ostream

namespace stdx {
using namespace std;

class string_view
{
    const char* m_start;
    const char* m_end;

public:
    string_view():
        m_start(nullptr), m_end(nullptr)
    {
    }
    string_view(const char* s, const char* e):
        m_start(s), m_end(e)
    {
        if(!(s <= e))
            throw ::std::invalid_argument("start must be before end for string_view");
    }
    string_view(const char* s):
        m_start(s), m_end(s)
    {
        while(*m_end)
            m_end ++;
    }
    string_view(const string& s):
        m_start(s.data()), m_end(m_start + s.size())
    {
    }

    size_t size() const {
        return m_end - m_start;
    }

    bool operator==(const string_view& x) const { return cmp(x) == 0; }
    bool operator!=(const string_view& x) const { return cmp(x) != 0; }
    bool operator< (const string_view& x) const { return cmp(x) <  0; }
    bool operator> (const string_view& x) const { return cmp(x) >  0; }
    bool operator<=(const string_view& x) const { return cmp(x) <= 0; }
    bool operator>=(const string_view& x) const { return cmp(x) >= 0; }
    bool operator==(const char* x) const { return cmp(string_view(x)) == 0; }
    bool operator!=(const char* x) const { return cmp(string_view(x)) != 0; }
    bool operator< (const char* x) const { return cmp(string_view(x)) <  0; }
    bool operator> (const char* x) const { return cmp(string_view(x)) >  0; }
    bool operator<=(const char* x) const { return cmp(string_view(x)) <= 0; }
    bool operator>=(const char* x) const { return cmp(string_view(x)) >= 0; }
    bool operator==(const string& x) const { return cmp(string_view(x)) == 0; }
    bool operator!=(const string& x) const { return cmp(string_view(x)) != 0; }
    bool operator< (const string& x) const { return cmp(string_view(x)) <  0; }
    bool operator> (const string& x) const { return cmp(string_view(x)) >  0; }
    bool operator<=(const string& x) const { return cmp(string_view(x)) <= 0; }
    bool operator>=(const string& x) const { return cmp(string_view(x)) >= 0; }

    friend ::std::ostream& operator<<(::std::ostream& os, const string_view& x) {
        for(const char* s = x.m_start; s != x.m_end; s++)
            os << *s;
        return os;
    }

private:
    int cmp(const string_view& x) const {
        const char *a, *b;
        for( a = m_start, b = x.m_start; a != m_end && b != x.m_end; a++, b++)
        {
            if( *a != *b ) {
                return *a < *b ? -1 : 1;
            }
        }
        if( a == m_end && b == m_end )
            return 0;
        if( a == m_end )
            return -1;
        else
            return 1;
    }
};

}
<commit_msg>string_view - Fix buggy comparison<commit_after>/*
 * MRustC - Rust Compiler
 * - By John Hodge (Mutabah/thePowersGang)
 *
 * include/string_view.hpp
 * - Clone of the `string_view` class (introduced in C++17)
 */
#pragma once
#include <string>
#include <cstddef>  // size_t
#include <iostream> // ostream

namespace stdx {
using namespace std;

class string_view
{
    const char* m_start;
    const char* m_end;

public:
    string_view():
        m_start(nullptr), m_end(nullptr)
    {
    }
    string_view(const char* s, const char* e):
        m_start(s), m_end(e)
    {
        if(!(s <= e))
            throw ::std::invalid_argument("start must be before end for string_view");
    }
    string_view(const char* s):
        m_start(s), m_end(s)
    {
        while(*m_end)
            m_end ++;
    }
    string_view(const string& s):
        m_start(s.data()), m_end(m_start + s.size())
    {
    }

    size_t size() const {
        return m_end - m_start;
    }

    bool operator==(const string_view& x) const { return cmp(x) == 0; }
    bool operator!=(const string_view& x) const { return cmp(x) != 0; }
    bool operator< (const string_view& x) const { return cmp(x) <  0; }
    bool operator> (const string_view& x) const { return cmp(x) >  0; }
    bool operator<=(const string_view& x) const { return cmp(x) <= 0; }
    bool operator>=(const string_view& x) const { return cmp(x) >= 0; }
    bool operator==(const char* x) const { return cmp(string_view(x)) == 0; }
    bool operator!=(const char* x) const { return cmp(string_view(x)) != 0; }
    bool operator< (const char* x) const { return cmp(string_view(x)) <  0; }
    bool operator> (const char* x) const { return cmp(string_view(x)) >  0; }
    bool operator<=(const char* x) const { return cmp(string_view(x)) <= 0; }
    bool operator>=(const char* x) const { return cmp(string_view(x)) >= 0; }
    bool operator==(const string& x) const { return cmp(string_view(x)) == 0; }
    bool operator!=(const string& x) const { return cmp(string_view(x)) != 0; }
    bool operator< (const string& x) const { return cmp(string_view(x)) <  0; }
    bool operator> (const string& x) const { return cmp(string_view(x)) >  0; }
    bool operator<=(const string& x) const { return cmp(string_view(x)) <= 0; }
    bool operator>=(const string& x) const { return cmp(string_view(x)) >= 0; }

    friend ::std::ostream& operator<<(::std::ostream& os, const string_view& x) {
        for(const char* s = x.m_start; s != x.m_end; s++)
            os << *s;
        return os;
    }

private:
    int cmp(const string_view& x) const {
        const char *a, *b;
        for( a = m_start, b = x.m_start; a != m_end && b != x.m_end; a++, b++)
        {
            if( *a != *b ) {
                return *a < *b ? -1 : 1;
            }
        }
        if( a == m_end && b == x.m_end )
            return 0;
        if( a == m_end )
            return -1;
        else
            return 1;
    }
};

}
<|endoftext|>


<commit_before>#pragma once

#include "unicorn/core.hpp"
#include "unicorn/character.hpp"
#include "unicorn/regex.hpp"
#include "unicorn/string.hpp"
#include <algorithm>
#include <iostream>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <vector>

namespace Unicorn {

    namespace UnicornDetail {

        template <typename T, bool FP = std::is_floating_point<T>::value>
        struct ArgConv {
            T operator()(const u8string& s) const {
                return s.empty() ? T() : static_cast<T>(s);
            }
        };

        template <typename T>
        struct ArgConv<T, true> {
            T operator()(const u8string& s) const {
                return s.empty() ? T(0) : from_si<T>(s);
            }
        };

        template <typename T>
        struct ArgConv<T, false> {
            T operator()(const u8string& s) const {
                if (s.empty())
                    return T(0);
                else if (s.size() >= 3 && s[0] == '0' && (s[1] == 'X' || s[1] == 'x'))
                    return hex_to_int<T>(utf_iterator(s, 2));
                else
                    return from_si<T>(s);
            }
        };

        template <typename C>
        struct ArgConv<basic_string<C>, false> {
            basic_string<C> operator()(const u8string& s) const {
                return recode<C>(s);
            }
        };

    }

    class Options {
    public:
        static constexpr uint32_t locale = 1;    // Argument list is in local encoding
        static constexpr uint32_t noprefix = 2;  // First argument is not the command name
        static constexpr uint32_t quoted = 4;    // Allow arguments to be quoted
        static constexpr Kwarg<bool>
            anon = {},      // Assign anonymous arguments to this option
            boolean = {},   // Boolean option
            integer = {},   // Argument must be an integer
            uinteger = {},  // Argument must be an unsigned integer
            floating = {},  // Argument must be a floating point number
            multiple = {},  // Option may have multiple arguments
            required = {};  // Option is required
        static constexpr Kwarg<u8string>
            abbrev = {},    // Single letter abbreviation
            defval = {},    // Default value if not supplied
            group = {},     // Mutual exclusion group name
            pattern = {};   // Argument must match this regular expression
        class CommandError: public std::runtime_error {
        public:
            explicit CommandError(const u8string& details, const u8string& arg = {}, const u8string& arg2 = {});
        };
        class SpecError: public std::runtime_error {
        public:
            explicit SpecError(const u8string& option);
            SpecError(const u8string& details, const u8string& option);
        };
        explicit Options(const u8string& info, const u8string& head = {}, const u8string& tail = {}):
            app_info(str_trim(info)), help_auto(false),
            help_head(str_trim(head)), help_tail(str_trim(tail)), opts() {}
        template <typename... Args> void add(const u8string& name, const u8string& info, const Args&... args);
        void autohelp() noexcept { help_auto = true; }
        u8string help() const;
        u8string version() const { return app_info; }
        template <typename C, typename C2>
            bool parse(const vector<basic_string<C>>& args, std::basic_ostream<C2>& out, uint32_t flags = 0);
        template <typename C, typename C2>
            bool parse(const basic_string<C>& args, std::basic_ostream<C2>& out, uint32_t flags = 0);
        template <typename C, typename C2>
            bool parse(int argc, C** argv, std::basic_ostream<C2>& out, uint32_t flags = 0);
        template <typename C> bool parse(const vector<basic_string<C>>& args) { return parse(args, std::cout); }
        template <typename C> bool parse(const basic_string<C>& args) { return parse(args, std::cout); }
        template <typename C> bool parse(int argc, C** argv) { return parse(argc, argv, std::cout); }
        template <typename T> T get(const u8string& name) const
            { return UnicornDetail::ArgConv<T>()(str_join(find_values(name), " ")); }
        template <typename T> vector<T> get_list(const u8string& name) const;
        bool has(const u8string& name) const { return find_index(name, true) != npos; }
    private:
        using string_list = vector<u8string>;
        enum class help_mode { none, version, usage };
        struct option_type {
            string_list values;
            u8string abbrev;
            u8string defval;
            u8string group;
            u8string info;
            u8string name;
            Regex pattern;
            bool found = false;
            bool is_anon = false;
            bool is_boolean = false;
            bool is_integer = false;
            bool is_uinteger = false;
            bool is_float = false;
            bool is_multiple = false;
            bool is_required = false;
        };
        using option_list = vector<option_type>;
        u8string app_info;
        bool help_auto;
        u8string help_head;
        u8string help_tail;
        option_list opts;
        void add_option(option_type opt);
        size_t find_index(u8string name, bool found = false) const;
        string_list find_values(const u8string& name) const;
        help_mode parse_args(string_list args, uint32_t flags);
        void add_help_version();
        void clean_up_arguments(string_list& args, uint32_t flags);
        string_list parse_forced_anonymous(string_list& args);
        void parse_attached_arguments(string_list& args);
        void expand_abbreviations(string_list& args);
        void extract_named_options(string_list& args);
        void parse_remaining_anonymous(string_list& args, const string_list& anon);
        void check_required();
        void supply_defaults();
        template <typename C> void send_help(std::basic_ostream<C>& out, help_mode mode) const;
        template <typename C> static u8string arg_convert(const basic_string<C>& str, uint32_t /*flags*/)
            { return to_utf8(str); }
        static u8string arg_convert(const string& str, uint32_t flags);
        static void unquote(const u8string& src, string_list& dst);
    };

    template <typename... Args>
    void Options::add(const u8string& name, const u8string& info, const Args&... args) {
        option_type opt;
        u8string pat;
        opt.name = name;
        opt.info = info;
        kwget(anon, opt.is_anon, args...);
        kwget(boolean, opt.is_boolean, args...);
        kwget(integer, opt.is_integer, args...);
        kwget(uinteger, opt.is_uinteger, args...);
        kwget(floating, opt.is_float, args...);
        kwget(multiple, opt.is_multiple, args...);
        kwget(required, opt.is_required, args...);
        kwget(abbrev, opt.abbrev, args...);
        kwget(defval, opt.defval, args...);
        kwget(group, opt.group, args...);
        kwget(pattern, pat, args...);
        opt.pattern = Regex(pat);
        add_option(opt);
    }

    template <typename T>
    vector<T> Options::get_list(const u8string& name) const {
        string_list svec = find_values(name);
        vector<T> tvec;
        std::transform(svec.begin(), svec.end(), append(tvec), UnicornDetail::ArgConv<T>());
        return tvec;
    }

    template <typename C, typename C2>
    bool Options::parse(const vector<basic_string<C>>& args, std::basic_ostream<C2>& out, uint32_t flags) {
        string_list u8vec;
        std::transform(args.begin(), args.end(), append(u8vec),
            [=] (const basic_string<C>& s) { return arg_convert(s, flags); });
        auto help_wanted = parse_args(u8vec, flags);
        send_help(out, help_wanted);
        return help_wanted != help_mode::none;
    }

    template <typename C, typename C2>
    bool Options::parse(const basic_string<C>& args, std::basic_ostream<C2>& out, uint32_t flags) {
        auto u8args = arg_convert(args, flags);
        string_list vec;
        if (flags & quoted) {
            unquote(u8args, vec);
            flags &= ~ quoted;
        } else {
            str_split(u8args, append(vec));
        }
        auto help_wanted = parse_args(vec, flags);
        send_help(out, help_wanted);
        return help_wanted != help_mode::none;
    }

    template <typename C, typename C2>
    bool Options::parse(int argc, C** argv, std::basic_ostream<C2>& out, uint32_t flags) {
        vector<basic_string<C>> args(argv, argv + argc);
        if (flags & quoted)
            return parse(str_join(args, str_char<C>(U' ')), out, flags);
        else
            return parse(args, out, flags);
    }

    template <typename C>
    void Options::send_help(std::basic_ostream<C>& out, help_mode mode) const {
        u8string message;
        switch (mode) {
            case help_mode::version:  message = app_info + '\n'; break;
            case help_mode::usage:    message = help(); break;
            default:                  break;
        }
        if (! message.empty())
            out << recode<C>(message);
    }

}
<commit_msg>Make argument conversion a bit smarter<commit_after>#pragma once

#include "unicorn/core.hpp"
#include "unicorn/character.hpp"
#include "unicorn/regex.hpp"
#include "unicorn/string.hpp"
#include <algorithm>
#include <iostream>
#include <stdexcept>
#include <string>
#include <type_traits>
#include <vector>

namespace Unicorn {

    namespace UnicornDetail {

        template <typename T, bool I = std::is_integral<T>::value,
            bool F = std::is_floating_point<T>::value>
        struct ArgConv;

        template <typename T>
        struct ArgConv<T, false, false> {
            T operator()(const u8string& s) const {
                return s.empty() ? T() : static_cast<T>(s);
            }
        };

        template <typename T>
        struct ArgConv<T, true, false> {
            T operator()(const u8string& s) const {
                if (s.empty())
                    return T(0);
                else if (s.size() >= 3 && s[0] == '0' && (s[1] == 'X' || s[1] == 'x'))
                    return hex_to_int<T>(utf_iterator(s, 2));
                else
                    return from_si<T>(s);
            }
        };

        template <typename T>
        struct ArgConv<T, false, true> {
            T operator()(const u8string& s) const {
                return s.empty() ? T(0) : from_si<T>(s);
            }
        };

        template <typename C>
        struct ArgConv<basic_string<C>, false, false> {
            basic_string<C> operator()(const u8string& s) const {
                return recode<C>(s);
            }
        };

    }

    class Options {
    public:
        static constexpr uint32_t locale = 1;    // Argument list is in local encoding
        static constexpr uint32_t noprefix = 2;  // First argument is not the command name
        static constexpr uint32_t quoted = 4;    // Allow arguments to be quoted
        static constexpr Kwarg<bool>
            anon = {},      // Assign anonymous arguments to this option
            boolean = {},   // Boolean option
            integer = {},   // Argument must be an integer
            uinteger = {},  // Argument must be an unsigned integer
            floating = {},  // Argument must be a floating point number
            multiple = {},  // Option may have multiple arguments
            required = {};  // Option is required
        static constexpr Kwarg<u8string>
            abbrev = {},    // Single letter abbreviation
            defval = {},    // Default value if not supplied
            group = {},     // Mutual exclusion group name
            pattern = {};   // Argument must match this regular expression
        class CommandError: public std::runtime_error {
        public:
            explicit CommandError(const u8string& details, const u8string& arg = {}, const u8string& arg2 = {});
        };
        class SpecError: public std::runtime_error {
        public:
            explicit SpecError(const u8string& option);
            SpecError(const u8string& details, const u8string& option);
        };
        explicit Options(const u8string& info, const u8string& head = {}, const u8string& tail = {}):
            app_info(str_trim(info)), help_auto(false),
            help_head(str_trim(head)), help_tail(str_trim(tail)), opts() {}
        template <typename... Args> void add(const u8string& name, const u8string& info, const Args&... args);
        void autohelp() noexcept { help_auto = true; }
        u8string help() const;
        u8string version() const { return app_info; }
        template <typename C, typename C2>
            bool parse(const vector<basic_string<C>>& args, std::basic_ostream<C2>& out, uint32_t flags = 0);
        template <typename C, typename C2>
            bool parse(const basic_string<C>& args, std::basic_ostream<C2>& out, uint32_t flags = 0);
        template <typename C, typename C2>
            bool parse(int argc, C** argv, std::basic_ostream<C2>& out, uint32_t flags = 0);
        template <typename C> bool parse(const vector<basic_string<C>>& args) { return parse(args, std::cout); }
        template <typename C> bool parse(const basic_string<C>& args) { return parse(args, std::cout); }
        template <typename C> bool parse(int argc, C** argv) { return parse(argc, argv, std::cout); }
        template <typename T> T get(const u8string& name) const
            { return UnicornDetail::ArgConv<T>()(str_join(find_values(name), " ")); }
        template <typename T> vector<T> get_list(const u8string& name) const;
        bool has(const u8string& name) const { return find_index(name, true) != npos; }
    private:
        using string_list = vector<u8string>;
        enum class help_mode { none, version, usage };
        struct option_type {
            string_list values;
            u8string abbrev;
            u8string defval;
            u8string group;
            u8string info;
            u8string name;
            Regex pattern;
            bool found = false;
            bool is_anon = false;
            bool is_boolean = false;
            bool is_integer = false;
            bool is_uinteger = false;
            bool is_float = false;
            bool is_multiple = false;
            bool is_required = false;
        };
        using option_list = vector<option_type>;
        u8string app_info;
        bool help_auto;
        u8string help_head;
        u8string help_tail;
        option_list opts;
        void add_option(option_type opt);
        size_t find_index(u8string name, bool found = false) const;
        string_list find_values(const u8string& name) const;
        help_mode parse_args(string_list args, uint32_t flags);
        void add_help_version();
        void clean_up_arguments(string_list& args, uint32_t flags);
        string_list parse_forced_anonymous(string_list& args);
        void parse_attached_arguments(string_list& args);
        void expand_abbreviations(string_list& args);
        void extract_named_options(string_list& args);
        void parse_remaining_anonymous(string_list& args, const string_list& anon);
        void check_required();
        void supply_defaults();
        template <typename C> void send_help(std::basic_ostream<C>& out, help_mode mode) const;
        template <typename C> static u8string arg_convert(const basic_string<C>& str, uint32_t /*flags*/)
            { return to_utf8(str); }
        static u8string arg_convert(const string& str, uint32_t flags);
        static void unquote(const u8string& src, string_list& dst);
    };

    template <typename... Args>
    void Options::add(const u8string& name, const u8string& info, const Args&... args) {
        option_type opt;
        u8string pat;
        opt.name = name;
        opt.info = info;
        kwget(anon, opt.is_anon, args...);
        kwget(boolean, opt.is_boolean, args...);
        kwget(integer, opt.is_integer, args...);
        kwget(uinteger, opt.is_uinteger, args...);
        kwget(floating, opt.is_float, args...);
        kwget(multiple, opt.is_multiple, args...);
        kwget(required, opt.is_required, args...);
        kwget(abbrev, opt.abbrev, args...);
        kwget(defval, opt.defval, args...);
        kwget(group, opt.group, args...);
        kwget(pattern, pat, args...);
        opt.pattern = Regex(pat);
        add_option(opt);
    }

    template <typename T>
    vector<T> Options::get_list(const u8string& name) const {
        string_list svec = find_values(name);
        vector<T> tvec;
        std::transform(svec.begin(), svec.end(), append(tvec), UnicornDetail::ArgConv<T>());
        return tvec;
    }

    template <typename C, typename C2>
    bool Options::parse(const vector<basic_string<C>>& args, std::basic_ostream<C2>& out, uint32_t flags) {
        string_list u8vec;
        std::transform(args.begin(), args.end(), append(u8vec),
            [=] (const basic_string<C>& s) { return arg_convert(s, flags); });
        auto help_wanted = parse_args(u8vec, flags);
        send_help(out, help_wanted);
        return help_wanted != help_mode::none;
    }

    template <typename C, typename C2>
    bool Options::parse(const basic_string<C>& args, std::basic_ostream<C2>& out, uint32_t flags) {
        auto u8args = arg_convert(args, flags);
        string_list vec;
        if (flags & quoted) {
            unquote(u8args, vec);
            flags &= ~ quoted;
        } else {
            str_split(u8args, append(vec));
        }
        auto help_wanted = parse_args(vec, flags);
        send_help(out, help_wanted);
        return help_wanted != help_mode::none;
    }

    template <typename C, typename C2>
    bool Options::parse(int argc, C** argv, std::basic_ostream<C2>& out, uint32_t flags) {
        vector<basic_string<C>> args(argv, argv + argc);
        if (flags & quoted)
            return parse(str_join(args, str_char<C>(U' ')), out, flags);
        else
            return parse(args, out, flags);
    }

    template <typename C>
    void Options::send_help(std::basic_ostream<C>& out, help_mode mode) const {
        u8string message;
        switch (mode) {
            case help_mode::version:  message = app_info + '\n'; break;
            case help_mode::usage:    message = help(); break;
            default:                  break;
        }
        if (! message.empty())
            out << recode<C>(message);
    }

}
<|endoftext|>


<commit_before>#include "CheckerBoard.h"
#include "StagePanel.h"
#include "SymbolExt.h"
#include "tools.h"

#include <string>

namespace sg
{

CheckerBoard::CheckerBoard(StagePanel* stage)
	: m_stage(stage)
{
	Clear();
}

void CheckerBoard::AddSprite(d2d::ISprite* sprite)
{
	int row, col;
	m_stage->TransCoordsToGridPos(sprite->getPosition(), row, col);

	SymbolExt* info = static_cast<SymbolExt*>(sprite->getSymbol().getUserData());
	if (!info) {
		return;
	}

	int center = (info->size >> 1);
	for (int i = 0; i < info->size; ++i) {
		for (int j = 0; j < info->size; ++j) {
			m_grid[row + i - center][col + j - center] = sprite;
		}
	}

	m_mapSprite2Pos.insert(std::make_pair(sprite, sprite->getPosition()));
}

void CheckerBoard::RemoveSprite(d2d::ISprite* sprite)
{
	std::map<d2d::ISprite*, d2d::Vector>::iterator itr
		= m_mapSprite2Pos.find(sprite);
	assert(itr != m_mapSprite2Pos.end());

	int row, col;
	m_stage->TransCoordsToGridPos(itr->second, row, col);

	SymbolExt* info = static_cast<SymbolExt*>(sprite->getSymbol().getUserData());
	if (!info) {
		return;
	}

	int center = (info->size >> 1);
	for (int i = 0; i < info->size; ++i) {
		for (int j = 0; j < info->size; ++j) {
			m_grid[row + i - center][col + j - center] = NULL;
		}
	}

	m_mapRemoved.insert(std::make_pair(itr->first, itr->second));
	m_mapSprite2Pos.erase(itr);
}

void CheckerBoard::Clear()
{
	memset(&m_grid[0][0], 0, sizeof(m_grid));
}

bool CheckerBoard::IsValid(d2d::ISprite* sprite) const
{
	int row, col;
	m_stage->TransCoordsToGridPos(sprite->getPosition(), row, col);

	SymbolExt* info = static_cast<SymbolExt*>(sprite->getSymbol().getUserData());
	if (!info) {
		return false;
	}

	int center = (info->size >> 1);
	for (int i = 0; i < info->size; ++i) {
		for (int j = 0; j < info->size; ++j) {
			int y = row + i - center;
			int x = col + j - center;
			if (m_grid[y][x] && m_grid[y][x] != sprite) {
				return false;
			}
		}
	}

	return true;
}

bool CheckerBoard::IsValid(const d2d::ISymbol& symbol, const d2d::Vector& pos) const
{
	int row, col;
	m_stage->TransCoordsToGridPos(pos, row, col);

	SymbolExt* info = static_cast<SymbolExt*>(symbol.getUserData());
	if (!info) {
		return false;
	}

	int center = (info->size >> 1);
	for (int i = 0; i < info->size; ++i) {
		for (int j = 0; j < info->size; ++j) {
			if (m_grid[row + i - center][col + j - center]) {
				return false;
			}
		}
	}

	return true;
}

void CheckerBoard::DebugDraw() const
{
	for (int i = 0; i < ROW; ++i) {
		for (int j = 0; j < COL; ++j) {
			if (m_grid[i][j]) {
				d2d::Vector pos;
				m_stage->TransGridPosToCoords(i, j, pos);
				d2d::PrimitiveDraw::drawCircle(pos, 10, true, 2, d2d::Colorf(0, 0, 0));
			}
		}
	}
}

bool CheckerBoard::SetCachedPos(d2d::ISprite* sprite) const
{
	std::map<d2d::ISprite*, d2d::Vector>::const_iterator itr
		= m_mapRemoved.find(sprite);
	if (itr != m_mapRemoved.end()) {
		sprite->setTransform(itr->second, sprite->getAngle());
		return true;
	} else {
		return false;
	}
}

void CheckerBoard::ResetWall()
{
	for (int i = 0; i < ROW - 1; ++i) {
		for (int j = 0; j < COL - 1; ++j) {
			bool curr = m_grid[i][j] && IsSymbolWall(*m_grid[i][j]);
			bool right = m_grid[i][j+1] && IsSymbolWall(*m_grid[i][j+1]);
			bool up = m_grid[i+1][j] && IsSymbolWall(*m_grid[i+1][j]);

			if (!curr) {
				continue;
			}

			d2d::ISprite* sprite = m_grid[i][j];
			const d2d::ISymbol& symbol = sprite->getSymbol();
			wxString filepath = symbol.getFilepath();
			int s = filepath.find("lv") + 2;
			int e = filepath.find('_', s-1);
			if (e != -1) {
				filepath = filepath.substr(0, e) + ".png";
			}
			int dot = filepath.find_last_of(".");

			int wall_type = 0;
			if (!right && !up) {
				;
			} else if (right && up) {
				wall_type = 3;
				filepath = filepath.insert(dot, "_3");
			} else if (right) {
				wall_type = 2;
				filepath = filepath.insert(dot, "_2");
			} else if (up) {
				wall_type = 1;
				filepath = filepath.insert(dot, "_1");
			}

			if (filepath == symbol.getFilepath()) {
				continue;
			}

			SymbolExt* old = static_cast<SymbolExt*>(symbol.getUserData());
			SymbolExt* info = new SymbolExt;
			*info = *old;
			info->wall_type = wall_type;

			d2d::ISymbol* new_s = d2d::SymbolMgr::Instance()->fetchSymbol(filepath);
			new_s->setUserData(info);
			m_grid[i][j]->setSymbol(new_s);
		}
	}
}

}<commit_msg>[FIXED] sg bug<commit_after>#include "CheckerBoard.h"
#include "StagePanel.h"
#include "SymbolExt.h"
#include "tools.h"

#include <string>

namespace sg
{

CheckerBoard::CheckerBoard(StagePanel* stage)
	: m_stage(stage)
{
	Clear();
}

void CheckerBoard::AddSprite(d2d::ISprite* sprite)
{
	int row, col;
	m_stage->TransCoordsToGridPos(sprite->getPosition(), row, col);

	SymbolExt* info = static_cast<SymbolExt*>(sprite->getSymbol().getUserData());
	if (!info) {
		return;
	}

	int center = (info->size >> 1);
	for (int i = 0; i < info->size; ++i) {
		for (int j = 0; j < info->size; ++j) {
			m_grid[row + i - center][col + j - center] = sprite;
		}
	}

	m_mapSprite2Pos.insert(std::make_pair(sprite, sprite->getPosition()));
}

void CheckerBoard::RemoveSprite(d2d::ISprite* sprite)
{
	if (!sprite->getSymbol().getUserData()) {
		return;
	}

	std::map<d2d::ISprite*, d2d::Vector>::iterator itr
		= m_mapSprite2Pos.find(sprite);
	assert(itr != m_mapSprite2Pos.end());

	int row, col;
	m_stage->TransCoordsToGridPos(itr->second, row, col);

	SymbolExt* info = static_cast<SymbolExt*>(sprite->getSymbol().getUserData());
	if (!info) {
		return;
	}

	int center = (info->size >> 1);
	for (int i = 0; i < info->size; ++i) {
		for (int j = 0; j < info->size; ++j) {
			m_grid[row + i - center][col + j - center] = NULL;
		}
	}

	m_mapRemoved.insert(std::make_pair(itr->first, itr->second));
	m_mapSprite2Pos.erase(itr);
}

void CheckerBoard::Clear()
{
	memset(&m_grid[0][0], 0, sizeof(m_grid));
}

bool CheckerBoard::IsValid(d2d::ISprite* sprite) const
{
	int row, col;
	m_stage->TransCoordsToGridPos(sprite->getPosition(), row, col);

	SymbolExt* info = static_cast<SymbolExt*>(sprite->getSymbol().getUserData());
	if (!info) {
		return false;
	}

	int center = (info->size >> 1);
	for (int i = 0; i < info->size; ++i) {
		for (int j = 0; j < info->size; ++j) {
			int y = row + i - center;
			int x = col + j - center;
			if (m_grid[y][x] && m_grid[y][x] != sprite) {
				return false;
			}
		}
	}

	return true;
}

bool CheckerBoard::IsValid(const d2d::ISymbol& symbol, const d2d::Vector& pos) const
{
	int row, col;
	m_stage->TransCoordsToGridPos(pos, row, col);

	SymbolExt* info = static_cast<SymbolExt*>(symbol.getUserData());
	if (!info) {
		return false;
	}

	int center = (info->size >> 1);
	for (int i = 0; i < info->size; ++i) {
		for (int j = 0; j < info->size; ++j) {
			if (m_grid[row + i - center][col + j - center]) {
				return false;
			}
		}
	}

	return true;
}

void CheckerBoard::DebugDraw() const
{
	for (int i = 0; i < ROW; ++i) {
		for (int j = 0; j < COL; ++j) {
			if (m_grid[i][j]) {
				d2d::Vector pos;
				m_stage->TransGridPosToCoords(i, j, pos);
				d2d::PrimitiveDraw::drawCircle(pos, 10, true, 2, d2d::Colorf(0, 0, 0));
			}
		}
	}
}

bool CheckerBoard::SetCachedPos(d2d::ISprite* sprite) const
{
	std::map<d2d::ISprite*, d2d::Vector>::const_iterator itr
		= m_mapRemoved.find(sprite);
	if (itr != m_mapRemoved.end()) {
		sprite->setTransform(itr->second, sprite->getAngle());
		return true;
	} else {
		return false;
	}
}

void CheckerBoard::ResetWall()
{
	for (int i = 0; i < ROW - 1; ++i) {
		for (int j = 0; j < COL - 1; ++j) {
			bool curr = m_grid[i][j] && IsSymbolWall(*m_grid[i][j]);
			bool right = m_grid[i][j+1] && IsSymbolWall(*m_grid[i][j+1]);
			bool up = m_grid[i+1][j] && IsSymbolWall(*m_grid[i+1][j]);

			if (!curr) {
				continue;
			}

			d2d::ISprite* sprite = m_grid[i][j];
			const d2d::ISymbol& symbol = sprite->getSymbol();
			wxString filepath = symbol.getFilepath();
			int s = filepath.find("lv") + 2;
			int e = filepath.find('_', s-1);
			if (e != -1) {
				filepath = filepath.substr(0, e) + ".png";
			}
			int dot = filepath.find_last_of(".");

			int wall_type = 0;
			if (!right && !up) {
				;
			} else if (right && up) {
				wall_type = 3;
				filepath = filepath.insert(dot, "_3");
			} else if (right) {
				wall_type = 2;
				filepath = filepath.insert(dot, "_2");
			} else if (up) {
				wall_type = 1;
				filepath = filepath.insert(dot, "_1");
			}

			if (filepath == symbol.getFilepath()) {
				continue;
			}

			SymbolExt* old = static_cast<SymbolExt*>(symbol.getUserData());
			SymbolExt* info = new SymbolExt;
			*info = *old;
			info->wall_type = wall_type;

			d2d::ISymbol* new_s = d2d::SymbolMgr::Instance()->fetchSymbol(filepath);
			new_s->setUserData(info);
			m_grid[i][j]->setSymbol(new_s);
		}
	}
}

}<|endoftext|>